@cleocode/cleo-os 2026.4.99 → 2026.4.101

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.
@@ -0,0 +1,62 @@
1
+ /**
2
+ * cleo-os Harness Registry.
3
+ *
4
+ * Centralises construction and lookup of {@link HarnessAdapter} implementations
5
+ * available in cleo-os. Adding a new harness means:
6
+ *
7
+ * 1. Implement {@link HarnessAdapter} in a subdirectory under `harnesses/`.
8
+ * 2. Add an entry to {@link HARNESS_REGISTRY} below.
9
+ * 3. Export the adapter class from the subdirectory's `index.ts`.
10
+ *
11
+ * @packageDocumentation
12
+ */
13
+ import type { HarnessAdapter } from './pi-coding-agent/types.js';
14
+ /**
15
+ * Metadata entry for a registered harness adapter.
16
+ *
17
+ * @public
18
+ */
19
+ export interface HarnessRegistryEntry {
20
+ /** Short stable identifier matching {@link HarnessAdapter.id}. */
21
+ id: string;
22
+ /** Human-readable display name. */
23
+ name: string;
24
+ /** Factory function that creates a fresh adapter instance. */
25
+ create: () => HarnessAdapter;
26
+ }
27
+ /**
28
+ * Look up a harness adapter by ID.
29
+ *
30
+ * @param id - Harness adapter ID (e.g. `"pi-coding-agent"`).
31
+ * @returns The registry entry, or `undefined` when not found.
32
+ *
33
+ * @example
34
+ * ```typescript
35
+ * const entry = getHarnessEntry('pi-coding-agent');
36
+ * const adapter = entry?.create();
37
+ * ```
38
+ *
39
+ * @public
40
+ */
41
+ export declare function getHarnessEntry(id: string): HarnessRegistryEntry | undefined;
42
+ /**
43
+ * Create a fresh instance of the harness adapter with the given ID.
44
+ *
45
+ * @param id - Harness adapter ID.
46
+ * @returns A new {@link HarnessAdapter} instance, or `null` when the ID is
47
+ * not registered.
48
+ *
49
+ * @public
50
+ */
51
+ export declare function createHarness(id: string): HarnessAdapter | null;
52
+ /**
53
+ * Return all registered harness adapter entries.
54
+ *
55
+ * @returns Array of all registry entries, in insertion order.
56
+ *
57
+ * @public
58
+ */
59
+ export declare function listHarnesses(): HarnessRegistryEntry[];
60
+ export { PiCodingAgentAdapter } from './pi-coding-agent/adapter.js';
61
+ export type { HarnessAdapter } from './pi-coding-agent/types.js';
62
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/harnesses/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;AAGH,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,4BAA4B,CAAC;AAMjE;;;;GAIG;AACH,MAAM,WAAW,oBAAoB;IACnC,kEAAkE;IAClE,EAAE,EAAE,MAAM,CAAC;IACX,mCAAmC;IACnC,IAAI,EAAE,MAAM,CAAC;IACb,8DAA8D;IAC9D,MAAM,EAAE,MAAM,cAAc,CAAC;CAC9B;AAsBD;;;;;;;;;;;;;GAaG;AACH,wBAAgB,eAAe,CAAC,EAAE,EAAE,MAAM,GAAG,oBAAoB,GAAG,SAAS,CAE5E;AAED;;;;;;;;GAQG;AACH,wBAAgB,aAAa,CAAC,EAAE,EAAE,MAAM,GAAG,cAAc,GAAG,IAAI,CAE/D;AAED;;;;;;GAMG;AACH,wBAAgB,aAAa,IAAI,oBAAoB,EAAE,CAEtD;AAED,OAAO,EAAE,oBAAoB,EAAE,MAAM,8BAA8B,CAAC;AAEpE,YAAY,EAAE,cAAc,EAAE,MAAM,4BAA4B,CAAC"}
@@ -0,0 +1,72 @@
1
+ /**
2
+ * cleo-os Harness Registry.
3
+ *
4
+ * Centralises construction and lookup of {@link HarnessAdapter} implementations
5
+ * available in cleo-os. Adding a new harness means:
6
+ *
7
+ * 1. Implement {@link HarnessAdapter} in a subdirectory under `harnesses/`.
8
+ * 2. Add an entry to {@link HARNESS_REGISTRY} below.
9
+ * 3. Export the adapter class from the subdirectory's `index.ts`.
10
+ *
11
+ * @packageDocumentation
12
+ */
13
+ import { PiCodingAgentAdapter } from './pi-coding-agent/adapter.js';
14
+ /**
15
+ * All harness adapters registered with cleo-os.
16
+ *
17
+ * Keyed by the adapter's {@link HarnessAdapter.id}.
18
+ */
19
+ const HARNESS_REGISTRY = new Map([
20
+ [
21
+ 'pi-coding-agent',
22
+ {
23
+ id: 'pi-coding-agent',
24
+ name: 'Pi Coding Agent',
25
+ create: () => new PiCodingAgentAdapter(),
26
+ },
27
+ ],
28
+ ]);
29
+ // ---------------------------------------------------------------------------
30
+ // Public API
31
+ // ---------------------------------------------------------------------------
32
+ /**
33
+ * Look up a harness adapter by ID.
34
+ *
35
+ * @param id - Harness adapter ID (e.g. `"pi-coding-agent"`).
36
+ * @returns The registry entry, or `undefined` when not found.
37
+ *
38
+ * @example
39
+ * ```typescript
40
+ * const entry = getHarnessEntry('pi-coding-agent');
41
+ * const adapter = entry?.create();
42
+ * ```
43
+ *
44
+ * @public
45
+ */
46
+ export function getHarnessEntry(id) {
47
+ return HARNESS_REGISTRY.get(id);
48
+ }
49
+ /**
50
+ * Create a fresh instance of the harness adapter with the given ID.
51
+ *
52
+ * @param id - Harness adapter ID.
53
+ * @returns A new {@link HarnessAdapter} instance, or `null` when the ID is
54
+ * not registered.
55
+ *
56
+ * @public
57
+ */
58
+ export function createHarness(id) {
59
+ return HARNESS_REGISTRY.get(id)?.create() ?? null;
60
+ }
61
+ /**
62
+ * Return all registered harness adapter entries.
63
+ *
64
+ * @returns Array of all registry entries, in insertion order.
65
+ *
66
+ * @public
67
+ */
68
+ export function listHarnesses() {
69
+ return Array.from(HARNESS_REGISTRY.values());
70
+ }
71
+ export { PiCodingAgentAdapter } from './pi-coding-agent/adapter.js';
72
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/harnesses/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;AAEH,OAAO,EAAE,oBAAoB,EAAE,MAAM,8BAA8B,CAAC;AAqBpE;;;;GAIG;AACH,MAAM,gBAAgB,GAA8C,IAAI,GAAG,CAAC;IAC1E;QACE,iBAAiB;QACjB;YACE,EAAE,EAAE,iBAAiB;YACrB,IAAI,EAAE,iBAAiB;YACvB,MAAM,EAAE,GAAG,EAAE,CAAC,IAAI,oBAAoB,EAAE;SACzC;KACF;CACF,CAAC,CAAC;AAEH,8EAA8E;AAC9E,aAAa;AACb,8EAA8E;AAE9E;;;;;;;;;;;;;GAaG;AACH,MAAM,UAAU,eAAe,CAAC,EAAU;IACxC,OAAO,gBAAgB,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC;AAClC,CAAC;AAED;;;;;;;;GAQG;AACH,MAAM,UAAU,aAAa,CAAC,EAAU;IACtC,OAAO,gBAAgB,CAAC,GAAG,CAAC,EAAE,CAAC,EAAE,MAAM,EAAE,IAAI,IAAI,CAAC;AACpD,CAAC;AAED;;;;;;GAMG;AACH,MAAM,UAAU,aAAa;IAC3B,OAAO,KAAK,CAAC,IAAI,CAAC,gBAAgB,CAAC,MAAM,EAAE,CAAC,CAAC;AAC/C,CAAC;AAED,OAAO,EAAE,oBAAoB,EAAE,MAAM,8BAA8B,CAAC"}
@@ -0,0 +1,132 @@
1
+ /**
2
+ * Pi Coding Agent Harness Adapter — cleo-os implementation.
3
+ *
4
+ * Implements the {@link HarnessAdapter} interface for the Pi coding agent CLI
5
+ * (`@mariozechner/pi-coding-agent`). Provides process spawn, status, kill,
6
+ * and output streaming for Pi processes launched by cleo-os.
7
+ *
8
+ * @remarks
9
+ * This adapter is the cleo-os counterpart to the CAAMP
10
+ * `PiSpawnProvider` in `packages/adapters/src/providers/pi/spawn.ts`.
11
+ * Where the CAAMP spawn provider is a detached fire-and-forget launcher,
12
+ * this adapter owns the full process lifecycle — attached stdin/stdout/stderr,
13
+ * bounded output buffering, and structured exit promises — so it can be
14
+ * used in orchestrated sandbox runs.
15
+ *
16
+ * Two launch modes are supported:
17
+ * - **Host-native** (default): Pi is invoked directly from PATH (or via
18
+ * `CLEO_PI_BINARY`). This is the standard mode for local development.
19
+ * - **Docker sandbox** (opt-in): Pi is launched inside the
20
+ * `cleo-sandbox/pi:local` Docker container when `CLEO_PI_SANDBOXED=1` is
21
+ * set or `sandboxed: true` is passed to {@link PiCodingAgentAdapter.spawn}.
22
+ * Falls back to host-native with a warning when Docker is unavailable.
23
+ *
24
+ * Instance IDs have the format `pi-<taskId>-<shortRandom>` to make
25
+ * correlation with task records straightforward.
26
+ *
27
+ * @see packages/adapters/src/providers/pi/spawn.ts — CAAMP spawn provider
28
+ * @see packages/cleo-os/src/harnesses/pi-coding-agent/pi-wrapper.ts — process management
29
+ * @see packages/cleo-os/src/harnesses/pi-coding-agent/docker-mode.ts — sandbox mode
30
+ * @task T922
31
+ * @epic T911
32
+ * @packageDocumentation
33
+ */
34
+ import type { HarnessAdapter, HarnessOutputLine, HarnessProcessStatus, HarnessSpawnOptions, HarnessSpawnResult } from './types.js';
35
+ /**
36
+ * Harness adapter for the Pi coding agent CLI in the cleo-os sandbox.
37
+ *
38
+ * Manages a pool of Pi processes, each identified by a stable instance ID.
39
+ * Supports host-native and Docker sandbox launch modes.
40
+ *
41
+ * @example
42
+ * ```typescript
43
+ * const adapter = new PiCodingAgentAdapter();
44
+ * const { instanceId, exitPromise } = await adapter.spawn('T123', 'Write a hello-world script');
45
+ * const status = await exitPromise;
46
+ * console.log('exit code:', status.exitCode);
47
+ * ```
48
+ *
49
+ * @public
50
+ */
51
+ export declare class PiCodingAgentAdapter implements HarnessAdapter {
52
+ /** Short adapter identifier. */
53
+ readonly id = "pi-coding-agent";
54
+ /** Active process tracking entries keyed by instance ID. */
55
+ private readonly processes;
56
+ /** Low-level Pi process launcher. */
57
+ private readonly wrapper;
58
+ /** Docker sandbox mode adapter. */
59
+ private readonly docker;
60
+ /**
61
+ * Generate a stable instance ID for a spawned process.
62
+ *
63
+ * @param taskId - CLEO task ID.
64
+ * @returns Instance ID string in the format `pi-<taskId>-<shortRandom>`.
65
+ */
66
+ private makeInstanceId;
67
+ /**
68
+ * Spawn a Pi coding agent process with the given task prompt.
69
+ *
70
+ * When `opts.sandboxed` is `true` (or `CLEO_PI_SANDBOXED=1` is set), the
71
+ * adapter first verifies Docker readiness and delegates to
72
+ * {@link DockerModeAdapter.spawnInDocker}. On Docker failure it falls back
73
+ * to host-native mode with a warning to stderr.
74
+ *
75
+ * The returned {@link HarnessSpawnResult.exitPromise} resolves once the
76
+ * process exits or is killed. It NEVER rejects — failures are encoded in
77
+ * the resolved {@link HarnessProcessStatus}.
78
+ *
79
+ * @param taskId - Stable CLEO task identifier associated with this run.
80
+ * @param prompt - Prompt text to pass to the Pi agent.
81
+ * @param opts - Optional spawn configuration.
82
+ * @returns Spawn result containing the instance ID, PID, and exit promise.
83
+ *
84
+ * @public
85
+ */
86
+ spawn(taskId: string, prompt: string, opts?: HarnessSpawnOptions): Promise<HarnessSpawnResult>;
87
+ /**
88
+ * Query the current status of a spawned process.
89
+ *
90
+ * @param instanceId - Instance ID returned from {@link spawn}.
91
+ * @returns Current status snapshot, or `null` when the ID is not tracked.
92
+ *
93
+ * @public
94
+ */
95
+ status(instanceId: string): HarnessProcessStatus | null;
96
+ /**
97
+ * Terminate a running Pi process via SIGTERM-then-SIGKILL.
98
+ *
99
+ * Idempotent — subsequent calls after the first are no-ops.
100
+ *
101
+ * @param instanceId - Instance ID returned from {@link spawn}.
102
+ *
103
+ * @public
104
+ */
105
+ kill(instanceId: string): Promise<void>;
106
+ /**
107
+ * Return recently captured output lines for a process.
108
+ *
109
+ * Returns a snapshot of the bounded ring buffer maintained by the wrapper.
110
+ * The buffer is limited to `CLEO_HARNESS_OUTPUT_BUFFER` lines (default 500).
111
+ *
112
+ * @param instanceId - Instance ID returned from {@link spawn}.
113
+ * @returns Array of recent output lines, oldest first; empty when not found.
114
+ *
115
+ * @public
116
+ */
117
+ output(instanceId: string): HarnessOutputLine[];
118
+ /**
119
+ * Spawn Pi inside a Docker sandbox container.
120
+ *
121
+ * Checks Docker readiness first. On failure, falls back to host-native
122
+ * mode with a stderr warning. Prompt delivery and output buffering follow
123
+ * the same pattern as the host-native path in {@link PiWrapper.start}.
124
+ *
125
+ * @param entry - Process tracking entry (mutated in place).
126
+ * @param prompt - Prompt text to deliver to Pi.
127
+ * @param cwd - Host working directory (bind-mounted into container).
128
+ * @param env - Extra environment variable overrides.
129
+ */
130
+ private spawnInSandbox;
131
+ }
132
+ //# sourceMappingURL=adapter.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"adapter.d.ts","sourceRoot":"","sources":["../../../src/harnesses/pi-coding-agent/adapter.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAgCG;AAKH,OAAO,KAAK,EACV,cAAc,EACd,iBAAiB,EACjB,oBAAoB,EACpB,mBAAmB,EACnB,kBAAkB,EACnB,MAAM,YAAY,CAAC;AAMpB;;;;;;;;;;;;;;;GAeG;AACH,qBAAa,oBAAqB,YAAW,cAAc;IACzD,gCAAgC;IAChC,QAAQ,CAAC,EAAE,qBAAqB;IAEhC,4DAA4D;IAC5D,OAAO,CAAC,QAAQ,CAAC,SAAS,CAAqC;IAE/D,qCAAqC;IACrC,OAAO,CAAC,QAAQ,CAAC,OAAO,CAAmB;IAE3C,mCAAmC;IACnC,OAAO,CAAC,QAAQ,CAAC,MAAM,CAA2B;IAElD;;;;;OAKG;IACH,OAAO,CAAC,cAAc;IAKtB;;;;;;;;;;;;;;;;;;OAkBG;IACG,KAAK,CACT,MAAM,EAAE,MAAM,EACd,MAAM,EAAE,MAAM,EACd,IAAI,CAAC,EAAE,mBAAmB,GACzB,OAAO,CAAC,kBAAkB,CAAC;IAmC9B;;;;;;;OAOG;IACH,MAAM,CAAC,UAAU,EAAE,MAAM,GAAG,oBAAoB,GAAG,IAAI;IAMvD;;;;;;;;OAQG;IACG,IAAI,CAAC,UAAU,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAM7C;;;;;;;;;;OAUG;IACH,MAAM,CAAC,UAAU,EAAE,MAAM,GAAG,iBAAiB,EAAE;IAU/C;;;;;;;;;;;OAWG;YACW,cAAc;CAuF7B"}
@@ -0,0 +1,265 @@
1
+ /**
2
+ * Pi Coding Agent Harness Adapter — cleo-os implementation.
3
+ *
4
+ * Implements the {@link HarnessAdapter} interface for the Pi coding agent CLI
5
+ * (`@mariozechner/pi-coding-agent`). Provides process spawn, status, kill,
6
+ * and output streaming for Pi processes launched by cleo-os.
7
+ *
8
+ * @remarks
9
+ * This adapter is the cleo-os counterpart to the CAAMP
10
+ * `PiSpawnProvider` in `packages/adapters/src/providers/pi/spawn.ts`.
11
+ * Where the CAAMP spawn provider is a detached fire-and-forget launcher,
12
+ * this adapter owns the full process lifecycle — attached stdin/stdout/stderr,
13
+ * bounded output buffering, and structured exit promises — so it can be
14
+ * used in orchestrated sandbox runs.
15
+ *
16
+ * Two launch modes are supported:
17
+ * - **Host-native** (default): Pi is invoked directly from PATH (or via
18
+ * `CLEO_PI_BINARY`). This is the standard mode for local development.
19
+ * - **Docker sandbox** (opt-in): Pi is launched inside the
20
+ * `cleo-sandbox/pi:local` Docker container when `CLEO_PI_SANDBOXED=1` is
21
+ * set or `sandboxed: true` is passed to {@link PiCodingAgentAdapter.spawn}.
22
+ * Falls back to host-native with a warning when Docker is unavailable.
23
+ *
24
+ * Instance IDs have the format `pi-<taskId>-<shortRandom>` to make
25
+ * correlation with task records straightforward.
26
+ *
27
+ * @see packages/adapters/src/providers/pi/spawn.ts — CAAMP spawn provider
28
+ * @see packages/cleo-os/src/harnesses/pi-coding-agent/pi-wrapper.ts — process management
29
+ * @see packages/cleo-os/src/harnesses/pi-coding-agent/docker-mode.ts — sandbox mode
30
+ * @task T922
31
+ * @epic T911
32
+ * @packageDocumentation
33
+ */
34
+ import { writeFile } from 'node:fs/promises';
35
+ import { DockerModeAdapter, isSandboxedGlobally } from './docker-mode.js';
36
+ import { buildStatus, createProcessEntry, PiWrapper } from './pi-wrapper.js';
37
+ // ---------------------------------------------------------------------------
38
+ // PiCodingAgentAdapter
39
+ // ---------------------------------------------------------------------------
40
+ /**
41
+ * Harness adapter for the Pi coding agent CLI in the cleo-os sandbox.
42
+ *
43
+ * Manages a pool of Pi processes, each identified by a stable instance ID.
44
+ * Supports host-native and Docker sandbox launch modes.
45
+ *
46
+ * @example
47
+ * ```typescript
48
+ * const adapter = new PiCodingAgentAdapter();
49
+ * const { instanceId, exitPromise } = await adapter.spawn('T123', 'Write a hello-world script');
50
+ * const status = await exitPromise;
51
+ * console.log('exit code:', status.exitCode);
52
+ * ```
53
+ *
54
+ * @public
55
+ */
56
+ export class PiCodingAgentAdapter {
57
+ /** Short adapter identifier. */
58
+ id = 'pi-coding-agent';
59
+ /** Active process tracking entries keyed by instance ID. */
60
+ processes = new Map();
61
+ /** Low-level Pi process launcher. */
62
+ wrapper = new PiWrapper();
63
+ /** Docker sandbox mode adapter. */
64
+ docker = new DockerModeAdapter();
65
+ /**
66
+ * Generate a stable instance ID for a spawned process.
67
+ *
68
+ * @param taskId - CLEO task ID.
69
+ * @returns Instance ID string in the format `pi-<taskId>-<shortRandom>`.
70
+ */
71
+ makeInstanceId(taskId) {
72
+ const rnd = Math.random().toString(36).slice(2, 9);
73
+ return `pi-${taskId}-${rnd}`;
74
+ }
75
+ /**
76
+ * Spawn a Pi coding agent process with the given task prompt.
77
+ *
78
+ * When `opts.sandboxed` is `true` (or `CLEO_PI_SANDBOXED=1` is set), the
79
+ * adapter first verifies Docker readiness and delegates to
80
+ * {@link DockerModeAdapter.spawnInDocker}. On Docker failure it falls back
81
+ * to host-native mode with a warning to stderr.
82
+ *
83
+ * The returned {@link HarnessSpawnResult.exitPromise} resolves once the
84
+ * process exits or is killed. It NEVER rejects — failures are encoded in
85
+ * the resolved {@link HarnessProcessStatus}.
86
+ *
87
+ * @param taskId - Stable CLEO task identifier associated with this run.
88
+ * @param prompt - Prompt text to pass to the Pi agent.
89
+ * @param opts - Optional spawn configuration.
90
+ * @returns Spawn result containing the instance ID, PID, and exit promise.
91
+ *
92
+ * @public
93
+ */
94
+ async spawn(taskId, prompt, opts) {
95
+ const instanceId = this.makeInstanceId(taskId);
96
+ const cwd = opts?.cwd ?? process.cwd();
97
+ const env = opts?.env ?? {};
98
+ const useSandbox = opts?.sandboxed === true || isSandboxedGlobally();
99
+ // Build exit promise — resolved by the process entry when the child exits.
100
+ let resolveExit;
101
+ const exitPromise = new Promise((resolve) => {
102
+ resolveExit = resolve;
103
+ });
104
+ const entry = createProcessEntry(instanceId, taskId, resolveExit);
105
+ this.processes.set(instanceId, entry);
106
+ // Wire abort signal to kill.
107
+ if (opts?.signal !== undefined) {
108
+ opts.signal.addEventListener('abort', () => {
109
+ void this.kill(instanceId);
110
+ });
111
+ }
112
+ if (useSandbox) {
113
+ await this.spawnInSandbox(entry, prompt, cwd, env);
114
+ }
115
+ else {
116
+ await this.wrapper.start(entry, prompt, cwd, env);
117
+ }
118
+ return {
119
+ instanceId,
120
+ pid: entry.pid,
121
+ exitPromise,
122
+ };
123
+ }
124
+ /**
125
+ * Query the current status of a spawned process.
126
+ *
127
+ * @param instanceId - Instance ID returned from {@link spawn}.
128
+ * @returns Current status snapshot, or `null` when the ID is not tracked.
129
+ *
130
+ * @public
131
+ */
132
+ status(instanceId) {
133
+ const entry = this.processes.get(instanceId);
134
+ if (entry === undefined)
135
+ return null;
136
+ return buildStatus(entry);
137
+ }
138
+ /**
139
+ * Terminate a running Pi process via SIGTERM-then-SIGKILL.
140
+ *
141
+ * Idempotent — subsequent calls after the first are no-ops.
142
+ *
143
+ * @param instanceId - Instance ID returned from {@link spawn}.
144
+ *
145
+ * @public
146
+ */
147
+ async kill(instanceId) {
148
+ const entry = this.processes.get(instanceId);
149
+ if (entry === undefined)
150
+ return;
151
+ this.wrapper.terminate(entry);
152
+ }
153
+ /**
154
+ * Return recently captured output lines for a process.
155
+ *
156
+ * Returns a snapshot of the bounded ring buffer maintained by the wrapper.
157
+ * The buffer is limited to `CLEO_HARNESS_OUTPUT_BUFFER` lines (default 500).
158
+ *
159
+ * @param instanceId - Instance ID returned from {@link spawn}.
160
+ * @returns Array of recent output lines, oldest first; empty when not found.
161
+ *
162
+ * @public
163
+ */
164
+ output(instanceId) {
165
+ const entry = this.processes.get(instanceId);
166
+ if (entry === undefined)
167
+ return [];
168
+ return [...entry.outputBuffer];
169
+ }
170
+ // ---------------------------------------------------------------------------
171
+ // Internal — Docker sandbox path
172
+ // ---------------------------------------------------------------------------
173
+ /**
174
+ * Spawn Pi inside a Docker sandbox container.
175
+ *
176
+ * Checks Docker readiness first. On failure, falls back to host-native
177
+ * mode with a stderr warning. Prompt delivery and output buffering follow
178
+ * the same pattern as the host-native path in {@link PiWrapper.start}.
179
+ *
180
+ * @param entry - Process tracking entry (mutated in place).
181
+ * @param prompt - Prompt text to deliver to Pi.
182
+ * @param cwd - Host working directory (bind-mounted into container).
183
+ * @param env - Extra environment variable overrides.
184
+ */
185
+ async spawnInSandbox(entry, prompt, cwd, env) {
186
+ const readiness = await this.docker.checkReadiness();
187
+ if (!readiness.ready) {
188
+ process.stderr.write(`[cleo-os/pi-coding-agent] Docker sandbox not ready: ${readiness.reason ?? 'unknown reason'}. Falling back to host-native mode.\n`);
189
+ await this.wrapper.start(entry, prompt, cwd, env);
190
+ return;
191
+ }
192
+ // Write prompt to a host-side temp file (bind-mounted read-only into container).
193
+ const promptFilePath = `/tmp/cleo-pi-${entry.instanceId}.txt`;
194
+ entry.tmpFile = promptFilePath;
195
+ try {
196
+ await writeFile(promptFilePath, prompt, 'utf-8');
197
+ }
198
+ catch (err) {
199
+ entry.state = 'failed';
200
+ entry.error = err instanceof Error ? err.message : String(err);
201
+ entry.endedAt = new Date().toISOString();
202
+ entry.resolveExit(buildStatus(entry));
203
+ return;
204
+ }
205
+ // Delegate to DockerModeAdapter which builds `docker run` args and spawns.
206
+ const child = this.docker.spawnInDocker({
207
+ prompt,
208
+ cwd,
209
+ env,
210
+ promptFilePath,
211
+ });
212
+ entry.child = child;
213
+ entry.pid = child.pid ?? null;
214
+ entry.state = 'running';
215
+ const bufferSize = 500; // use default; getOutputBufferSize() is in pi-wrapper.ts
216
+ child.stdout?.setEncoding('utf-8');
217
+ child.stdout?.on('data', (chunk) => {
218
+ for (const rawLine of chunk.split('\n')) {
219
+ const line = rawLine.trimEnd();
220
+ if (line.length === 0)
221
+ continue;
222
+ entry.outputBuffer.push({ source: 'stdout', line, timestamp: new Date().toISOString() });
223
+ if (entry.outputBuffer.length > bufferSize)
224
+ entry.outputBuffer.shift();
225
+ }
226
+ });
227
+ child.stderr?.setEncoding('utf-8');
228
+ child.stderr?.on('data', (chunk) => {
229
+ for (const rawLine of chunk.split('\n')) {
230
+ const line = rawLine.trimEnd();
231
+ if (line.length === 0)
232
+ continue;
233
+ entry.outputBuffer.push({ source: 'stderr', line, timestamp: new Date().toISOString() });
234
+ if (entry.outputBuffer.length > bufferSize)
235
+ entry.outputBuffer.shift();
236
+ }
237
+ });
238
+ child.on('close', async (code, signal) => {
239
+ if (entry.killTimer !== null) {
240
+ clearTimeout(entry.killTimer);
241
+ entry.killTimer = null;
242
+ }
243
+ entry.child = null;
244
+ entry.endedAt = new Date().toISOString();
245
+ if (entry.state === 'running') {
246
+ entry.state = signal !== null ? 'killed' : 'exited';
247
+ entry.exitCode = code;
248
+ entry.terminatingSignal = signal;
249
+ }
250
+ // Clean up the host-side prompt temp file.
251
+ if (entry.tmpFile !== null) {
252
+ try {
253
+ const { unlink } = await import('node:fs/promises');
254
+ await unlink(entry.tmpFile);
255
+ }
256
+ catch {
257
+ // Best-effort.
258
+ }
259
+ entry.tmpFile = null;
260
+ }
261
+ entry.resolveExit(buildStatus(entry));
262
+ });
263
+ }
264
+ }
265
+ //# sourceMappingURL=adapter.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"adapter.js","sourceRoot":"","sources":["../../../src/harnesses/pi-coding-agent/adapter.ts"],"names":[],"mappings":"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"}