feat(bash): add an opaque owner token to the executor seam

Background-task ownership needs a stable home that survives a consumer HMR
reload. Add an optional `owner?: string` to `BashExecRequest` and a
required-but-nullable `owner: string | undefined` to the resolved
`BashExecSpec` (mirroring how `workdir`/`timeoutMs` are required on the spec —
a forgotten owner is a visible `undefined`, never a silently-absent property
that yields an unowned, cross-session-readable task). `resolve()` carries it
through.

Expose the stored token via a new `BashExecutor.ownerOf(id): string |
undefined` seam (ONE read path — not also on the public `BashTask`). The
executor stores and returns the token verbatim and NEVER interprets it: the
access POLICY lives in the consumer (`dsh-tool-bash`). `bash-local` stores
`owner` on its `TrackedTask` and implements `ownerOf`; unknown-id and
known-but-ownerless both read as `undefined`. Because ownership lives on the
task in the executor (disposed with the `dsh-bash` fiber), it survives a
`tool-bash` HMR reload.

Updates the StubExecutor seam test and the bash/bash-local READMEs.
This commit is contained in:
Tianyi Cui
2026-06-20 08:12:49 +08:00
parent 5a5b7d19c3
commit d1b7c3bf95
7 files changed
+55 -28

No files matched your search

+7
View File
@@ -6,6 +6,7 @@ import type { BashExecRequest, BashExecSpec, BashRunResult, BashTask, BashTaskRe
/** Minimal concrete executor: records calls, lets tests drive completions. */
class StubExecutor extends BashExecutor {
tasks = new Map<string, BashTask>()
private owners = new Map<string, string | undefined>()
resolve(request: BashExecRequest): BashExecSpec {
return {
@@ -13,6 +14,7 @@ class StubExecutor extends BashExecutor {
workdir: request.workdir ?? '/stub',
timeoutMs: request.timeoutMs ?? 1000,
...request.signal ? { signal: request.signal } : {},
owner: request.owner,
}
}
@@ -38,6 +40,7 @@ class StubExecutor extends BashExecutor {
done: Promise.resolve(),
}
this.tasks.set(task.id, task)
this.owners.set(task.id, spec.owner)
return task
}
@@ -45,6 +48,10 @@ class StubExecutor extends BashExecutor {
return this.tasks.get(id)
}
ownerOf(id: string): string | undefined {
return this.owners.get(id)
}
list(): BashTask[] {
return [...this.tasks.values()]
}