fix(web-search-card): surface truncation recovery, widen cardless fallback, validate wire shape, fix tail-cap
Address the ds-review-bot findings on the search card:
- searchCardModel dropped the result view's `content`, so a capped search's
`Full … stored at: <locator>` recovery footer vanished from the UI (the card
replaces the raw text). Thread it through as `SearchCardModel.recovery` and
render it below the card at all three sites, only when truncated.
- SearchRow's fallback body was gated on `state === 'error'`, so a settled
non-error call with no card (a successful nested run_code sub-dispatch, a
legacy generic result) showed only its summary with content lost. Widen it to
any settled call with `search === null`.
- searchCardModel trusted the `files`/`paths` shape the host wire schema only
string-checks; a malformed known-kind frame would crash SearchBlock. Validate
the full shape and fall to the generic path on mismatch.
- SearchBlock's restored tail file header added a row without consuming a tail
slot, exceeding maxLines by one and overstating the hidden count. Make it
consume a slot so the visible count holds at maxLines and `hidden` stays exact.
Correct the fixture JSDoc (now genuinely exceeds the row cap) and the Agent Note
recovery-text claim, sync the ui-conversation bilingual README with the search
row, and add an assembled keyless snapshot (apps/web/tests/search-card.snapshot.ts)
that pins the grep card's shape from the built bundles.
2026-07-30 22:40:07 +08:00
|
|
|
kind=matches
|
2026-08-23 17:31:37 +08:00
|
|
|
summary=Showing 9 of 42 matches · 3 files
|
fix(web-search-card): surface truncation recovery, widen cardless fallback, validate wire shape, fix tail-cap
Address the ds-review-bot findings on the search card:
- searchCardModel dropped the result view's `content`, so a capped search's
`Full … stored at: <locator>` recovery footer vanished from the UI (the card
replaces the raw text). Thread it through as `SearchCardModel.recovery` and
render it below the card at all three sites, only when truncated.
- SearchRow's fallback body was gated on `state === 'error'`, so a settled
non-error call with no card (a successful nested run_code sub-dispatch, a
legacy generic result) showed only its summary with content lost. Widen it to
any settled call with `search === null`.
- searchCardModel trusted the `files`/`paths` shape the host wire schema only
string-checks; a malformed known-kind frame would crash SearchBlock. Validate
the full shape and fall to the generic path on mismatch.
- SearchBlock's restored tail file header added a row without consuming a tail
slot, exceeding maxLines by one and overstating the hidden count. Make it
consume a slot so the visible count holds at maxLines and `hidden` stays exact.
Correct the fixture JSDoc (now genuinely exceeds the row cap) and the Agent Note
recovery-text claim, sync the ui-conversation bilingual README with the search
row, and add an assembled keyless snapshot (apps/web/tests/search-card.snapshot.ts)
that pins the grep card's shape from the built bundles.
2026-07-30 22:40:07 +08:00
|
|
|
file=packages/client/ui-primitives/src/SearchBlock.tsx3
|
2026-08-08 15:29:26 +08:00
|
|
|
file=packages/client/ui-tool/src/client/tool/toolviews/search-row.tsx4
|
fix(web-search-card): surface truncation recovery, widen cardless fallback, validate wire shape, fix tail-cap
Address the ds-review-bot findings on the search card:
- searchCardModel dropped the result view's `content`, so a capped search's
`Full … stored at: <locator>` recovery footer vanished from the UI (the card
replaces the raw text). Thread it through as `SearchCardModel.recovery` and
render it below the card at all three sites, only when truncated.
- SearchRow's fallback body was gated on `state === 'error'`, so a settled
non-error call with no card (a successful nested run_code sub-dispatch, a
legacy generic result) showed only its summary with content lost. Widen it to
any settled call with `search === null`.
- searchCardModel trusted the `files`/`paths` shape the host wire schema only
string-checks; a malformed known-kind frame would crash SearchBlock. Validate
the full shape and fall to the generic path on mismatch.
- SearchBlock's restored tail file header added a row without consuming a tail
slot, exceeding maxLines by one and overstating the hidden count. Make it
consume a slot so the visible count holds at maxLines and `hidden` stays exact.
Correct the fixture JSDoc (now genuinely exceeds the row cap) and the Agent Note
recovery-text claim, sync the ui-conversation bilingual README with the search
row, and add an assembled keyless snapshot (apps/web/tests/search-card.snapshot.ts)
that pins the grep card's shape from the built bundles.
2026-07-30 22:40:07 +08:00
|
|
|
line=16: export const DEFAULT_SEARCH_MAX_LINES = 16
|
|
|
|
|
line=138: export function SearchBlock(props: SearchBlockProps) {
|
|
|
|
|
line=141: const [collapsed, setCollapsed] = useState<ReadonlySet<number>>(() => new Set())
|
2026-08-08 15:29:26 +08:00
|
|
|
line=36: const search = searchCardModel(block)
|
|
|
|
|
line=56: search={search}
|
|
|
|
|
line=78: yield ctx.slots.register({ name: 'tool.call.toolview', key: 'grep', locale: NS }, SearchRow)
|
2026-08-23 17:31:37 +08:00
|
|
|
expand=… 4 more lines
|
2026-07-31 16:34:16 +08:00
|
|
|
recovery=Found 9 of 42 matches
|
|
|
|
|
|
|
|
|
|
packages/client/ui-primitives/src/SearchBlock.tsx
|
|
|
|
|
Line 16: export const DEFAULT_SEARCH_MAX_LINES = 16
|
|
|
|
|
Line 138: export function SearchBlock(props: SearchBlockProps) {
|
|
|
|
|
Line 141: const [collapsed, setCollapsed] = useState<ReadonlySet<number>>(() => new Set())
|
2026-08-08 15:29:26 +08:00
|
|
|
packages/client/ui-tool/src/client/tool/models/search-card-model.ts
|
|
|
|
|
Line 45: export const CHAT_SEARCH_MAX_LINES = 8
|
|
|
|
|
Line 130: export function searchCardModel(block: ToolCallBlock): SearchCardModel | null {
|
|
|
|
|
packages/client/ui-tool/src/client/tool/toolviews/search-row.tsx
|
|
|
|
|
Line 34: export function SearchRow({ toolName, block, inspect, t }: SearchRowProps) {
|
|
|
|
|
Line 36: const search = searchCardModel(block)
|
|
|
|
|
Line 56: search={search}
|
|
|
|
|
Line 78: yield ctx.slots.register({ name: 'tool.call.toolview', key: 'grep', locale: NS }, SearchRow)
|
2026-07-31 16:34:16 +08:00
|
|
|
|
2026-07-31 17:38:17 +08:00
|
|
|
(Full grep result stored at: fixture://spill/grep-66. Read it to see every match.)
|