~bigbes/lethe

96e95ab9e44d2234ab036319836a5087eb4c2a2f — Eugene Blikh 23 days ago 8aeda69
fix: add tool column to search table; remove conversation bleed from comments
M internal/server/web/dist/index.html => internal/server/web/dist/index.html +2 -2
@@ 13,8 13,8 @@
      href="https://fonts.googleapis.com/css2?family=Inter:wght@400;500;600&family=JetBrains+Mono:wght@400;500;700&display=swap"
      rel="stylesheet"
    />
    <script type="module" crossorigin src="/assets/index-Cjf6VAVm.js"></script>
    <link rel="stylesheet" crossorigin href="/assets/index-D-7MmxJh.css">
    <script type="module" crossorigin src="/assets/index-BLnRqqxn.js"></script>
    <link rel="stylesheet" crossorigin href="/assets/index-Dc2JzkyG.css">
  </head>
  <body class="density-compact">
    <div id="root"></div>

M web/src/features/search/SearchTable.tsx => web/src/features/search/SearchTable.tsx +4 -2
@@ 1,6 1,6 @@
import React from 'react'
import { useNavigate } from '@tanstack/react-router'
import { EmptyState } from '../../primitives'
import { EmptyState, ToolDot } from '../../primitives'
import type { SearchRow } from '../../api/adapters'
import { highlightSnippet } from './highlightSnippet'



@@ 11,7 11,7 @@ interface SearchTableProps {
  onLoadMore: () => void
}

const COLS = '1fr 1fr 2fr 60px'
const COLS = '80px 1fr 1fr 2fr 60px'

export function SearchTable({ rows, hasMore, loadingMore, onLoadMore }: SearchTableProps): React.JSX.Element {
  const navigate = useNavigate()


@@ 27,6 27,7 @@ export function SearchTable({ rows, hasMore, loadingMore, onLoadMore }: SearchTa
  return (
    <div className="search-table body">
      <div className="search-thead search-cols" style={{ gridTemplateColumns: COLS }}>
        <span>tool</span>
        <span>host</span>
        <span>cwd</span>
        <span>snippet</span>


@@ 45,6 46,7 @@ export function SearchTable({ rows, hasMore, loadingMore, onLoadMore }: SearchTa
            })
          }}
        >
          <span className="mono"><ToolDot tool={r.tool} /> {r.tool}</span>
          <span className="mono truncate">{r.host}</span>
          <span className="mono muted truncate">{r.cwd}</span>
          <span className="snippet truncate">{highlightSnippet(r.snippet)}</span>

M web/src/features/search/highlightSnippet.ts => web/src/features/search/highlightSnippet.ts +1 -4
@@ 4,10 4,7 @@ const MARKER_RUNES = /\x02|\x03/g

/**
 * Splits a snippet string on \x02/\x03 marker runes and interleaves plain text
 * with `<mark>` elements for matched segments.
 *
 * Respects IV2 — no dangerouslySetInnerHTML, marker-rune split with React text
 * nodes only, safe against XSS.
 * with `<mark>` elements for matched segments — safe against XSS.
 */
export function highlightSnippet(snippet: string): (string | React.JSX.Element)[] {
  const parts = snippet.split(MARKER_RUNES)

M web/src/features/search/useSearch.ts => web/src/features/search/useSearch.ts +0 -2
@@ 36,8 36,6 @@ interface UseSearchReturn {
 * - Query key includes filters so changing any filter triggers a fresh fetch.
 * - Empty `q` short-circuits to an empty result set without issuing a request.
 * - Cursor pagination appends results (never replaces) when fetchNextPage is called.
 *
 * Respects: IV3 (cursor pagination), AS1 (cursor pagination is stable).
 */
export function useSearch(filters: SearchFilters, enabled: boolean): UseSearchReturn {
  const query = useInfiniteQuery<SearchResponseDTO, Error, SearchResult>({

M web/src/styles/search.css => web/src/styles/search.css +2 -2
@@ 37,9 37,9 @@
  background: var(--paper-2);
}

/* Column grid: HOST · CWD · SNIPPET · RANK */
/* Column grid: TOOL · HOST · CWD · SNIPPET · RANK */
.search-cols {
  grid-template-columns: 1fr 1fr 2fr 60px;
  grid-template-columns: 80px 1fr 1fr 2fr 60px;
}

/* ─── Snippet with highlights ─── */