@almyty/runner 1.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (59) hide show
  1. package/README.md +72 -0
  2. package/dist/binaries.d.ts +30 -0
  3. package/dist/binaries.js +99 -0
  4. package/dist/binaries.js.map +1 -0
  5. package/dist/cli.d.ts +12 -0
  6. package/dist/cli.js +128 -0
  7. package/dist/cli.js.map +1 -0
  8. package/dist/coding-agents/detect.d.ts +12 -0
  9. package/dist/coding-agents/detect.js +35 -0
  10. package/dist/coding-agents/detect.js.map +1 -0
  11. package/dist/coding-agents/index.d.ts +15 -0
  12. package/dist/coding-agents/index.js +15 -0
  13. package/dist/coding-agents/index.js.map +1 -0
  14. package/dist/coding-agents/registry.d.ts +9 -0
  15. package/dist/coding-agents/registry.js +260 -0
  16. package/dist/coding-agents/registry.js.map +1 -0
  17. package/dist/coding-agents/spawn-spec.d.ts +47 -0
  18. package/dist/coding-agents/spawn-spec.js +58 -0
  19. package/dist/coding-agents/spawn-spec.js.map +1 -0
  20. package/dist/coding-agents/status.d.ts +38 -0
  21. package/dist/coding-agents/status.js +111 -0
  22. package/dist/coding-agents/status.js.map +1 -0
  23. package/dist/coding-agents/types.d.ts +104 -0
  24. package/dist/coding-agents/types.js +18 -0
  25. package/dist/coding-agents/types.js.map +1 -0
  26. package/dist/coding-sessions.d.ts +80 -0
  27. package/dist/coding-sessions.js +121 -0
  28. package/dist/coding-sessions.js.map +1 -0
  29. package/dist/config.d.ts +49 -0
  30. package/dist/config.js +180 -0
  31. package/dist/config.js.map +1 -0
  32. package/dist/daemon.d.ts +71 -0
  33. package/dist/daemon.js +353 -0
  34. package/dist/daemon.js.map +1 -0
  35. package/dist/handlers.d.ts +39 -0
  36. package/dist/handlers.js +299 -0
  37. package/dist/handlers.js.map +1 -0
  38. package/dist/index.d.ts +17 -0
  39. package/dist/index.js +18 -0
  40. package/dist/index.js.map +1 -0
  41. package/dist/policy.d.ts +16 -0
  42. package/dist/policy.js +134 -0
  43. package/dist/policy.js.map +1 -0
  44. package/dist/process-manager.d.ts +107 -0
  45. package/dist/process-manager.js +334 -0
  46. package/dist/process-manager.js.map +1 -0
  47. package/dist/protocol.d.ts +53 -0
  48. package/dist/protocol.js +39 -0
  49. package/dist/protocol.js.map +1 -0
  50. package/dist/runtime-info.d.ts +23 -0
  51. package/dist/runtime-info.js +35 -0
  52. package/dist/runtime-info.js.map +1 -0
  53. package/dist/streamable-client.d.ts +69 -0
  54. package/dist/streamable-client.js +204 -0
  55. package/dist/streamable-client.js.map +1 -0
  56. package/dist/types.d.ts +112 -0
  57. package/dist/types.js +21 -0
  58. package/dist/types.js.map +1 -0
  59. package/package.json +54 -0
