@cleocode/cleo-os 2026.4.100 → 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,179 @@
1
+ /**
2
+ * Docker sandbox mode for the Pi coding agent harness.
3
+ *
4
+ * When `CLEO_PI_SANDBOXED=1` is set (or `sandboxed: true` is passed to
5
+ * {@link PiCodingAgentAdapter.spawn}), the adapter routes the Pi process
6
+ * through a Docker container instead of running Pi host-native.
7
+ *
8
+ * @remarks
9
+ * The sandbox container image mirrors the pattern established by the
10
+ * `cleo-sandbox` project (`/mnt/projects/cleo-sandbox/harnesses/pi/`):
11
+ *
12
+ * - Base: `cleo-sandbox/pi:local` (or the image named in
13
+ * `CLEO_PI_SANDBOX_IMAGE`). This image has `@mariozechner/pi-coding-agent`
14
+ * installed globally and a non-root `cleo` user.
15
+ * - The cleocode source tree is bind-mounted read-only at `/sandbox-src`.
16
+ * - An artifacts volume is bind-mounted at `/sandbox`.
17
+ * - API keys are passed via `-e` at container creation time — NEVER baked
18
+ * into the image.
19
+ *
20
+ * When Docker is not available or the image is not present, the adapter
21
+ * falls back to host-native mode with a warning logged to stderr.
22
+ *
23
+ * Environment variable overrides (all optional):
24
+ * - `CLEO_PI_SANDBOXED` — set to `1` to enable docker mode globally
25
+ * - `CLEO_PI_SANDBOX_IMAGE` — Docker image name (default: `cleo-sandbox/pi:local`)
26
+ * - `CLEO_PI_SANDBOX_NETWORK` — Docker network name (default: none)
27
+ * - `CLEO_PI_SANDBOX_WORKDIR` — Container working directory (default: `/sandbox`)
28
+ * - `CLEO_PI_SANDBOX_SOURCE` — Host path bind-mounted at `/sandbox-src`
29
+ * - `CLEO_PI_SANDBOX_ARTIFACTS` — Host path bind-mounted at `/sandbox`
30
+ *
31
+ * @see `/mnt/projects/cleo-sandbox/harnesses/pi/Dockerfile` — reference image
32
+ * @see `/mnt/projects/openclaw/Dockerfile.sandbox-common` — OpenClaw sandbox pattern
33
+ * @packageDocumentation
34
+ */
35
+ import { spawn } from 'node:child_process';
36
+ /**
37
+ * Return `true` when docker sandbox mode is globally enabled via env var.
38
+ *
39
+ * @public
40
+ */
41
+ export declare function isSandboxedGlobally(): boolean;
42
+ /**
43
+ * Return the Docker image name to use for the Pi sandbox container.
44
+ *
45
+ * Reads `CLEO_PI_SANDBOX_IMAGE` from the environment; falls back to
46
+ * {@link DEFAULT_SANDBOX_IMAGE}.
47
+ *
48
+ * @public
49
+ */
50
+ export declare function getSandboxImage(): string;
51
+ /**
52
+ * Return the working directory path to use inside the container.
53
+ *
54
+ * Reads `CLEO_PI_SANDBOX_WORKDIR`; falls back to {@link DEFAULT_CONTAINER_WORKDIR}.
55
+ *
56
+ * @public
57
+ */
58
+ export declare function getContainerWorkdir(): string;
59
+ /**
60
+ * Check whether the Docker CLI is available and the daemon is reachable.
61
+ *
62
+ * Runs `docker info` with a short timeout. Returns `false` when Docker is
63
+ * not installed or the daemon is not running so the adapter can fall back
64
+ * gracefully to host-native mode.
65
+ *
66
+ * @returns `true` when Docker is usable, `false` otherwise.
67
+ *
68
+ * @public
69
+ */
70
+ export declare function isDockerAvailable(): Promise<boolean>;
71
+ /**
72
+ * Check whether the Pi sandbox Docker image exists locally.
73
+ *
74
+ * @param image - Image name to probe (defaults to {@link getSandboxImage}).
75
+ * @returns `true` when the image is present, `false` otherwise.
76
+ *
77
+ * @public
78
+ */
79
+ export declare function isSandboxImagePresent(image?: string): Promise<boolean>;
80
+ /**
81
+ * Options for constructing a `docker run` invocation.
82
+ *
83
+ * @public
84
+ */
85
+ export interface DockerRunOptions {
86
+ /** Prompt text to pass to Pi inside the container. */
87
+ prompt: string;
88
+ /**
89
+ * Host working directory.
90
+ *
91
+ * When set, mounted read-write at {@link getContainerWorkdir} inside the
92
+ * container so Pi can write output artifacts.
93
+ *
94
+ * @defaultValue undefined
95
+ */
96
+ cwd?: string;
97
+ /**
98
+ * Extra environment variable overrides injected via `-e` flags.
99
+ *
100
+ * @defaultValue undefined
101
+ */
102
+ env?: Record<string, string>;
103
+ /**
104
+ * Path to the temporary prompt file already written by the caller.
105
+ *
106
+ * The adapter writes the prompt to a host-side temp file and bind-mounts it
107
+ * into the container at `/tmp/pi-prompt.txt`. Pi reads this file as its
108
+ * prompt argument (`pi /tmp/pi-prompt.txt`).
109
+ *
110
+ * @defaultValue undefined
111
+ */
112
+ promptFilePath?: string;
113
+ /**
114
+ * Docker image override for this invocation.
115
+ *
116
+ * @defaultValue `getSandboxImage()`
117
+ */
118
+ image?: string;
119
+ }
120
+ /**
121
+ * Build the `docker run` argument array for a sandboxed Pi invocation.
122
+ *
123
+ * The resulting array is suitable as the second argument to Node's
124
+ * `child_process.spawn('docker', args)` call.
125
+ *
126
+ * @remarks
127
+ * Key design choices (mirroring OpenClaw's sandbox pattern):
128
+ * - `--rm` — container is removed on exit; no persistent container state.
129
+ * - Read-only source mount (`/sandbox-src:ro`) — prevents agent from
130
+ * modifying the cleocode source tree.
131
+ * - Read-write artifacts mount (`/sandbox`) — agent output lands here.
132
+ * - API keys forwarded from the host environment when present.
133
+ * - `PI_TELEMETRY=0` always injected to suppress telemetry.
134
+ * - No ports exposed — sandbox containers are ephemeral CLI workers.
135
+ *
136
+ * @param opts - Options controlling the container configuration.
137
+ * @returns Array of arguments for `docker run`.
138
+ *
139
+ * @public
140
+ */
141
+ export declare function buildDockerRunArgs(opts: DockerRunOptions): string[];
142
+ /**
143
+ * Supplemental adapter that wraps Pi runs inside a Docker sandbox container.
144
+ *
145
+ * Used by {@link PiCodingAgentAdapter} when sandbox mode is enabled.
146
+ * Callers should first call {@link checkDockerReadiness} to verify that
147
+ * Docker is available and the sandbox image is present.
148
+ *
149
+ * @public
150
+ */
151
+ export declare class DockerModeAdapter {
152
+ /**
153
+ * Verify that Docker is available and the sandbox image is present.
154
+ *
155
+ * @param image - Image to check (defaults to {@link getSandboxImage}).
156
+ * @returns Object describing readiness and any issue encountered.
157
+ *
158
+ * @public
159
+ */
160
+ checkReadiness(image?: string): Promise<{
161
+ ready: boolean;
162
+ reason?: string;
163
+ }>;
164
+ /**
165
+ * Spawn Pi inside a Docker sandbox container.
166
+ *
167
+ * Builds the `docker run` argument list via {@link buildDockerRunArgs} and
168
+ * delegates to Node's `child_process.spawn`. The returned `ChildProcess` is
169
+ * wired identically to the host-native path in {@link PiWrapper.start} so
170
+ * the adapter can use the same output buffering and cleanup logic.
171
+ *
172
+ * @param opts - Docker run options.
173
+ * @returns A spawned `ChildProcess` handle.
174
+ *
175
+ * @public
176
+ */
177
+ spawnInDocker(opts: DockerRunOptions): ReturnType<typeof spawn>;
178
+ }
179
+ //# sourceMappingURL=docker-mode.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"docker-mode.d.ts","sourceRoot":"","sources":["../../../src/harnesses/pi-coding-agent/docker-mode.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAiCG;AAEH,OAAO,EAAQ,KAAK,EAAE,MAAM,oBAAoB,CAAC;AAejD;;;;GAIG;AACH,wBAAgB,mBAAmB,IAAI,OAAO,CAE7C;AAED;;;;;;;GAOG;AACH,wBAAgB,eAAe,IAAI,MAAM,CAExC;AAED;;;;;;GAMG;AACH,wBAAgB,mBAAmB,IAAI,MAAM,CAE5C;AAMD;;;;;;;;;;GAUG;AACH,wBAAsB,iBAAiB,IAAI,OAAO,CAAC,OAAO,CAAC,CAO1D;AAED;;;;;;;GAOG;AACH,wBAAsB,qBAAqB,CAAC,KAAK,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC,CAU5E;AAMD;;;;GAIG;AACH,MAAM,WAAW,gBAAgB;IAC/B,sDAAsD;IACtD,MAAM,EAAE,MAAM,CAAC;IACf;;;;;;;OAOG;IACH,GAAG,CAAC,EAAE,MAAM,CAAC;IACb;;;;OAIG;IACH,GAAG,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IAC7B;;;;;;;;OAQG;IACH,cAAc,CAAC,EAAE,MAAM,CAAC;IACxB;;;;OAIG;IACH,KAAK,CAAC,EAAE,MAAM,CAAC;CAChB;AAED;;;;;;;;;;;;;;;;;;;;GAoBG;AACH,wBAAgB,kBAAkB,CAAC,IAAI,EAAE,gBAAgB,GAAG,MAAM,EAAE,CA2DnE;AAMD;;;;;;;;GAQG;AACH,qBAAa,iBAAiB;IAC5B;;;;;;;OAOG;IACG,cAAc,CAAC,KAAK,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC;QAAE,KAAK,EAAE,OAAO,CAAC;QAAC,MAAM,CAAC,EAAE,MAAM,CAAA;KAAE,CAAC;IAclF;;;;;;;;;;;;OAYG;IACH,aAAa,CAAC,IAAI,EAAE,gBAAgB,GAAG,UAAU,CAAC,OAAO,KAAK,CAAC;CAMhE"}
@@ -0,0 +1,241 @@
1
+ /**
2
+ * Docker sandbox mode for the Pi coding agent harness.
3
+ *
4
+ * When `CLEO_PI_SANDBOXED=1` is set (or `sandboxed: true` is passed to
5
+ * {@link PiCodingAgentAdapter.spawn}), the adapter routes the Pi process
6
+ * through a Docker container instead of running Pi host-native.
7
+ *
8
+ * @remarks
9
+ * The sandbox container image mirrors the pattern established by the
10
+ * `cleo-sandbox` project (`/mnt/projects/cleo-sandbox/harnesses/pi/`):
11
+ *
12
+ * - Base: `cleo-sandbox/pi:local` (or the image named in
13
+ * `CLEO_PI_SANDBOX_IMAGE`). This image has `@mariozechner/pi-coding-agent`
14
+ * installed globally and a non-root `cleo` user.
15
+ * - The cleocode source tree is bind-mounted read-only at `/sandbox-src`.
16
+ * - An artifacts volume is bind-mounted at `/sandbox`.
17
+ * - API keys are passed via `-e` at container creation time — NEVER baked
18
+ * into the image.
19
+ *
20
+ * When Docker is not available or the image is not present, the adapter
21
+ * falls back to host-native mode with a warning logged to stderr.
22
+ *
23
+ * Environment variable overrides (all optional):
24
+ * - `CLEO_PI_SANDBOXED` — set to `1` to enable docker mode globally
25
+ * - `CLEO_PI_SANDBOX_IMAGE` — Docker image name (default: `cleo-sandbox/pi:local`)
26
+ * - `CLEO_PI_SANDBOX_NETWORK` — Docker network name (default: none)
27
+ * - `CLEO_PI_SANDBOX_WORKDIR` — Container working directory (default: `/sandbox`)
28
+ * - `CLEO_PI_SANDBOX_SOURCE` — Host path bind-mounted at `/sandbox-src`
29
+ * - `CLEO_PI_SANDBOX_ARTIFACTS` — Host path bind-mounted at `/sandbox`
30
+ *
31
+ * @see `/mnt/projects/cleo-sandbox/harnesses/pi/Dockerfile` — reference image
32
+ * @see `/mnt/projects/openclaw/Dockerfile.sandbox-common` — OpenClaw sandbox pattern
33
+ * @packageDocumentation
34
+ */
35
+ import { exec, spawn } from 'node:child_process';
36
+ import { promisify } from 'node:util';
37
+ const execAsync = promisify(exec);
38
+ /** Default Docker image for the Pi sandbox container. */
39
+ const DEFAULT_SANDBOX_IMAGE = 'cleo-sandbox/pi:local';
40
+ /** Default working directory inside the sandbox container. */
41
+ const DEFAULT_CONTAINER_WORKDIR = '/sandbox';
42
+ // ---------------------------------------------------------------------------
43
+ // Configuration helpers
44
+ // ---------------------------------------------------------------------------
45
+ /**
46
+ * Return `true` when docker sandbox mode is globally enabled via env var.
47
+ *
48
+ * @public
49
+ */
50
+ export function isSandboxedGlobally() {
51
+ return process.env['CLEO_PI_SANDBOXED'] === '1';
52
+ }
53
+ /**
54
+ * Return the Docker image name to use for the Pi sandbox container.
55
+ *
56
+ * Reads `CLEO_PI_SANDBOX_IMAGE` from the environment; falls back to
57
+ * {@link DEFAULT_SANDBOX_IMAGE}.
58
+ *
59
+ * @public
60
+ */
61
+ export function getSandboxImage() {
62
+ return process.env['CLEO_PI_SANDBOX_IMAGE'] ?? DEFAULT_SANDBOX_IMAGE;
63
+ }
64
+ /**
65
+ * Return the working directory path to use inside the container.
66
+ *
67
+ * Reads `CLEO_PI_SANDBOX_WORKDIR`; falls back to {@link DEFAULT_CONTAINER_WORKDIR}.
68
+ *
69
+ * @public
70
+ */
71
+ export function getContainerWorkdir() {
72
+ return process.env['CLEO_PI_SANDBOX_WORKDIR'] ?? DEFAULT_CONTAINER_WORKDIR;
73
+ }
74
+ // ---------------------------------------------------------------------------
75
+ // Docker availability probe
76
+ // ---------------------------------------------------------------------------
77
+ /**
78
+ * Check whether the Docker CLI is available and the daemon is reachable.
79
+ *
80
+ * Runs `docker info` with a short timeout. Returns `false` when Docker is
81
+ * not installed or the daemon is not running so the adapter can fall back
82
+ * gracefully to host-native mode.
83
+ *
84
+ * @returns `true` when Docker is usable, `false` otherwise.
85
+ *
86
+ * @public
87
+ */
88
+ export async function isDockerAvailable() {
89
+ try {
90
+ await execAsync('docker info --format "{{.ServerVersion}}"', { timeout: 5000 });
91
+ return true;
92
+ }
93
+ catch {
94
+ return false;
95
+ }
96
+ }
97
+ /**
98
+ * Check whether the Pi sandbox Docker image exists locally.
99
+ *
100
+ * @param image - Image name to probe (defaults to {@link getSandboxImage}).
101
+ * @returns `true` when the image is present, `false` otherwise.
102
+ *
103
+ * @public
104
+ */
105
+ export async function isSandboxImagePresent(image) {
106
+ const tag = image ?? getSandboxImage();
107
+ try {
108
+ const { stdout } = await execAsync(`docker image inspect "${tag}" --format "{{.Id}}"`, {
109
+ timeout: 5000,
110
+ });
111
+ return stdout.trim().length > 0;
112
+ }
113
+ catch {
114
+ return false;
115
+ }
116
+ }
117
+ /**
118
+ * Build the `docker run` argument array for a sandboxed Pi invocation.
119
+ *
120
+ * The resulting array is suitable as the second argument to Node's
121
+ * `child_process.spawn('docker', args)` call.
122
+ *
123
+ * @remarks
124
+ * Key design choices (mirroring OpenClaw's sandbox pattern):
125
+ * - `--rm` — container is removed on exit; no persistent container state.
126
+ * - Read-only source mount (`/sandbox-src:ro`) — prevents agent from
127
+ * modifying the cleocode source tree.
128
+ * - Read-write artifacts mount (`/sandbox`) — agent output lands here.
129
+ * - API keys forwarded from the host environment when present.
130
+ * - `PI_TELEMETRY=0` always injected to suppress telemetry.
131
+ * - No ports exposed — sandbox containers are ephemeral CLI workers.
132
+ *
133
+ * @param opts - Options controlling the container configuration.
134
+ * @returns Array of arguments for `docker run`.
135
+ *
136
+ * @public
137
+ */
138
+ export function buildDockerRunArgs(opts) {
139
+ const image = opts.image ?? getSandboxImage();
140
+ const containerWorkdir = getContainerWorkdir();
141
+ const network = process.env['CLEO_PI_SANDBOX_NETWORK'];
142
+ const sourceMount = process.env['CLEO_PI_SANDBOX_SOURCE'];
143
+ const artifactsMount = opts.cwd ?? process.env['CLEO_PI_SANDBOX_ARTIFACTS'];
144
+ const args = ['run', '--rm', '--init'];
145
+ // Network isolation (optional).
146
+ if (network !== undefined && network.length > 0) {
147
+ args.push('--network', network);
148
+ }
149
+ // Working directory inside the container.
150
+ args.push('-w', containerWorkdir);
151
+ // Read-only source mount (cleocode source tree).
152
+ if (sourceMount !== undefined && sourceMount.length > 0) {
153
+ args.push('-v', `${sourceMount}:/sandbox-src:ro`);
154
+ }
155
+ // Read-write artifacts mount.
156
+ if (artifactsMount !== undefined && artifactsMount.length > 0) {
157
+ args.push('-v', `${artifactsMount}:${containerWorkdir}`);
158
+ }
159
+ // Bind-mount the prompt file into the container.
160
+ if (opts.promptFilePath !== undefined) {
161
+ args.push('-v', `${opts.promptFilePath}:/tmp/pi-prompt.txt:ro`);
162
+ }
163
+ // Core environment variables.
164
+ args.push('-e', 'PI_TELEMETRY=0');
165
+ // Forward API keys from the host environment.
166
+ for (const key of [
167
+ 'ANTHROPIC_API_KEY',
168
+ 'OPENAI_API_KEY',
169
+ 'GOOGLE_API_KEY',
170
+ 'OPENROUTER_API_KEY',
171
+ ]) {
172
+ const val = process.env[key];
173
+ if (val !== undefined && val.length > 0) {
174
+ args.push('-e', `${key}=${val}`);
175
+ }
176
+ }
177
+ // Caller-supplied environment overrides.
178
+ if (opts.env !== undefined) {
179
+ for (const [k, v] of Object.entries(opts.env)) {
180
+ args.push('-e', `${k}=${v}`);
181
+ }
182
+ }
183
+ // Image and command: `pi /tmp/pi-prompt.txt`
184
+ args.push(image, 'pi', '/tmp/pi-prompt.txt');
185
+ return args;
186
+ }
187
+ // ---------------------------------------------------------------------------
188
+ // DockerModeAdapter
189
+ // ---------------------------------------------------------------------------
190
+ /**
191
+ * Supplemental adapter that wraps Pi runs inside a Docker sandbox container.
192
+ *
193
+ * Used by {@link PiCodingAgentAdapter} when sandbox mode is enabled.
194
+ * Callers should first call {@link checkDockerReadiness} to verify that
195
+ * Docker is available and the sandbox image is present.
196
+ *
197
+ * @public
198
+ */
199
+ export class DockerModeAdapter {
200
+ /**
201
+ * Verify that Docker is available and the sandbox image is present.
202
+ *
203
+ * @param image - Image to check (defaults to {@link getSandboxImage}).
204
+ * @returns Object describing readiness and any issue encountered.
205
+ *
206
+ * @public
207
+ */
208
+ async checkReadiness(image) {
209
+ if (!(await isDockerAvailable())) {
210
+ return { ready: false, reason: 'Docker daemon not available' };
211
+ }
212
+ const tag = image ?? getSandboxImage();
213
+ if (!(await isSandboxImagePresent(tag))) {
214
+ return {
215
+ ready: false,
216
+ reason: `Sandbox image "${tag}" not found. Build it with: cd /mnt/projects/cleo-sandbox && docker build -f harnesses/pi/Dockerfile -t ${tag} .`,
217
+ };
218
+ }
219
+ return { ready: true };
220
+ }
221
+ /**
222
+ * Spawn Pi inside a Docker sandbox container.
223
+ *
224
+ * Builds the `docker run` argument list via {@link buildDockerRunArgs} and
225
+ * delegates to Node's `child_process.spawn`. The returned `ChildProcess` is
226
+ * wired identically to the host-native path in {@link PiWrapper.start} so
227
+ * the adapter can use the same output buffering and cleanup logic.
228
+ *
229
+ * @param opts - Docker run options.
230
+ * @returns A spawned `ChildProcess` handle.
231
+ *
232
+ * @public
233
+ */
234
+ spawnInDocker(opts) {
235
+ const args = buildDockerRunArgs(opts);
236
+ return spawn('docker', args, {
237
+ stdio: ['ignore', 'pipe', 'pipe'],
238
+ });
239
+ }
240
+ }
241
+ //# sourceMappingURL=docker-mode.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"docker-mode.js","sourceRoot":"","sources":["../../../src/harnesses/pi-coding-agent/docker-mode.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,13 @@
1
+ /**
2
+ * Pi Coding Agent harness adapter — public barrel export.
3
+ *
4
+ * Re-exports the adapter class, type contract, and supporting utilities
5
+ * for the Pi coding agent harness in cleo-os.
6
+ *
7
+ * @packageDocumentation
8
+ */
9
+ export { PiCodingAgentAdapter } from './adapter.js';
10
+ export { DockerModeAdapter, getSandboxImage, isSandboxedGlobally } from './docker-mode.js';
11
+ export { getPiBinaryPath, getTerminateGraceMs, PiWrapper, resolveExtensionPaths, } from './pi-wrapper.js';
12
+ export type { HarnessAdapter, HarnessOutputLine, HarnessProcessState, HarnessProcessStatus, HarnessSpawnOptions, HarnessSpawnResult, } from './types.js';
13
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/harnesses/pi-coding-agent/index.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAEH,OAAO,EAAE,oBAAoB,EAAE,MAAM,cAAc,CAAC;AACpD,OAAO,EAAE,iBAAiB,EAAE,eAAe,EAAE,mBAAmB,EAAE,MAAM,kBAAkB,CAAC;AAC3F,OAAO,EACL,eAAe,EACf,mBAAmB,EACnB,SAAS,EACT,qBAAqB,GACtB,MAAM,iBAAiB,CAAC;AACzB,YAAY,EACV,cAAc,EACd,iBAAiB,EACjB,mBAAmB,EACnB,oBAAoB,EACpB,mBAAmB,EACnB,kBAAkB,GACnB,MAAM,YAAY,CAAC"}
@@ -0,0 +1,12 @@
1
+ /**
2
+ * Pi Coding Agent harness adapter — public barrel export.
3
+ *
4
+ * Re-exports the adapter class, type contract, and supporting utilities
5
+ * for the Pi coding agent harness in cleo-os.
6
+ *
7
+ * @packageDocumentation
8
+ */
9
+ export { PiCodingAgentAdapter } from './adapter.js';
10
+ export { DockerModeAdapter, getSandboxImage, isSandboxedGlobally } from './docker-mode.js';
11
+ export { getPiBinaryPath, getTerminateGraceMs, PiWrapper, resolveExtensionPaths, } from './pi-wrapper.js';
12
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../../src/harnesses/pi-coding-agent/index.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAEH,OAAO,EAAE,oBAAoB,EAAE,MAAM,cAAc,CAAC;AACpD,OAAO,EAAE,iBAAiB,EAAE,eAAe,EAAE,mBAAmB,EAAE,MAAM,kBAAkB,CAAC;AAC3F,OAAO,EACL,eAAe,EACf,mBAAmB,EACnB,SAAS,EACT,qBAAqB,GACtB,MAAM,iBAAiB,CAAC"}
@@ -0,0 +1,178 @@
1
+ /**
2
+ * Pi binary wrapper — low-level launcher for the Pi coding agent CLI.
3
+ *
4
+ * Handles prompt delivery, process spawning, stdin/stdout/stderr wiring,
5
+ * and SIGTERM-then-SIGKILL cleanup. This module is the only place in
6
+ * cleo-os that touches `child_process.spawn` directly for Pi.
7
+ *
8
+ * @remarks
9
+ * Pi receives its prompt via **file mode**: the prompt text is written to a
10
+ * temporary file under `/tmp/` and passed as a positional CLI argument
11
+ * (`pi <file>`). This mirrors the pattern used by `PiSpawnProvider` in
12
+ * `packages/adapters/` and avoids stdin complexity for non-interactive runs.
13
+ *
14
+ * CleoOS extension injection follows the same mechanism as `cli.ts`: each
15
+ * discovered extension is prepended as `--extension <path>` so Pi loads
16
+ * bridges (CANT bridge, hooks bridge, etc.) even in non-interactive mode.
17
+ *
18
+ * Environment variable overrides (all optional):
19
+ * - `CLEO_PI_BINARY` — path to the `pi` binary (default: `pi` from PATH)
20
+ * - `CLEO_TERMINATE_GRACE_MS` — SIGTERM grace window in ms (default: `5000`)
21
+ * - `CLEO_HARNESS_OUTPUT_BUFFER` — ring buffer capacity per process (default: `500`)
22
+ *
23
+ * OpenClaw patterns adopted:
24
+ * - Extension injection via `--extension <path>` flags.
25
+ * - Prompt written to `/tmp/` with a unique suffix; cleaned up on exit.
26
+ * - `PI_TELEMETRY=0` injected by default to suppress telemetry in CI.
27
+ *
28
+ * @packageDocumentation
29
+ */
30
+ import type { ChildProcess } from 'node:child_process';
31
+ import type { HarnessOutputLine, HarnessProcessState, HarnessProcessStatus } from './types.js';
32
+ /**
33
+ * Resolve the `pi` binary path.
34
+ *
35
+ * Honours `CLEO_PI_BINARY` env var when set (absolute path or bare name),
36
+ * otherwise defaults to `pi` (expects the binary on PATH).
37
+ *
38
+ * @returns Resolved binary path string.
39
+ *
40
+ * @public
41
+ */
42
+ export declare function getPiBinaryPath(): string;
43
+ /**
44
+ * Return the SIGTERM grace window in milliseconds.
45
+ *
46
+ * Reads `CLEO_TERMINATE_GRACE_MS` from the environment; falls back to
47
+ * {@link DEFAULT_TERMINATE_GRACE_MS} when absent or non-positive.
48
+ *
49
+ * @public
50
+ */
51
+ export declare function getTerminateGraceMs(): number;
52
+ /**
53
+ * Return the output ring buffer capacity.
54
+ *
55
+ * Reads `CLEO_HARNESS_OUTPUT_BUFFER` from the environment; falls back to
56
+ * {@link DEFAULT_OUTPUT_BUFFER_SIZE} when absent or non-positive.
57
+ *
58
+ * @public
59
+ */
60
+ export declare function getOutputBufferSize(): number;
61
+ /**
62
+ * Collect CleoOS extension paths that exist on disk.
63
+ *
64
+ * Resolves the standard extension list relative to the compiled package root
65
+ * (`extensions/` directory adjacent to `dist/`). Only paths that exist on
66
+ * disk are returned — missing extensions are skipped silently so the adapter
67
+ * degrades gracefully when extensions are not installed.
68
+ *
69
+ * Mirrors `collectExtensionPaths()` in `cli.ts` but does not depend on
70
+ * `@cleocode/core` to keep this module free of external package imports.
71
+ *
72
+ * @returns Array of absolute `.js` extension paths.
73
+ *
74
+ * @public
75
+ */
76
+ export declare function resolveExtensionPaths(): string[];
77
+ /**
78
+ * Internal state tracked for each spawned Pi process.
79
+ */
80
+ export interface PiProcessEntry {
81
+ /** OS process ID (or null if spawn failed before assigning one). */
82
+ pid: number | null;
83
+ /** Live child process handle (null after the process exits). */
84
+ child: ChildProcess | null;
85
+ /** Task ID from the caller. */
86
+ taskId: string;
87
+ /** Stable instance ID. */
88
+ instanceId: string;
89
+ /** ISO-8601 spawn timestamp. */
90
+ startedAt: string;
91
+ /** Current lifecycle state. */
92
+ state: HarnessProcessState;
93
+ /** Exit code (populated on exit). */
94
+ exitCode: number | null;
95
+ /** Signal used to terminate (populated on kill). */
96
+ terminatingSignal: NodeJS.Signals | null;
97
+ /** ISO-8601 end timestamp. */
98
+ endedAt: string | null;
99
+ /** Error message for 'failed' state. */
100
+ error: string | null;
101
+ /** Bounded output ring buffer. */
102
+ outputBuffer: HarnessOutputLine[];
103
+ /** Resolve callback for the exitPromise. */
104
+ resolveExit: (status: HarnessProcessStatus) => void;
105
+ /** Path of the temporary prompt file (cleaned up on exit). */
106
+ tmpFile: string | null;
107
+ /** SIGKILL timer handle (set during the grace window). */
108
+ killTimer: ReturnType<typeof setTimeout> | null;
109
+ }
110
+ /**
111
+ * Snapshot the current state of a process entry as a {@link HarnessProcessStatus}.
112
+ *
113
+ * @param entry - The process tracking entry.
114
+ * @returns Immutable status snapshot.
115
+ *
116
+ * @public
117
+ */
118
+ export declare function buildStatus(entry: PiProcessEntry): HarnessProcessStatus;
119
+ /**
120
+ * Create a new process tracking entry for a given instance and task.
121
+ *
122
+ * The entry starts in a transitional `'failed'` state that will be
123
+ * immediately overwritten by {@link PiWrapper.start} on success.
124
+ *
125
+ * @param instanceId - Stable instance identifier.
126
+ * @param taskId - CLEO task ID.
127
+ * @param resolveExit - Promise resolve callback wired to the exit promise.
128
+ * @returns Initialised (pre-spawn) tracking entry.
129
+ *
130
+ * @public
131
+ */
132
+ export declare function createProcessEntry(instanceId: string, taskId: string, resolveExit: (status: HarnessProcessStatus) => void): PiProcessEntry;
133
+ /**
134
+ * Low-level Pi process launcher.
135
+ *
136
+ * Manages the full lifecycle of Pi CLI processes: spawning via
137
+ * {@link start}, output buffering into a ring buffer, and
138
+ * SIGTERM-then-SIGKILL termination via {@link terminate}. Process state
139
+ * is tracked in a {@link PiProcessEntry} held by the caller
140
+ * ({@link PiCodingAgentAdapter}).
141
+ *
142
+ * @public
143
+ */
144
+ export declare class PiWrapper {
145
+ /**
146
+ * Spawn a Pi CLI process for the given task.
147
+ *
148
+ * Writes the prompt to a temporary file in `/tmp/`, builds the argument
149
+ * list (prepending `--extension <path>` for each available CleoOS
150
+ * extension), and spawns Pi as a child process. Stdout and stderr are
151
+ * line-buffered into `entry.outputBuffer`.
152
+ *
153
+ * When spawn fails (e.g. binary not found), `entry.state` is set to
154
+ * `'failed'` and `entry.resolveExit` is called before returning.
155
+ *
156
+ * @param entry - Pre-allocated process tracking entry. Mutated in place.
157
+ * @param prompt - Prompt text to deliver to Pi.
158
+ * @param cwd - Working directory for the child process.
159
+ * @param env - Environment variable overrides merged atop the current env.
160
+ * @returns The mutated `entry` (for chaining convenience).
161
+ *
162
+ * @public
163
+ */
164
+ start(entry: PiProcessEntry, prompt: string, cwd: string, env: Record<string, string>): Promise<PiProcessEntry>;
165
+ /**
166
+ * Terminate a Pi process via SIGTERM-then-SIGKILL.
167
+ *
168
+ * Sends SIGTERM immediately. If the process has not exited within the
169
+ * configured grace window ({@link getTerminateGraceMs}), sends SIGKILL.
170
+ * Idempotent — subsequent calls when the process is already dead are no-ops.
171
+ *
172
+ * @param entry - The process tracking entry to terminate.
173
+ *
174
+ * @public
175
+ */
176
+ terminate(entry: PiProcessEntry): void;
177
+ }
178
+ //# sourceMappingURL=pi-wrapper.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"pi-wrapper.d.ts","sourceRoot":"","sources":["../../../src/harnesses/pi-coding-agent/pi-wrapper.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA4BG;AAEH,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,oBAAoB,CAAC;AAMvD,OAAO,KAAK,EAAE,iBAAiB,EAAE,mBAAmB,EAAE,oBAAoB,EAAE,MAAM,YAAY,CAAC;AAc/F;;;;;;;;;GASG;AACH,wBAAgB,eAAe,IAAI,MAAM,CAExC;AAED;;;;;;;GAOG;AACH,wBAAgB,mBAAmB,IAAI,MAAM,CAO5C;AAED;;;;;;;GAOG;AACH,wBAAgB,mBAAmB,IAAI,MAAM,CAO5C;AAMD;;;;;;;;;;;;;;GAcG;AACH,wBAAgB,qBAAqB,IAAI,MAAM,EAAE,CAYhD;AAMD;;GAEG;AACH,MAAM,WAAW,cAAc;IAC7B,oEAAoE;IACpE,GAAG,EAAE,MAAM,GAAG,IAAI,CAAC;IACnB,gEAAgE;IAChE,KAAK,EAAE,YAAY,GAAG,IAAI,CAAC;IAC3B,+BAA+B;IAC/B,MAAM,EAAE,MAAM,CAAC;IACf,0BAA0B;IAC1B,UAAU,EAAE,MAAM,CAAC;IACnB,gCAAgC;IAChC,SAAS,EAAE,MAAM,CAAC;IAClB,+BAA+B;IAC/B,KAAK,EAAE,mBAAmB,CAAC;IAC3B,qCAAqC;IACrC,QAAQ,EAAE,MAAM,GAAG,IAAI,CAAC;IACxB,oDAAoD;IACpD,iBAAiB,EAAE,MAAM,CAAC,OAAO,GAAG,IAAI,CAAC;IACzC,8BAA8B;IAC9B,OAAO,EAAE,MAAM,GAAG,IAAI,CAAC;IACvB,wCAAwC;IACxC,KAAK,EAAE,MAAM,GAAG,IAAI,CAAC;IACrB,kCAAkC;IAClC,YAAY,EAAE,iBAAiB,EAAE,CAAC;IAClC,4CAA4C;IAC5C,WAAW,EAAE,CAAC,MAAM,EAAE,oBAAoB,KAAK,IAAI,CAAC;IACpD,8DAA8D;IAC9D,OAAO,EAAE,MAAM,GAAG,IAAI,CAAC;IACvB,0DAA0D;IAC1D,SAAS,EAAE,UAAU,CAAC,OAAO,UAAU,CAAC,GAAG,IAAI,CAAC;CACjD;AAuCD;;;;;;;GAOG;AACH,wBAAgB,WAAW,CAAC,KAAK,EAAE,cAAc,GAAG,oBAAoB,CAWvE;AAED;;;;;;;;;;;;GAYG;AACH,wBAAgB,kBAAkB,CAChC,UAAU,EAAE,MAAM,EAClB,MAAM,EAAE,MAAM,EACd,WAAW,EAAE,CAAC,MAAM,EAAE,oBAAoB,KAAK,IAAI,GAClD,cAAc,CAiBhB;AAMD;;;;;;;;;;GAUG;AACH,qBAAa,SAAS;IACpB;;;;;;;;;;;;;;;;;;OAkBG;IACG,KAAK,CACT,KAAK,EAAE,cAAc,EACrB,MAAM,EAAE,MAAM,EACd,GAAG,EAAE,MAAM,EACX,GAAG,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,GAC1B,OAAO,CAAC,cAAc,CAAC;IAsG1B;;;;;;;;;;OAUG;IACH,SAAS,CAAC,KAAK,EAAE,cAAc,GAAG,IAAI;CAoBvC"}