diff options
| author | Adam Malczewski <[email protected]> | 2026-06-25 14:06:23 +0900 |
|---|---|---|
| committer | Adam Malczewski <[email protected]> | 2026-06-25 14:06:23 +0900 |
| commit | 1ff0eac44cd44751af979c51c746a1774c268e8a (patch) | |
| tree | bf1c4563595e5b4c23f63e1d5b0782400be7e025 /packages/tool-shell/src/shell.ts | |
| parent | 54db4583e66134010375a1fa94256f36034ffdff (diff) | |
| download | dispatch-1ff0eac44cd44751af979c51c746a1774c268e8a.tar.gz dispatch-1ff0eac44cd44751af979c51c746a1774c268e8a.zip | |
feat(ssh): wave 2 — route filesystem/shell tools behind ExecBackend
Wave 2 of transparent SSH support (4 parallel owner-agents on disjoint
tool packages). The tools now resolve an ExecBackend per-call from
ctx.computerId and call backend.spawn / backend.readFile / etc. instead of
node:fs and node:child_process directly — so they are transport-agnostic
(local now; remote over SSH later, transparent to the agent). Still LOCAL-ONLY
this wave (computerId always undefined -> LocalExecBackend, behavior-identical).
- tool-shell: factory takes resolveBackend; execute calls backend.spawn.
spawn.ts DELETED (realSpawn was a verbatim duplicate of exec-backend's
LocalExecBackend.spawn — logic moved to the sanctioned shared package).
manifest dependsOn:[exec-backend]; host.getService at activation.
- tool-read-file: readFile/stat/readdir -> backend.* (pure logic untouched;
ENOENT .code branches kept).
- tool-write-file: exists/stat/writeFile -> backend.* (pure logic untouched).
- tool-edit-file: readFile/writeFile -> backend.* + forward-compatible REMOTE
diagnostics skip (ctx.computerId set -> skip LSP, return empty — plan §6.1;
local path byte-identical to today). LSP lookup stays lazy.
- orchestrator: pre-wired @dispatch/exec-backend dep into the 4 tool
package.jsons + bun install (build/config, my lane) so isolated verify
resolved cleanly; agents added the ../exec-backend tsconfig ref.
Verified: tsc -b EXIT 0, biome clean, 1599 vitest pass (was 1592).
Refs: notes/ssh-support-plan.md (decisions §0.5/§13). No merge or push.
Diffstat (limited to 'packages/tool-shell/src/shell.ts')
| -rw-r--r-- | packages/tool-shell/src/shell.ts | 15 |
1 files changed, 5 insertions, 10 deletions
diff --git a/packages/tool-shell/src/shell.ts b/packages/tool-shell/src/shell.ts index cc76bca..dac7fab 100644 --- a/packages/tool-shell/src/shell.ts +++ b/packages/tool-shell/src/shell.ts @@ -1,4 +1,5 @@ import { resolve } from "node:path"; +import type { ExecBackendResolver } from "@dispatch/exec-backend"; import type { ToolContract, ToolExecuteContext, ToolResult } from "@dispatch/kernel"; const DEFAULT_TIMEOUT = 120_000; @@ -15,14 +16,6 @@ export interface SpawnResult { readonly aborted: boolean; } -export type SpawnShell = (params: { - readonly command: string; - readonly cwd: string; - readonly signal: AbortSignal; - readonly timeout: number; - readonly onOutput: (data: string, stream: "stdout" | "stderr") => void; -}) => Promise<SpawnResult>; - export function validateArgs(args: unknown): ValidatedArgs | { readonly error: string } { if (args === null || args === undefined || typeof args !== "object") { return { error: "Error: Arguments must be an object." }; @@ -88,7 +81,7 @@ export function buildResult(params: { export function createRunShellTool(deps: { readonly workdir: string; - readonly spawn: SpawnShell; + readonly resolveBackend: ExecBackendResolver; readonly outputCap?: number; }): ToolContract { const workdir = resolve(deps.workdir); @@ -139,10 +132,12 @@ export function createRunShellTool(deps: { output += data; }; + const backend = deps.resolveBackend(ctx.computerId); + let spawnResult: SpawnResult; try { - spawnResult = await deps.spawn({ + spawnResult = await backend.spawn({ command, cwd: effectiveCwd, signal: ctx.signal, |