@@ -0,0 +1,299 @@
1
+ import { shellExec } from './process-manager.js';
2
+ import { enforceSpawnPolicy, enforceShellPolicy } from './policy.js';
3
+ import { detectRuntimeInfo, RUNNER_VERSION } from './runtime-info.js';
4
+ import { WORKER_ERROR_CODES } from './protocol.js';
5
+ import { buildAgentSpawn, classifyStatus, detectCodingAgents, findByBinary, getCodingAgent, listCodingAgents, stripVtEscapes, } from './coding-agents/index.js';
6
+ import { realExec } from './binaries.js';
7
+ import { RUNNER_ERROR_CODES, RunnerError, } from './types.js';
8
+ export async function dispatchHandler(ctx, req) {
9
+ try {
10
+ switch (req.method) {
11
+ case 'process.spawn': return ok(await spawn(ctx, req));
12
+ case 'process.write': return ok(await write(ctx, req));
13
+ case 'process.read': return ok(await read(ctx, req));
14
+ case 'process.wait_for_idle': return ok(await waitForIdle(ctx, req));
15
+ case 'process.signal': return ok(await signal(ctx, req));
16
+ case 'process.close_input': return ok(await closeInput(ctx, req));
17
+ case 'process.list': return ok(await list(ctx, req));
18
+ case 'process.wait': return ok(await waitH(ctx, req));
19
+ case 'shell.exec': return ok(await shell(ctx, req));
20
+ case 'runner.info': return ok(await info(ctx));
21
+ case 'agent.list': return ok(agentList());
22
+ case 'agent.spawn': return ok(await agentSpawn(ctx, req));
23
+ case 'agent.status': return ok(agentStatus(ctx, req));
24
+ case 'coding.list': return ok(await codingList(ctx));
25
+ case 'coding.start': return ok(await codingStart(ctx, req));
26
+ case 'coding.input': return ok(codingInput(ctx, req));
27
+ case 'coding.status': return ok(codingStatus(ctx, req));
28
+ case 'coding.stop': return ok(codingStop(ctx, req));
29
+ default:
30
+ return err(WORKER_ERROR_CODES.MALFORMED_ENVELOPE, `unknown method ${req.method}`);
31
+ }
32
+ }
33
+ catch (e) {
34
+ if (e instanceof RunnerError) {
35
+ return err(WORKER_ERROR_CODES.INTERNAL, e.message, { code: e.code, data: e.data });
36
+ }
37
+ return err(WORKER_ERROR_CODES.INTERNAL, e?.message ?? String(e));
38
+ }
39
+ }
40
+ // ── handlers ────────────────────────────────────────────────────────
41
+ async function spawn(ctx, req) {
42
+ const ws = requireWorkspace(req);
43
+ const p = req.params;
44
+ if (typeof p.binary !== 'string' || p.binary.length === 0) {
45
+ throw new RunnerError('binary is required', RUNNER_ERROR_CODES.PATH_DENIED);
46
+ }
47
+ const args = Array.isArray(p.args) ? p.args.map(String) : [];
48
+ const env = isStringMap(p.env) ? p.env : undefined;
49
+ const opts = {
50
+ binary: p.binary,
51
+ args,
52
+ env,
53
+ pty: p.pty !== false,
54
+ cwd: typeof p.cwd === 'string' ? p.cwd : undefined,
55
+ };
56
+ // Enforce the runner execution policy (isolation/deny/cwd/install) and
57
+ // use the sanitized env — refuses, rather than silently running, anything
58
+ // the config forbids.
59
+ opts.env = enforceSpawnPolicy(ctx.config, opts).env;
60
+ const handle = await ctx.processes.spawn(ws, opts);
61
+ return { processId: handle.processId };
62
+ }
63
+ async function write(ctx, req) {
64
+ const ws = requireWorkspace(req);
65
+ const p = req.params;
66
+ ctx.processes.write(ws, requireString(p.processId, 'processId'), requireString(p.data, 'data'));
67
+ return {};
68
+ }
69
+ async function read(ctx, req) {
70
+ const ws = requireWorkspace(req);
71
+ const p = req.params;
72
+ return ctx.processes.read(ws, requireString(p.processId, 'processId'));
73
+ }
74
+ async function waitForIdle(ctx, req) {
75
+ const ws = requireWorkspace(req);
76
+ const p = req.params;
77
+ const idleMs = typeof p.idleMs === 'number' ? p.idleMs : 250;
78
+ const maxWaitMs = typeof p.maxWaitMs === 'number' ? p.maxWaitMs : 30_000;
79
+ return ctx.processes.waitForIdle(ws, requireString(p.processId, 'processId'), { idleMs, maxWaitMs });
80
+ }
81
+ async function signal(ctx, req) {
82
+ const ws = requireWorkspace(req);
83
+ const p = req.params;
84
+ const sig = p.signal ?? 'TERM';
85
+ if (sig !== 'TERM' && sig !== 'INT' && sig !== 'KILL') {
86
+ throw new RunnerError(`unsupported signal ${sig}`, RUNNER_ERROR_CODES.PATH_DENIED);
87
+ }
88
+ ctx.processes.signal(ws, requireString(p.processId, 'processId'), sig);
89
+ return {};
90
+ }
91
+ async function closeInput(ctx, req) {
92
+ const ws = requireWorkspace(req);
93
+ const p = req.params;
94
+ ctx.processes.closeInput(ws, requireString(p.processId, 'processId'));
95
+ return {};
96
+ }
97
+ async function list(ctx, req) {
98
+ const ws = req.workspaceId; // optional: list all when undefined
99
+ return { processes: ctx.processes.list(ws) };
100
+ }
101
+ async function waitH(ctx, req) {
102
+ const ws = requireWorkspace(req);
103
+ const p = req.params;
104
+ return ctx.processes.wait(ws, requireString(p.processId, 'processId'), p.timeoutMs);
105
+ }
106
+ async function shell(ctx, req) {
107
+ // shell.exec is workspace-scoped for audit but doesn't depend on
108
+ // the process manager's bookkeeping; one-shot execution returns
109
+ // stdout+stderr+exit and forgets.
110
+ requireWorkspace(req);
111
+ const p = req.params;
112
+ const cmd = requireString(p.cmd, 'cmd');
113
+ // Enforce the same execution policy as process.spawn — isolation
114
+ // fail-closed, denyPatterns, installBlocked — and run with the
115
+ // sanitized env. Without this, shell.exec was a hole straight past
116
+ // every protection spawn honours.
117
+ const { env } = enforceShellPolicy(ctx.config, cmd, p.env);
118
+ return shellExec(cmd, env, p.timeoutMs);
119
+ }
120
+ async function info(ctx) {
121
+ // We re-detect on every call; binaries can be installed/removed at
122
+ // runtime and the user expects the snapshot to be fresh. Cheap when
123
+ // probeAll runs in parallel.
124
+ const runtime = ctx.cachedRuntimeInfo
125
+ ?? await detectRuntimeInfo({ binaries: [] });
126
+ return {
127
+ name: ctx.runnerName,
128
+ labels: ctx.labels,
129
+ runtime,
130
+ runnerVersion: RUNNER_VERSION,
131
+ binaries: runtime.binaries,
132
+ capacity: { maxConcurrent: ctx.maxConcurrent, inUse: ctx.processes.inUse() },
133
+ };
134
+ }
135
+ // ── coding-agent surface ────────────────────────────────────────────
136
+ /**
137
+ * Catalog of coding-agent platforms this runner knows how to drive. Static —
138
+ * what's actually installed is in runner.info's runtime.codingAgents. The
139
+ * catalog tells an orchestrator what it COULD ask for and the levers per CLI.
140
+ */
141
+ function agentList() {
142
+ return {
143
+ platforms: listCodingAgents().map((s) => ({
144
+ id: s.id,
145
+ displayName: s.displayName,
146
+ binary: s.binary,
147
+ providerFamily: s.providerFamily,
148
+ apiKeyEnvVars: s.apiKeyEnvVars,
149
+ configDirEnvVar: s.configDirEnvVar,
150
+ supportsMcp: s.supportsMcp,
151
+ canManage: s.canManage,
152
+ resume: s.session.kind,
153
+ })),
154
+ };
155
+ }
156
+ /**
157
+ * Launch a coding-agent CLI as an unattended member. Builds the platform's
158
+ * spawn spec (headless auth + isolated config home + auto-approve + resume),
159
+ * then runs it through the SAME execution policy as process.spawn — the coding
160
+ * agent gets no privilege the generic surface wouldn't.
161
+ */
162
+ async function agentSpawn(ctx, req) {
163
+ const ws = requireWorkspace(req);
164
+ const p = req.params;
165
+ const spec = getCodingAgent(requireString(p.platform, 'platform'));
166
+ if (!spec) {
167
+ throw new RunnerError(`unknown coding-agent platform ${p.platform}`, RUNNER_ERROR_CODES.PATH_DENIED);
168
+ }
169
+ const opts = buildAgentSpawn(spec, {
170
+ apiKey: p.apiKey,
171
+ apiKeyEnvVar: p.apiKeyEnvVar,
172
+ configDir: p.configDir,
173
+ autoApprove: p.autoApprove,
174
+ model: p.model,
175
+ resumeSessionId: p.resumeSessionId,
176
+ extraArgs: Array.isArray(p.extraArgs) ? p.extraArgs.map(String) : undefined,
177
+ cwd: p.cwd,
178
+ });
179
+ // Same policy gate as process.spawn — isolation/deny/cwd/install all apply.
180
+ opts.env = enforceSpawnPolicy(ctx.config, opts).env;
181
+ const handle = await ctx.processes.spawn(ws, opts);
182
+ return { processId: handle.processId, platform: spec.id, binary: spec.binary, args: opts.args };
183
+ }
184
+ /**
185
+ * Non-destructively classify a spawned agent's pane: busy / idle /
186
+ * awaiting_input / awaiting_auth / error. Resolves the platform from the
187
+ * process's binary (or an explicit `platform` override), strips VT escapes
188
+ * from the recent tail, and runs the per-CLI status table. Does NOT drain the
189
+ * agent's own read() buffer.
190
+ */
191
+ function agentStatus(ctx, req) {
192
+ const ws = requireWorkspace(req);
193
+ const p = req.params;
194
+ const snap = ctx.processes.snapshot(ws, requireString(p.processId, 'processId'));
195
+ const spec = p.platform ? getCodingAgent(p.platform) : findByBinary(snap.binary);
196
+ if (!spec) {
197
+ throw new RunnerError(`cannot resolve coding-agent platform for binary ${snap.binary}`, RUNNER_ERROR_CODES.PATH_DENIED);
198
+ }
199
+ const screen = stripVtEscapes(snap.tail);
200
+ const agentStatusValue = snap.status !== 'running' ? 'exited' : classifyStatus(spec.status, screen);
201
+ return {
202
+ platform: spec.id,
203
+ processStatus: snap.status,
204
+ status: agentStatusValue,
205
+ idleMs: snap.idleMs,
206
+ };
207
+ }
208
+ // ── coding-session surface (chat-to-runner bridge) ─────────────────
209
+ //
210
+ // Unlike agent.* (workspace-scoped unattended members), coding.* sessions
211
+ // are daemon-global interactive sessions driven from the chat REPL. The
212
+ // CodingSessionManager namespaces each one under a synthetic workspace and
213
+ // streams output upstream as coding.output/coding.exit event envelopes.
214
+ function requireCoding(ctx) {
215
+ if (!ctx.coding) {
216
+ throw new RunnerError('coding sessions are not available on this runner', RUNNER_ERROR_CODES.PATH_DENIED);
217
+ }
218
+ return ctx.coding;
219
+ }
220
+ /** Coding CLIs actually installed on this machine (fresh probe). */
221
+ async function codingList(ctx) {
222
+ const agents = await detectCodingAgents(ctx.probeExec ?? realExec);
223
+ return { agents };
224
+ }
225
+ /**
226
+ * Start a coding session: resolve the platform spec, build the spawn spec
227
+ * (auto-approve, task as final positional arg, pipe stdio), run it through
228
+ * the SAME execution policy as process.spawn, then hand it to the session
229
+ * registry which streams output back as events.
230
+ */
231
+ async function codingStart(ctx, req) {
232
+ const coding = requireCoding(ctx);
233
+ const p = req.params;
234
+ const spec = getCodingAgent(requireString(p.agent, 'agent'));
235
+ if (!spec) {
236
+ throw new RunnerError(`unknown coding agent ${p.agent}`, RUNNER_ERROR_CODES.PATH_DENIED);
237
+ }
238
+ const input = {
239
+ task: requireString(p.task, 'task'),
240
+ cwd: typeof p.cwd === 'string' && p.cwd.length > 0 ? p.cwd : undefined,
241
+ model: typeof p.model === 'string' ? p.model : undefined,
242
+ extraArgs: Array.isArray(p.extraArgs) ? p.extraArgs.map(String) : undefined,
243
+ };
244
+ const opts = coding.buildStartOptions(spec, input);
245
+ // Same policy gate as process.spawn — isolation/deny/cwd/install all apply.
246
+ opts.env = enforceSpawnPolicy(ctx.config, opts).env;
247
+ return coding.start(spec, input, opts);
248
+ }
249
+ /** Route a line of user input to the session's stdin. */
250
+ function codingInput(ctx, req) {
251
+ const coding = requireCoding(ctx);
252
+ const p = req.params;
253
+ coding.input(requireString(p.sessionId, 'sessionId'), requireString(p.data, 'data'));
254
+ return {};
255
+ }
256
+ /** One session's status, or the full session list when sessionId is omitted. */
257
+ function codingStatus(ctx, req) {
258
+ const coding = requireCoding(ctx);
259
+ const p = req.params;
260
+ if (typeof p.sessionId === 'string' && p.sessionId.length > 0) {
261
+ return coding.status(p.sessionId);
262
+ }
263
+ return { sessions: coding.list() };
264
+ }
265
+ /** Stop a session (TERM; KILL with force). */
266
+ function codingStop(ctx, req) {
267
+ const coding = requireCoding(ctx);
268
+ const p = req.params;
269
+ return coding.stop(requireString(p.sessionId, 'sessionId'), p.force === true);
270
+ }
271
+ // ── helpers ─────────────────────────────────────────────────────────
272
+ function requireWorkspace(req) {
273
+ if (!req.workspaceId) {
274
+ throw new RunnerError('workspaceId is required', RUNNER_ERROR_CODES.PATH_DENIED);
275
+ }
276
+ return req.workspaceId;
277
+ }
278
+ function requireString(v, name) {
279
+ if (typeof v !== 'string' || v.length === 0) {
280
+ throw new RunnerError(`${name} is required`, RUNNER_ERROR_CODES.PATH_DENIED);
281
+ }
282
+ return v;
283
+ }
284
+ function isStringMap(v) {
285
+ if (!v || typeof v !== 'object')
286
+ return false;
287
+ for (const val of Object.values(v)) {
288
+ if (typeof val !== 'string')
289
+ return false;
290
+ }
291
+ return true;
292
+ }
293
+ function ok(result) {
294
+ return { ok: true, result };
295
+ }
296
+ function err(code, message, data) {
297
+ return { ok: false, error: { code, message, data } };
298
+ }
299
+ //# sourceMappingURL=handlers.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"handlers.js","sourceRoot":"","sources":["../src/handlers.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,17 @@
1
+ /**
2
+ * Programmatic exports for the runner package.
3
+ *
4
+ * Most consumers run the CLI (`almyty-runner start`); programmatic
5
+ * access exists so backend tests and the integration spec can drive
6
+ * the runner without spawning a subprocess.
7
+ */
8
+ export { RunnerDaemon, readStatus, stopDaemon, type DaemonStatus } from './daemon.js';
9
+ export { ProcessManager, shellExec, createDefaultAdapterFactory, type ProcessAdapter, type AdapterFactory, } from './process-manager.js';
10
+ export { CodingSessionManager, type CodingEmitter, type CodingEventPayload, type CodingSessionRecord, type CodingStartInput, } from './coding-sessions.js';
11
+ export { loadConfig, DEFAULTS, DEFAULT_BINARY_PROBE_LIST, GLOBAL_CONFIG_PATH, PROJECT_CONFIG_PATH } from './config.js';
12
+ export { detectRuntimeInfo, RUNNER_VERSION } from './runtime-info.js';
13
+ export { probe, probeAll, realExec, type ProbeExec } from './binaries.js';
14
+ export { dispatchHandler, type HandlerContext } from './handlers.js';
15
+ export { StreamableClient, envelope, type StreamableClientOptions, } from './streamable-client.js';
16
+ export { WORKER_PROTOCOL_VERSION, WORKER_ERROR_CODES, isWorkerEnvelope, type WorkerEnvelope, type RequestPayload, type ResponsePayload, type HeartbeatPayload, } from './protocol.js';
17
+ export { RunnerError, RUNNER_ERROR_CODES, type ResolvedConfig, type RunnerConfig, type RunnerInfo, type RunnerRuntimeInfo, type ProcessHandle, type ProcessSignal, type SpawnOptions, type ReadResult, type WaitForIdleOptions, type WaitForIdleResult, type WaitResult, type ShellExecResult, } from './types.js';
package/dist/index.js ADDED
@@ -0,0 +1,18 @@
1
+ /**
2
+ * Programmatic exports for the runner package.
3
+ *
4
+ * Most consumers run the CLI (`almyty-runner start`); programmatic
5
+ * access exists so backend tests and the integration spec can drive
6
+ * the runner without spawning a subprocess.
7
+ */
8
+ export { RunnerDaemon, readStatus, stopDaemon } from './daemon.js';
9
+ export { ProcessManager, shellExec, createDefaultAdapterFactory, } from './process-manager.js';
10
+ export { CodingSessionManager, } from './coding-sessions.js';
11
+ export { loadConfig, DEFAULTS, DEFAULT_BINARY_PROBE_LIST, GLOBAL_CONFIG_PATH, PROJECT_CONFIG_PATH } from './config.js';
12
+ export { detectRuntimeInfo, RUNNER_VERSION } from './runtime-info.js';
13
+ export { probe, probeAll, realExec } from './binaries.js';
14
+ export { dispatchHandler } from './handlers.js';
15
+ export { StreamableClient, envelope, } from './streamable-client.js';
16
+ export { WORKER_PROTOCOL_VERSION, WORKER_ERROR_CODES, isWorkerEnvelope, } from './protocol.js';
17
+ export { RunnerError, RUNNER_ERROR_CODES, } from './types.js';
18
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AACH,OAAO,EAAE,YAAY,EAAE,UAAU,EAAE,UAAU,EAAqB,MAAM,aAAa,CAAC;AACtF,OAAO,EACL,cAAc,EACd,SAAS,EACT,2BAA2B,GAG5B,MAAM,sBAAsB,CAAC;AAC9B,OAAO,EACL,oBAAoB,GAKrB,MAAM,sBAAsB,CAAC;AAC9B,OAAO,EAAE,UAAU,EAAE,QAAQ,EAAE,yBAAyB,EAAE,kBAAkB,EAAE,mBAAmB,EAAE,MAAM,aAAa,CAAC;AACvH,OAAO,EAAE,iBAAiB,EAAE,cAAc,EAAE,MAAM,mBAAmB,CAAC;AACtE,OAAO,EAAE,KAAK,EAAE,QAAQ,EAAE,QAAQ,EAAkB,MAAM,eAAe,CAAC;AAC1E,OAAO,EAAE,eAAe,EAAuB,MAAM,eAAe,CAAC;AACrE,OAAO,EACL,gBAAgB,EAChB,QAAQ,GAET,MAAM,wBAAwB,CAAC;AAChC,OAAO,EACL,uBAAuB,EACvB,kBAAkB,EAClB,gBAAgB,GAKjB,MAAM,eAAe,CAAC;AACvB,OAAO,EACL,WAAW,EACX,kBAAkB,GAanB,MAAM,YAAY,CAAC"}
@@ -0,0 +1,16 @@
1
+ import { RunnerConfig } from './types.js';
2
+ /** Drop env keys a payload must not be allowed to set. */
3
+ export declare function sanitizeEnv(env?: Record<string, string>): Record<string, string> | undefined;
4
+ /** Enforce policy for a process.spawn; returns the sanitized env to use. */
5
+ export declare function enforceSpawnPolicy(config: RunnerConfig, opts: {
6
+ binary: string;
7
+ args: string[];
8
+ cwd?: string;
9
+ env?: Record<string, string>;
10
+ }): {
11
+ env?: Record<string, string>;
12
+ };
13
+ /** Enforce policy for a shell.exec; returns the sanitized env to use. */
14
+ export declare function enforceShellPolicy(config: RunnerConfig, cmd: string, env?: Record<string, string>): {
15
+ env?: Record<string, string>;
16
+ };
package/dist/policy.js ADDED
@@ -0,0 +1,134 @@
1
+ /**
2
+ * Runner execution policy enforcement.
3
+ *
4
+ * The runner config advertises an isolation tier, a cwd allowlist, deny
5
+ * patterns, a network-blocked flag, and an install-blocked flag. Until
6
+ * this module these were *documented but never enforced* — every
7
+ * `process.spawn` / `shell.exec` ran any backend-supplied command on the
8
+ * host, with attacker-controllable env, regardless of config. That is host
9
+ * RCE behind a config that lies about protecting the user.
10
+ *
11
+ * This enforces the contract before any spawn:
12
+ * - Fail closed when `defaultIsolation: 'container'` is configured but no
13
+ * container runtime is implemented (the default) — refuse rather than
14
+ * silently run on the host. Host execution is opt-in (`isolation: host`).
15
+ * - Fail closed when `networkBlocked` is requested (can't be honoured on
16
+ * the host).
17
+ * - Reject commands matching `denyPatterns`, and package installs when
18
+ * `installBlocked`.
19
+ * - Constrain `cwd` to `allowedCwdRoots` (realpath-canonicalized to block
20
+ * symlink/`..` escape).
21
+ * - Strip env keys a payload must never set (PATH, LD_PRELOAD, …).
22
+ */
23
+ import { realpathSync } from 'fs';
24
+ import { resolve, sep } from 'path';
25
+ import { RunnerError, RUNNER_ERROR_CODES } from './types.js';
26
+ // Env vars a payload must never override: they redirect which binary runs
27
+ // (PATH), preload code into the process (LD_PRELOAD and friends), or change
28
+ // interpreter behaviour. The daemon's own values are kept by stripping
29
+ // these from the inbound env before it's merged over process.env.
30
+ const BLOCKED_ENV_KEYS = new Set([
31
+ 'PATH',
32
+ 'LD_PRELOAD',
33
+ 'LD_LIBRARY_PATH',
34
+ 'LD_AUDIT',
35
+ 'DYLD_INSERT_LIBRARIES',
36
+ 'DYLD_LIBRARY_PATH',
37
+ 'NODE_OPTIONS',
38
+ 'PYTHONPATH',
39
+ 'PYTHONSTARTUP',
40
+ 'BASH_ENV',
41
+ 'ENV',
42
+ 'IFS',
43
+ 'GIT_SSH',
44
+ 'GIT_SSH_COMMAND',
45
+ 'GIT_EXEC_PATH',
46
+ 'PROMPT_COMMAND',
47
+ ].map((k) => k.toUpperCase()));
48
+ const INSTALL_RE = /\b(?:npm\s+(?:i|install|ci|add)|yarn\s+add|pnpm\s+(?:add|install|i)|pip3?\s+install|gem\s+install|cargo\s+install|go\s+install|apt(?:-get)?\s+install|brew\s+install|nix-env|conda\s+install)\b/i;
49
+ /** Drop env keys a payload must not be allowed to set. */
50
+ export function sanitizeEnv(env) {
51
+ if (!env)
52
+ return env;
53
+ const out = {};
54
+ for (const [k, v] of Object.entries(env)) {
55
+ if (BLOCKED_ENV_KEYS.has(k.toUpperCase()))
56
+ continue;
57
+ out[k] = v;
58
+ }
59
+ return out;
60
+ }
61
+ function assertIsolationSupported(config) {
62
+ if (config.defaultIsolation === 'container') {
63
+ throw new RunnerError('container isolation is configured but not implemented by this runner build; ' +
64
+ "refusing to run on the host. Set isolation to 'host' to explicitly allow host execution.", RUNNER_ERROR_CODES.COMMAND_DENIED);
65
+ }
66
+ if (config.networkBlocked) {
67
+ throw new RunnerError('networkBlocked is set but cannot be enforced under host isolation; refusing to run.', RUNNER_ERROR_CODES.COMMAND_DENIED);
68
+ }
69
+ }
70
+ function matchesDeny(command, patterns) {
71
+ for (const pat of patterns) {
72
+ if (!pat)
73
+ continue;
74
+ try {
75
+ if (new RegExp(pat).test(command))
76
+ return pat;
77
+ }
78
+ catch {
79
+ // Invalid regex — fall back to a literal substring match so a
80
+ // malformed pattern still denies rather than silently allowing.
81
+ if (command.includes(pat))
82
+ return pat;
83
+ }
84
+ }
85
+ return null;
86
+ }
87
+ function assertCommandAllowed(config, command) {
88
+ const deny = matchesDeny(command, config.denyPatterns ?? []);
89
+ if (deny) {
90
+ throw new RunnerError(`command blocked by denyPattern: ${deny}`, RUNNER_ERROR_CODES.COMMAND_DENIED);
91
+ }
92
+ if (config.installBlocked && INSTALL_RE.test(command)) {
93
+ throw new RunnerError('package installation is blocked by runner policy (installBlocked)', RUNNER_ERROR_CODES.COMMAND_DENIED);
94
+ }
95
+ }
96
+ function canonical(p) {
97
+ const abs = resolve(p);
98
+ try {
99
+ return realpathSync(abs); // resolve symlinks to block escape via a link
100
+ }
101
+ catch {
102
+ return abs; // path may legitimately not exist yet
103
+ }
104
+ }
105
+ function assertCwdAllowed(config, cwd) {
106
+ const roots = config.allowedCwdRoots ?? [];
107
+ if (roots.length === 0)
108
+ return; // no restriction configured
109
+ if (!cwd) {
110
+ throw new RunnerError('cwd is required when allowedCwdRoots is configured', RUNNER_ERROR_CODES.PATH_DENIED);
111
+ }
112
+ const real = canonical(cwd);
113
+ const allowed = roots.some((root) => {
114
+ const r = canonical(root);
115
+ return real === r || real.startsWith(r + sep);
116
+ });
117
+ if (!allowed) {
118
+ throw new RunnerError(`cwd is outside allowedCwdRoots: ${cwd}`, RUNNER_ERROR_CODES.PATH_DENIED);
119
+ }
120
+ }
121
+ /** Enforce policy for a process.spawn; returns the sanitized env to use. */
122
+ export function enforceSpawnPolicy(config, opts) {
123
+ assertIsolationSupported(config);
124
+ assertCwdAllowed(config, opts.cwd);
125
+ assertCommandAllowed(config, [opts.binary, ...opts.args].join(' '));
126
+ return { env: sanitizeEnv(opts.env) };
127
+ }
128
+ /** Enforce policy for a shell.exec; returns the sanitized env to use. */
129
+ export function enforceShellPolicy(config, cmd, env) {
130
+ assertIsolationSupported(config);
131
+ assertCommandAllowed(config, cmd);
132
+ return { env: sanitizeEnv(env) };
133
+ }
134
+ //# sourceMappingURL=policy.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"policy.js","sourceRoot":"","sources":["../src/policy.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,107 @@
1
+ import { EventEmitter } from 'events';
2
+ import { ProcessHandle, ProcessSignal, ProcessStatus, ReadResult, ShellExecResult, SpawnOptions, WaitForIdleOptions, WaitForIdleResult, WaitResult } from './types.js';
3
+ /**
4
+ * Adapter interface around the actual PTY/pipe implementation.
5
+ *
6
+ * The runtime uses node-pty for PTY mode (the default) and node's
7
+ * built-in child_process for raw pipe mode. Both behind one interface
8
+ * so tests can swap in a synthetic child without spinning subprocesses.
9
+ *
10
+ * node-pty isn't loaded at module-init time; it's a native dep that
11
+ * we don't want to require for unit tests. The default factory below
12
+ * lazy-loads it on first PTY spawn, so non-PTY tests never touch it.
13
+ */
14
+ export interface ProcessAdapter extends EventEmitter {
15
+ readonly pid: number | undefined;
16
+ write(data: string): void;
17
+ resize?(cols: number, rows: number): void;
18
+ kill(signal?: string): void;
19
+ /**
20
+ * Best-effort EOF on stdin. PTY mode sends ^D; pipe mode closes
21
+ * the writable side of the child's stdin stream.
22
+ */
23
+ closeInput(): void;
24
+ }
25
+ export interface AdapterFactory {
26
+ spawnPty(opts: SpawnOptions): Promise<ProcessAdapter>;
27
+ spawnPipe(opts: SpawnOptions): Promise<ProcessAdapter>;
28
+ }
29
+ interface RunningProcess {
30
+ handle: ProcessHandle;
31
+ adapter: ProcessAdapter;
32
+ /** Output buffer; bytes accumulate here between read() calls. */
33
+ buffer: string;
34
+ /**
35
+ * Rolling tail of recent output, capped and NOT drained by read(). Used for
36
+ * non-destructive status snapshots (coding-agent status classification needs
37
+ * to see the current screen even after the agent has drained `buffer`).
38
+ */
39
+ recentTail: string;
40
+ /** Last time we observed any output activity from the child. */
41
+ lastOutputAt: number;
42
+ /** Resolved when the child exits, with the final exit info. */
43
+ exitPromise: Promise<WaitResult>;
44
+ exitInfo: WaitResult | null;
45
+ }
46
+ /**
47
+ * Per-runner process orchestrator.
48
+ *
49
+ * Bookkeeping: every process is namespaced by workspaceId. Cross-
50
+ * workspace lookups error loudly (process_cross_workspace) — this is
51
+ * cheap insurance against an agent in workspace A handing a stale
52
+ * process_id to a tool that runs in workspace B.
53
+ *
54
+ * Buffering: stdout/stderr accumulate in a per-process string buffer.
55
+ * read() drains it; wait_for_idle() reads with idle-detection. We
56
+ * don't try to interpret encodings or framing; the runner's job is
57
+ * to deliver bytes faithfully, not to reason about what they mean.
58
+ */
59
+ export declare class ProcessManager {
60
+ private readonly adapter;
61
+ private readonly maxConcurrent;
62
+ private readonly processes;
63
+ constructor(adapter: AdapterFactory, maxConcurrent: number);
64
+ inUse(): number;
65
+ list(workspaceId?: string): ProcessHandle[];
66
+ spawn(workspaceId: string, opts: SpawnOptions): Promise<ProcessHandle>;
67
+ /** Look up a process; enforces workspace ownership. */
68
+ getOrThrow(workspaceId: string, processId: string): RunningProcess;
69
+ write(workspaceId: string, processId: string, data: string): void;
70
+ /**
71
+ * Drain the output buffer. Returns whatever has accumulated since
72
+ * the last call; future calls return only what's new.
73
+ */
74
+ read(workspaceId: string, processId: string): ReadResult;
75
+ /**
76
+ * Non-destructive peek at the recent output tail. Unlike read(), this does
77
+ * NOT drain anything — it's for status classification, which must work even
78
+ * after the agent has drained `buffer` via read(). Returns the rolling tail
79
+ * (capped at RECENT_TAIL_CAP) plus the process status and idle interval.
80
+ */
81
+ snapshot(workspaceId: string, processId: string): {
82
+ tail: string;
83
+ binary: string;
84
+ status: ProcessStatus;
85
+ idleMs: number;
86
+ };
87
+ /**
88
+ * Subscribe to a process's live output and exit. Push-based counterpart to
89
+ * read(): the coding-session layer streams chunks to the backend as they
90
+ * arrive instead of polling. Does NOT drain the pull buffer — a caller can
91
+ * observe and read() the same process without losing bytes in either place.
92
+ * Returns an unsubscribe function.
93
+ */
94
+ observe(workspaceId: string, processId: string, handlers: {
95
+ onData?: (chunk: string) => void;
96
+ onExit?: (info: WaitResult) => void;
97
+ }): () => void;
98
+ waitForIdle(workspaceId: string, processId: string, opts: WaitForIdleOptions): Promise<WaitForIdleResult>;
99
+ closeInput(workspaceId: string, processId: string): void;
100
+ signal(workspaceId: string, processId: string, sig: ProcessSignal): void;
101
+ wait(workspaceId: string, processId: string, timeoutMs?: number): Promise<WaitResult>;
102
+ /** Kill all processes for a workspace and forget them. Used on workspace release. */
103
+ killWorkspace(workspaceId: string): Promise<number>;
104
+ }
105
+ export declare function createDefaultAdapterFactory(): AdapterFactory;
106
+ export declare function shellExec(cmd: string, env?: Record<string, string>, timeoutMs?: number): Promise<ShellExecResult>;
107
+ export {};