scripts/gen-website-api.ts renders website/zh-CN/api/{cordis,harness}/* and the
api-sidebar.json fragment the VitePress config imports, so pages and navigation
can never drift from the code: signatures, @param/@returns prose, dispatch
modes, and GitHub source links are extracted, never transcribed, and the
generator hard-errors on any rendered member missing docs. verify-website-api
(doc-sync + run-gates) is the freshness gate.
Replaces the hand-written zh api pages (7 pages covering 7 of 15 services,
with phantom APIs: Context.current/Context.events, agent/post-step, tool/call,
compact/*, llm/pre-request none of which exist) with generated English
references: 5 cordis pages, 15 per-service pages, and a 35-event catalog
grouped by scope. The hand-written hub api/index.md stays and now indexes the
full surface; zh for these pages arrives with the unified translation flow.
6.1 KiB
ctx.bash
BashExecutor (abstract seam) — provided by @deepseek-ai/dsh-bash.
Abstract bash execution service. Subclass, implement the abstract methods, and load the subclass as a plugin — it registers as ctx.bash (one implementation per context; loading a second throws, which is cordis' standard duplicate-service behavior).
Semantics every implementation must honor:
- run REJECTS only for infrastructure failures (unusable workdir, missing shell, pre-aborted signal). Nonzero exits, timeout kills, and abort kills RESOLVE with a descriptive BashRunResult — reporting a failed command is the tool layer's job, not an exception.
- start returns immediately; no timeout applies to background tasks (callers stop them via kill or the spec's AbortSignal). Completion must fire the onTaskDone listeners exactly once per task, and must NOT fire after the service is disposed.
- readOutput is incremental: consecutive reads never re-deliver output. Implementations bound their buffers; reads that lost data flag
lossyand point at full-stream spill files when available. - Disposal kills every running task and awaits their exit (no orphan processes survive
fiber.dispose()).
ctx.bash.resolve(request)
abstract resolve(request: BashExecRequest): BashExecSpec
Resolve a caller's BashExecRequest into a fully-specified BashExecSpec, applying this implementation's config defaults and caps (working directory, default/max timeout). Consumers (tool layer) call this, then pass the result to run/start — keeping defaulting in the implementation that owns the config while the seam type stays explicit (no hidden ?? default inside run/start).
request— the caller's request; omitted fields get this implementation's defaults, capped fields are clamped.
Returns the fully-specified spec to hand to {@link run}/{@link start}.
ctx.bash.run(spec)
abstract run(spec: BashExecSpec): Promise<BashRunResult>
Run a command in the foreground; resolves when it finishes.
spec— a resolved spec from {@link resolve}, never a raw request.
Returns the outcome; nonzero exits, timeout kills, and abort kills resolve with a descriptive result rather than reject.
ctx.bash.start(spec)
abstract start(spec: BashExecSpec): BashTask
Start a background task and return its handle immediately.
spec— a resolved spec from {@link resolve}, never a raw request.
Returns the live task handle; completion fires {@link onTaskDone}.
ctx.bash.get(id)
abstract get(id: BashTaskId): BashTask | undefined
Look up a background task by id.
id— the task id to look up.
Returns the tracked task, or undefined for an id this executor never issued.
ctx.bash.ownerOf(id)
abstract ownerOf(id: BashTaskId): OwnerToken | undefined
The opaque OWNER token recorded for a background task at start (from the BashExecSpec's owner), or undefined for an unknown id OR a known-but-ownerless task. The executor stores and returns the token verbatim — it never interprets it; the access POLICY (who may read/kill a task) lives in the consumer (@deepseek-ai/dsh-tool-bash), which compares ownerOf(id) to the caller's token. Collapsing unknown-id and known-but-unowned into the same undefined is fine: the consumer's access gate treats undefined as "open", and a genuinely unknown id then fails loudly at the subsequent readOutput/kill ("unknown task"). Storing ownership in the executor (disposed with ITS fiber) — not in the tool plugin — is what makes ownership survive a tool-bash HMR reload.
id— the background task id to look up ownership for.
Returns the token recorded at start, verbatim; undefined for an unknown id or a known-but-ownerless task.
ctx.bash.list()
abstract list(): BashTask[]
All tracked background tasks (insertion order).
Returns every task this executor started, running or finished.
ctx.bash.readOutput(id)
abstract readOutput(id: BashTaskId): BashTaskRead
Read output produced since the previous read. Throws for unknown ids.
id— the task to read from.
Returns the incremental read; consecutive reads never re-deliver output.
ctx.bash.kill(id)
abstract kill(id: BashTaskId): boolean
Kill a running background task. Returns false when it had already finished (no-op). Throws for unknown ids.
id— the task to kill.
Returns true when this call killed it, false when it had already finished.
ctx.bash.onTaskDone(listener)
onTaskDone(listener: BashTaskListener): () => void
Register a background-task completion listener (disposed with the calling fiber). Listeners never fire after this service is disposed.
listener— called exactly once per task completion.
Returns the disposer that unregisters the listener.