fix: address codex review round 2

Translate ctx.bash.run() REJECTIONS into the SEARCH_* taxonomy. The seam
contract has run() reject for infrastructure failures (a pre-aborted
signal, an unusable/deleted session workdir, a missing shell); the bare
await let those escape as plain Errors, so the tool registry produced
isError results without the structured SearchError { name, code } the
package documents. A pre-aborted spec.signal now maps to SEARCH_ABORTED
and any other start failure to SEARCH_FAILED, original error chained as
cause. Covered by fake-executor tests for both branches plus real-executor
integration tests pinning the exact pre-aborted-signal and deleted-cwd
paths.
This commit is contained in:
Dudu-0223
2026-07-09 21:28:42 +08:00
parent e94305d99e
commit 590f520949
3 changed files with 61 additions and 2 deletions

View File

@@ -158,7 +158,11 @@ async function completeStdout(toolName: string, result: BashRunResult, rawOutput
* success with zero results (`noMatches`), anything else throws a
* {@link SearchError} (abort/timeout → `SEARCH_ABORTED`, invalid pattern →
* `SEARCH_INVALID_PATTERN`, the rest → `SEARCH_FAILED` /
* `SEARCH_RAW_OUTPUT_OVERFLOW`).
* `SEARCH_RAW_OUTPUT_OVERFLOW`). A `run()` REJECTION — the seam's
* infrastructure failures (pre-aborted signal, unusable workdir, missing
* shell) — is translated into the same taxonomy: a pre-aborted signal becomes
* `SEARCH_ABORTED`, everything else `SEARCH_FAILED`, with the original as
* `cause`.
*
* @param ctx - the plugin context; execution uses its `bash` service.
* @param exec - the tool-execution context; supplies the session cwd and the abort signal.
@@ -180,7 +184,18 @@ export async function runRipgrep(
...cwd !== undefined ? { workdir: cwd } : {},
...exec.signal ? { signal: exec.signal } : {},
})
const result = await ctx.bash.run(spec)
let result: BashRunResult
try {
result = await ctx.bash.run(spec)
} catch (error: unknown) {
// The seam contract: run() REJECTS only for infrastructure failures — a
// pre-aborted signal, an unusable workdir, a missing shell. Translate them
// so these failures stay machine-routable under the SEARCH_* taxonomy.
if (spec.signal?.aborted === true) {
throw new SearchError(`${toolName} was aborted before completion (tool timeout or caller cancellation)`, 'SEARCH_ABORTED', { cause: error })
}
throw new SearchError(`${toolName} could not start its search command (unusable working directory or missing shell)`, 'SEARCH_FAILED', { cause: error })
}
if (result.aborted) {
throw new SearchError(`${toolName} was aborted before completion (tool timeout or caller cancellation)`, 'SEARCH_ABORTED')
}