@cleocode/adapters 2026.4.67 → 2026.4.68
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.
- package/dist/index.js +50 -32
- package/dist/index.js.map +4 -4
- package/dist/providers/codex/index.d.ts +1 -0
- package/dist/providers/codex/index.d.ts.map +1 -1
- package/dist/providers/codex/spawn.d.ts +82 -0
- package/dist/providers/codex/spawn.d.ts.map +1 -0
- package/dist/providers/gemini-cli/index.d.ts +1 -0
- package/dist/providers/gemini-cli/index.d.ts.map +1 -1
- package/dist/providers/gemini-cli/spawn.d.ts +83 -0
- package/dist/providers/gemini-cli/spawn.d.ts.map +1 -0
- package/dist/providers/kimi/index.d.ts +1 -0
- package/dist/providers/kimi/index.d.ts.map +1 -1
- package/dist/providers/kimi/spawn.d.ts +91 -0
- package/dist/providers/kimi/spawn.d.ts.map +1 -0
- package/package.json +3 -3
- package/src/providers/codex/index.ts +1 -0
- package/src/providers/codex/spawn.ts +224 -0
- package/src/providers/gemini-cli/index.ts +1 -0
- package/src/providers/gemini-cli/spawn.ts +220 -0
- package/src/providers/kimi/index.ts +1 -0
- package/src/providers/kimi/spawn.ts +274 -0
|
@@ -11,6 +11,7 @@ import { CodexAdapter } from './adapter.js';
|
|
|
11
11
|
export { CodexAdapter } from './adapter.js';
|
|
12
12
|
export { CodexHookProvider } from './hooks.js';
|
|
13
13
|
export { CodexInstallProvider } from './install.js';
|
|
14
|
+
export { CodexSpawnProvider } from './spawn.js';
|
|
14
15
|
export default CodexAdapter;
|
|
15
16
|
/**
|
|
16
17
|
* Factory function for creating adapter instances.
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/providers/codex/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAEH,OAAO,EAAE,YAAY,EAAE,MAAM,cAAc,CAAC;AAE5C,OAAO,EAAE,YAAY,EAAE,MAAM,cAAc,CAAC;AAC5C,OAAO,EAAE,iBAAiB,EAAE,MAAM,YAAY,CAAC;AAC/C,OAAO,EAAE,oBAAoB,EAAE,MAAM,cAAc,CAAC;
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/providers/codex/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAEH,OAAO,EAAE,YAAY,EAAE,MAAM,cAAc,CAAC;AAE5C,OAAO,EAAE,YAAY,EAAE,MAAM,cAAc,CAAC;AAC5C,OAAO,EAAE,iBAAiB,EAAE,MAAM,YAAY,CAAC;AAC/C,OAAO,EAAE,oBAAoB,EAAE,MAAM,cAAc,CAAC;AACpD,OAAO,EAAE,kBAAkB,EAAE,MAAM,YAAY,CAAC;AAEhD,eAAe,YAAY,CAAC;AAE5B;;;;;;;;;;;;;;;;;;;;GAoBG;AACH,wBAAgB,aAAa,IAAI,YAAY,CAE5C"}
|
|
@@ -0,0 +1,82 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Codex CLI Spawn Provider
|
|
3
|
+
*
|
|
4
|
+
* Implements `AdapterSpawnProvider` for the OpenAI Codex CLI (`codex` binary).
|
|
5
|
+
*
|
|
6
|
+
* The `codex` binary is the OpenAI Codex CLI agent, available at:
|
|
7
|
+
* https://github.com/openai/codex
|
|
8
|
+
*
|
|
9
|
+
* Invocation: `codex --full-auto <prompt-file>`
|
|
10
|
+
*
|
|
11
|
+
* The provider uses `--full-auto` (non-interactive, auto-approve all actions)
|
|
12
|
+
* which is the headless equivalent of the Claude Code `--dangerously-skip-permissions`
|
|
13
|
+
* flag. Processes run detached and are tracked by PID for listing and termination.
|
|
14
|
+
*
|
|
15
|
+
* If the `codex` binary is not found, `canSpawn()` returns `false` with a
|
|
16
|
+
* graceful error — no crash.
|
|
17
|
+
*
|
|
18
|
+
* @remarks
|
|
19
|
+
* As of 2026, the Codex CLI is the successor to the original OpenAI Codex
|
|
20
|
+
* playground. It reads prompts from stdin or file arguments and emits output
|
|
21
|
+
* to stdout. The `--full-auto` flag suppresses interactive approval prompts.
|
|
22
|
+
* Install: `npm install -g @openai/codex` or see the GitHub repo above.
|
|
23
|
+
*
|
|
24
|
+
* @task T648
|
|
25
|
+
*/
|
|
26
|
+
import type { AdapterSpawnProvider, SpawnContext, SpawnResult } from '@cleocode/contracts';
|
|
27
|
+
/**
|
|
28
|
+
* Spawn provider for the OpenAI Codex CLI.
|
|
29
|
+
*
|
|
30
|
+
* Spawns detached Codex CLI processes for subagent execution. Each spawn
|
|
31
|
+
* writes its prompt to a temporary file, then runs
|
|
32
|
+
* `codex --full-auto <tmpFile>` as a detached, unref'd child process.
|
|
33
|
+
*
|
|
34
|
+
* @remarks
|
|
35
|
+
* `canSpawn()` returns `false` (with no crash) when the `codex` binary is
|
|
36
|
+
* not found in PATH. Install instructions are emitted via `console.warn`
|
|
37
|
+
* once to help operators discover the binary is missing.
|
|
38
|
+
*
|
|
39
|
+
* Processes are tracked by instance ID in an in-memory map and verified
|
|
40
|
+
* via `kill(pid, 0)` liveness checks.
|
|
41
|
+
*
|
|
42
|
+
* @task T648
|
|
43
|
+
*/
|
|
44
|
+
export declare class CodexSpawnProvider implements AdapterSpawnProvider {
|
|
45
|
+
/** Map of instance IDs to tracked process info. */
|
|
46
|
+
private processMap;
|
|
47
|
+
/**
|
|
48
|
+
* Check if the Codex CLI is available in PATH.
|
|
49
|
+
*
|
|
50
|
+
* @returns `true` if `codex` is found via `which`
|
|
51
|
+
*/
|
|
52
|
+
canSpawn(): Promise<boolean>;
|
|
53
|
+
/**
|
|
54
|
+
* Spawn a subagent via the Codex CLI.
|
|
55
|
+
*
|
|
56
|
+
* Writes the prompt to a temporary file and spawns a detached Codex
|
|
57
|
+
* process. The process runs independently of the parent.
|
|
58
|
+
*
|
|
59
|
+
* @param context - Spawn context with taskId, prompt, and options
|
|
60
|
+
* @returns Spawn result with instance ID and status
|
|
61
|
+
*/
|
|
62
|
+
spawn(context: SpawnContext): Promise<SpawnResult>;
|
|
63
|
+
/**
|
|
64
|
+
* List currently running Codex subagent processes.
|
|
65
|
+
*
|
|
66
|
+
* Checks each tracked process via kill(pid, 0) to verify it is still alive.
|
|
67
|
+
* Dead processes are automatically cleaned from the tracking map.
|
|
68
|
+
*
|
|
69
|
+
* @returns Array of spawn results for running processes
|
|
70
|
+
*/
|
|
71
|
+
listRunning(): Promise<SpawnResult[]>;
|
|
72
|
+
/**
|
|
73
|
+
* Terminate a running spawn by instance ID.
|
|
74
|
+
*
|
|
75
|
+
* Sends SIGTERM to the tracked process. If the process is not found
|
|
76
|
+
* or has already exited, this is a no-op.
|
|
77
|
+
*
|
|
78
|
+
* @param instanceId - ID of the spawn instance to terminate
|
|
79
|
+
*/
|
|
80
|
+
terminate(instanceId: string): Promise<void>;
|
|
81
|
+
}
|
|
82
|
+
//# sourceMappingURL=spawn.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"spawn.d.ts","sourceRoot":"","sources":["../../../src/providers/codex/spawn.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;GAwBG;AAKH,OAAO,KAAK,EAAE,oBAAoB,EAAE,YAAY,EAAE,WAAW,EAAE,MAAM,qBAAqB,CAAC;AAY3F;;;;;;;;;;;;;;;;GAgBG;AACH,qBAAa,kBAAmB,YAAW,oBAAoB;IAC7D,mDAAmD;IACnD,OAAO,CAAC,UAAU,CAAqC;IAEvD;;;;OAIG;IACG,QAAQ,IAAI,OAAO,CAAC,OAAO,CAAC;IAclC;;;;;;;;OAQG;IACG,KAAK,CAAC,OAAO,EAAE,YAAY,GAAG,OAAO,CAAC,WAAW,CAAC;IAqFxD;;;;;;;OAOG;IACG,WAAW,IAAI,OAAO,CAAC,WAAW,EAAE,CAAC;IAqB3C;;;;;;;OAOG;IACG,SAAS,CAAC,UAAU,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;CAWnD"}
|
|
@@ -11,6 +11,7 @@ import { GeminiCliAdapter } from './adapter.js';
|
|
|
11
11
|
export { GeminiCliAdapter } from './adapter.js';
|
|
12
12
|
export { GeminiCliHookProvider } from './hooks.js';
|
|
13
13
|
export { GeminiCliInstallProvider } from './install.js';
|
|
14
|
+
export { GeminiCliSpawnProvider } from './spawn.js';
|
|
14
15
|
export default GeminiCliAdapter;
|
|
15
16
|
/**
|
|
16
17
|
* Factory function for creating adapter instances.
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/providers/gemini-cli/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAEH,OAAO,EAAE,gBAAgB,EAAE,MAAM,cAAc,CAAC;AAEhD,OAAO,EAAE,gBAAgB,EAAE,MAAM,cAAc,CAAC;AAChD,OAAO,EAAE,qBAAqB,EAAE,MAAM,YAAY,CAAC;AACnD,OAAO,EAAE,wBAAwB,EAAE,MAAM,cAAc,CAAC;
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/providers/gemini-cli/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAEH,OAAO,EAAE,gBAAgB,EAAE,MAAM,cAAc,CAAC;AAEhD,OAAO,EAAE,gBAAgB,EAAE,MAAM,cAAc,CAAC;AAChD,OAAO,EAAE,qBAAqB,EAAE,MAAM,YAAY,CAAC;AACnD,OAAO,EAAE,wBAAwB,EAAE,MAAM,cAAc,CAAC;AACxD,OAAO,EAAE,sBAAsB,EAAE,MAAM,YAAY,CAAC;AAEpD,eAAe,gBAAgB,CAAC;AAEhC;;;;;;;;;;;;;;;;;;;;GAoBG;AACH,wBAAgB,aAAa,IAAI,gBAAgB,CAEhD"}
|
|
@@ -0,0 +1,83 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Gemini CLI Spawn Provider
|
|
3
|
+
*
|
|
4
|
+
* Implements `AdapterSpawnProvider` for the Google Gemini CLI (`gemini` binary).
|
|
5
|
+
*
|
|
6
|
+
* The `gemini` binary is the Google Gemini CLI agent, available at:
|
|
7
|
+
* https://github.com/google-gemini/gemini-cli
|
|
8
|
+
*
|
|
9
|
+
* Invocation: `gemini --yolo < <prompt-file>`
|
|
10
|
+
*
|
|
11
|
+
* The provider pipes the prompt via stdin using the `--yolo` flag, which
|
|
12
|
+
* enables non-interactive mode (auto-approve all actions). Processes run
|
|
13
|
+
* detached and are tracked by PID for listing and termination.
|
|
14
|
+
*
|
|
15
|
+
* If the `gemini` binary is not found, `canSpawn()` returns `false` with a
|
|
16
|
+
* graceful error — no crash.
|
|
17
|
+
*
|
|
18
|
+
* @remarks
|
|
19
|
+
* The Gemini CLI supports a `--model` flag to select the model family and a
|
|
20
|
+
* `--yolo` flag for non-interactive headless execution (equivalent to Claude
|
|
21
|
+
* Code's `--dangerously-skip-permissions`). Prompts are supplied via stdin
|
|
22
|
+
* when run in `--yolo` mode. Install: `npm install -g @google/gemini-cli`
|
|
23
|
+
* or see the GitHub repo above.
|
|
24
|
+
*
|
|
25
|
+
* @task T648
|
|
26
|
+
*/
|
|
27
|
+
import type { AdapterSpawnProvider, SpawnContext, SpawnResult } from '@cleocode/contracts';
|
|
28
|
+
/**
|
|
29
|
+
* Spawn provider for the Google Gemini CLI.
|
|
30
|
+
*
|
|
31
|
+
* Spawns detached Gemini CLI processes for subagent execution. Each spawn
|
|
32
|
+
* pipes its prompt via stdin, then runs
|
|
33
|
+
* `gemini --yolo --model <model>` as a detached, unref'd child process.
|
|
34
|
+
*
|
|
35
|
+
* @remarks
|
|
36
|
+
* `canSpawn()` returns `false` (with no crash) when the `gemini` binary is
|
|
37
|
+
* not found in PATH. Install instructions are emitted via `console.warn`
|
|
38
|
+
* once to help operators discover the binary is missing.
|
|
39
|
+
*
|
|
40
|
+
* Processes are tracked by instance ID in an in-memory map and verified
|
|
41
|
+
* via `kill(pid, 0)` liveness checks.
|
|
42
|
+
*
|
|
43
|
+
* @task T648
|
|
44
|
+
*/
|
|
45
|
+
export declare class GeminiCliSpawnProvider implements AdapterSpawnProvider {
|
|
46
|
+
/** Map of instance IDs to tracked process info. */
|
|
47
|
+
private processMap;
|
|
48
|
+
/**
|
|
49
|
+
* Check if the Gemini CLI is available in PATH.
|
|
50
|
+
*
|
|
51
|
+
* @returns `true` if `gemini` is found via `which`
|
|
52
|
+
*/
|
|
53
|
+
canSpawn(): Promise<boolean>;
|
|
54
|
+
/**
|
|
55
|
+
* Spawn a subagent via the Gemini CLI.
|
|
56
|
+
*
|
|
57
|
+
* Pipes the enriched prompt to stdin and spawns a detached Gemini
|
|
58
|
+
* process. The process runs independently of the parent.
|
|
59
|
+
*
|
|
60
|
+
* @param context - Spawn context with taskId, prompt, and options
|
|
61
|
+
* @returns Spawn result with instance ID and status
|
|
62
|
+
*/
|
|
63
|
+
spawn(context: SpawnContext): Promise<SpawnResult>;
|
|
64
|
+
/**
|
|
65
|
+
* List currently running Gemini CLI subagent processes.
|
|
66
|
+
*
|
|
67
|
+
* Checks each tracked process via kill(pid, 0) to verify it is still alive.
|
|
68
|
+
* Dead processes are automatically cleaned from the tracking map.
|
|
69
|
+
*
|
|
70
|
+
* @returns Array of spawn results for running processes
|
|
71
|
+
*/
|
|
72
|
+
listRunning(): Promise<SpawnResult[]>;
|
|
73
|
+
/**
|
|
74
|
+
* Terminate a running spawn by instance ID.
|
|
75
|
+
*
|
|
76
|
+
* Sends SIGTERM to the tracked process. If the process is not found
|
|
77
|
+
* or has already exited, this is a no-op.
|
|
78
|
+
*
|
|
79
|
+
* @param instanceId - ID of the spawn instance to terminate
|
|
80
|
+
*/
|
|
81
|
+
terminate(instanceId: string): Promise<void>;
|
|
82
|
+
}
|
|
83
|
+
//# sourceMappingURL=spawn.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"spawn.d.ts","sourceRoot":"","sources":["../../../src/providers/gemini-cli/spawn.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;GAyBG;AAIH,OAAO,KAAK,EAAE,oBAAoB,EAAE,YAAY,EAAE,WAAW,EAAE,MAAM,qBAAqB,CAAC;AAe3F;;;;;;;;;;;;;;;;GAgBG;AACH,qBAAa,sBAAuB,YAAW,oBAAoB;IACjE,mDAAmD;IACnD,OAAO,CAAC,UAAU,CAAqC;IAEvD;;;;OAIG;IACG,QAAQ,IAAI,OAAO,CAAC,OAAO,CAAC;IAclC;;;;;;;;OAQG;IACG,KAAK,CAAC,OAAO,EAAE,YAAY,GAAG,OAAO,CAAC,WAAW,CAAC;IA8ExD;;;;;;;OAOG;IACG,WAAW,IAAI,OAAO,CAAC,WAAW,EAAE,CAAC;IAqB3C;;;;;;;OAOG;IACG,SAAS,CAAC,UAAU,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;CAWnD"}
|
|
@@ -11,6 +11,7 @@ import { KimiAdapter } from './adapter.js';
|
|
|
11
11
|
export { KimiAdapter } from './adapter.js';
|
|
12
12
|
export { KimiHookProvider } from './hooks.js';
|
|
13
13
|
export { KimiInstallProvider } from './install.js';
|
|
14
|
+
export { KimiSpawnProvider } from './spawn.js';
|
|
14
15
|
export default KimiAdapter;
|
|
15
16
|
/**
|
|
16
17
|
* Factory function for creating adapter instances.
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/providers/kimi/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAEH,OAAO,EAAE,WAAW,EAAE,MAAM,cAAc,CAAC;AAE3C,OAAO,EAAE,WAAW,EAAE,MAAM,cAAc,CAAC;AAC3C,OAAO,EAAE,gBAAgB,EAAE,MAAM,YAAY,CAAC;AAC9C,OAAO,EAAE,mBAAmB,EAAE,MAAM,cAAc,CAAC;
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/providers/kimi/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAEH,OAAO,EAAE,WAAW,EAAE,MAAM,cAAc,CAAC;AAE3C,OAAO,EAAE,WAAW,EAAE,MAAM,cAAc,CAAC;AAC3C,OAAO,EAAE,gBAAgB,EAAE,MAAM,YAAY,CAAC;AAC9C,OAAO,EAAE,mBAAmB,EAAE,MAAM,cAAc,CAAC;AACnD,OAAO,EAAE,iBAAiB,EAAE,MAAM,YAAY,CAAC;AAE/C,eAAe,WAAW,CAAC;AAE3B;;;;;;;;;;;;;;;;;;;;GAoBG;AACH,wBAAgB,aAAa,IAAI,WAAW,CAE3C"}
|
|
@@ -0,0 +1,91 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Kimi (Moonshot AI) Spawn Provider
|
|
3
|
+
*
|
|
4
|
+
* Implements `AdapterSpawnProvider` for Moonshot AI's Kimi models.
|
|
5
|
+
*
|
|
6
|
+
* There is no widely-distributed standalone Kimi CLI binary. This provider
|
|
7
|
+
* uses the Moonshot AI Chat Completions API directly (REST, no extra SDK
|
|
8
|
+
* dependency) when `MOONSHOT_API_KEY` is present in the environment.
|
|
9
|
+
*
|
|
10
|
+
* API documentation: https://platform.moonshot.cn/docs/api/chat
|
|
11
|
+
* Endpoint: https://api.moonshot.cn/v1/chat/completions
|
|
12
|
+
*
|
|
13
|
+
* `canSpawn()` returns `true` only when:
|
|
14
|
+
* 1. `MOONSHOT_API_KEY` is set in the environment, OR
|
|
15
|
+
* 2. A `kimi` binary is found in PATH (future CLI support)
|
|
16
|
+
*
|
|
17
|
+
* If neither condition holds, `canSpawn()` returns `false` with a clear
|
|
18
|
+
* message — no crash.
|
|
19
|
+
*
|
|
20
|
+
* @remarks
|
|
21
|
+
* Unlike the CLI-based providers (codex, gemini-cli), Kimi spawn runs the
|
|
22
|
+
* API call to completion before returning (`status: 'completed'` or
|
|
23
|
+
* `status: 'failed'`). This mirrors the claude-sdk and openai-sdk providers.
|
|
24
|
+
* The API call uses Node's built-in `fetch` (Node 18+) with no extra
|
|
25
|
+
* dependencies.
|
|
26
|
+
*
|
|
27
|
+
* @task T648
|
|
28
|
+
*/
|
|
29
|
+
import type { AdapterSpawnProvider, SpawnContext, SpawnResult } from '@cleocode/contracts';
|
|
30
|
+
/**
|
|
31
|
+
* Spawn provider for Moonshot AI Kimi.
|
|
32
|
+
*
|
|
33
|
+
* Uses the Moonshot AI Chat Completions REST API to run subagent prompts.
|
|
34
|
+
* Each `spawn()` call completes synchronously (awaits the API response) and
|
|
35
|
+
* returns `status: 'completed'` or `status: 'failed'`.
|
|
36
|
+
*
|
|
37
|
+
* In-flight runs are tracked by instance ID so `listRunning()` reflects
|
|
38
|
+
* concurrent spawns correctly.
|
|
39
|
+
*
|
|
40
|
+
* @remarks
|
|
41
|
+
* `canSpawn()` checks for `MOONSHOT_API_KEY` first (API mode), then falls
|
|
42
|
+
* back to checking for a `kimi` CLI binary (CLI mode, future). If neither is
|
|
43
|
+
* available, `canSpawn()` returns `false` and `spawn()` throws a descriptive
|
|
44
|
+
* error rather than crashing silently.
|
|
45
|
+
*
|
|
46
|
+
* @task T648
|
|
47
|
+
*/
|
|
48
|
+
export declare class KimiSpawnProvider implements AdapterSpawnProvider {
|
|
49
|
+
/** In-flight run tracking set. */
|
|
50
|
+
private readonly runningInstances;
|
|
51
|
+
/**
|
|
52
|
+
* Check whether Kimi spawning is available in the current environment.
|
|
53
|
+
*
|
|
54
|
+
* Returns `true` when either:
|
|
55
|
+
* - `MOONSHOT_API_KEY` is set (API mode), or
|
|
56
|
+
* - A `kimi` binary is found in PATH (CLI mode — future)
|
|
57
|
+
*
|
|
58
|
+
* @returns `true` when any Kimi access method is available
|
|
59
|
+
*/
|
|
60
|
+
canSpawn(): Promise<boolean>;
|
|
61
|
+
/**
|
|
62
|
+
* Spawn a subagent via the Moonshot AI Kimi API.
|
|
63
|
+
*
|
|
64
|
+
* Enriches the prompt with CANT context (best-effort), then calls
|
|
65
|
+
* the Moonshot Chat Completions API. The call is awaited to completion.
|
|
66
|
+
*
|
|
67
|
+
* @param context - Spawn context with taskId, prompt, and options
|
|
68
|
+
* @returns Resolved spawn result with `status: 'completed'` or `'failed'`
|
|
69
|
+
*/
|
|
70
|
+
spawn(context: SpawnContext): Promise<SpawnResult>;
|
|
71
|
+
/**
|
|
72
|
+
* List currently in-flight Kimi API calls.
|
|
73
|
+
*
|
|
74
|
+
* Because each `spawn()` call awaits the API response, this list is
|
|
75
|
+
* typically empty unless concurrent spawns are in flight.
|
|
76
|
+
*
|
|
77
|
+
* @returns Array of in-progress spawn results
|
|
78
|
+
*/
|
|
79
|
+
listRunning(): Promise<SpawnResult[]>;
|
|
80
|
+
/**
|
|
81
|
+
* Remove an instance from the running-instances tracking map.
|
|
82
|
+
*
|
|
83
|
+
* The underlying fetch call cannot be cancelled externally once started.
|
|
84
|
+
* This method removes the entry so it will no longer appear in
|
|
85
|
+
* `listRunning()`, but does not abort the in-progress HTTP request.
|
|
86
|
+
*
|
|
87
|
+
* @param instanceId - ID of the spawn instance to terminate
|
|
88
|
+
*/
|
|
89
|
+
terminate(instanceId: string): Promise<void>;
|
|
90
|
+
}
|
|
91
|
+
//# sourceMappingURL=spawn.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"spawn.d.ts","sourceRoot":"","sources":["../../../src/providers/kimi/spawn.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;GA2BG;AAIH,OAAO,KAAK,EAAE,oBAAoB,EAAE,YAAY,EAAE,WAAW,EAAE,MAAM,qBAAqB,CAAC;AA8D3F;;;;;;;;;;;;;;;;;GAiBG;AACH,qBAAa,iBAAkB,YAAW,oBAAoB;IAC5D,kCAAkC;IAClC,OAAO,CAAC,QAAQ,CAAC,gBAAgB,CAAiC;IAElE;;;;;;;;OAQG;IACG,QAAQ,IAAI,OAAO,CAAC,OAAO,CAAC;IAYlC;;;;;;;;OAQG;IACG,KAAK,CAAC,OAAO,EAAE,YAAY,GAAG,OAAO,CAAC,WAAW,CAAC;IAkGxD;;;;;;;OAOG;IACG,WAAW,IAAI,OAAO,CAAC,WAAW,EAAE,CAAC;IAU3C;;;;;;;;OAQG;IACG,SAAS,CAAC,UAAU,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;CAGnD"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@cleocode/adapters",
|
|
3
|
-
"version": "2026.4.
|
|
3
|
+
"version": "2026.4.68",
|
|
4
4
|
"description": "Unified provider adapters for CLEO (Claude Code, OpenCode, Cursor)",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "dist/index.js",
|
|
@@ -14,8 +14,8 @@
|
|
|
14
14
|
"dependencies": {
|
|
15
15
|
"@anthropic-ai/claude-agent-sdk": "0.2.108",
|
|
16
16
|
"@openai/agents": "0.8.3",
|
|
17
|
-
"@cleocode/caamp": "2026.4.
|
|
18
|
-
"@cleocode/contracts": "2026.4.
|
|
17
|
+
"@cleocode/caamp": "2026.4.68",
|
|
18
|
+
"@cleocode/contracts": "2026.4.68"
|
|
19
19
|
},
|
|
20
20
|
"license": "MIT",
|
|
21
21
|
"engines": {
|
|
@@ -13,6 +13,7 @@ import { CodexAdapter } from './adapter.js';
|
|
|
13
13
|
export { CodexAdapter } from './adapter.js';
|
|
14
14
|
export { CodexHookProvider } from './hooks.js';
|
|
15
15
|
export { CodexInstallProvider } from './install.js';
|
|
16
|
+
export { CodexSpawnProvider } from './spawn.js';
|
|
16
17
|
|
|
17
18
|
export default CodexAdapter;
|
|
18
19
|
|
|
@@ -0,0 +1,224 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Codex CLI Spawn Provider
|
|
3
|
+
*
|
|
4
|
+
* Implements `AdapterSpawnProvider` for the OpenAI Codex CLI (`codex` binary).
|
|
5
|
+
*
|
|
6
|
+
* The `codex` binary is the OpenAI Codex CLI agent, available at:
|
|
7
|
+
* https://github.com/openai/codex
|
|
8
|
+
*
|
|
9
|
+
* Invocation: `codex --full-auto <prompt-file>`
|
|
10
|
+
*
|
|
11
|
+
* The provider uses `--full-auto` (non-interactive, auto-approve all actions)
|
|
12
|
+
* which is the headless equivalent of the Claude Code `--dangerously-skip-permissions`
|
|
13
|
+
* flag. Processes run detached and are tracked by PID for listing and termination.
|
|
14
|
+
*
|
|
15
|
+
* If the `codex` binary is not found, `canSpawn()` returns `false` with a
|
|
16
|
+
* graceful error — no crash.
|
|
17
|
+
*
|
|
18
|
+
* @remarks
|
|
19
|
+
* As of 2026, the Codex CLI is the successor to the original OpenAI Codex
|
|
20
|
+
* playground. It reads prompts from stdin or file arguments and emits output
|
|
21
|
+
* to stdout. The `--full-auto` flag suppresses interactive approval prompts.
|
|
22
|
+
* Install: `npm install -g @openai/codex` or see the GitHub repo above.
|
|
23
|
+
*
|
|
24
|
+
* @task T648
|
|
25
|
+
*/
|
|
26
|
+
|
|
27
|
+
import { exec, spawn as nodeSpawn } from 'node:child_process';
|
|
28
|
+
import { unlink, writeFile } from 'node:fs/promises';
|
|
29
|
+
import { promisify } from 'node:util';
|
|
30
|
+
import type { AdapterSpawnProvider, SpawnContext, SpawnResult } from '@cleocode/contracts';
|
|
31
|
+
import { getErrorMessage } from '@cleocode/contracts';
|
|
32
|
+
|
|
33
|
+
const execAsync = promisify(exec);
|
|
34
|
+
|
|
35
|
+
/** Internal tracking entry for a spawned process. */
|
|
36
|
+
interface TrackedProcess {
|
|
37
|
+
pid: number;
|
|
38
|
+
taskId: string;
|
|
39
|
+
startTime: string;
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
/**
|
|
43
|
+
* Spawn provider for the OpenAI Codex CLI.
|
|
44
|
+
*
|
|
45
|
+
* Spawns detached Codex CLI processes for subagent execution. Each spawn
|
|
46
|
+
* writes its prompt to a temporary file, then runs
|
|
47
|
+
* `codex --full-auto <tmpFile>` as a detached, unref'd child process.
|
|
48
|
+
*
|
|
49
|
+
* @remarks
|
|
50
|
+
* `canSpawn()` returns `false` (with no crash) when the `codex` binary is
|
|
51
|
+
* not found in PATH. Install instructions are emitted via `console.warn`
|
|
52
|
+
* once to help operators discover the binary is missing.
|
|
53
|
+
*
|
|
54
|
+
* Processes are tracked by instance ID in an in-memory map and verified
|
|
55
|
+
* via `kill(pid, 0)` liveness checks.
|
|
56
|
+
*
|
|
57
|
+
* @task T648
|
|
58
|
+
*/
|
|
59
|
+
export class CodexSpawnProvider implements AdapterSpawnProvider {
|
|
60
|
+
/** Map of instance IDs to tracked process info. */
|
|
61
|
+
private processMap = new Map<string, TrackedProcess>();
|
|
62
|
+
|
|
63
|
+
/**
|
|
64
|
+
* Check if the Codex CLI is available in PATH.
|
|
65
|
+
*
|
|
66
|
+
* @returns `true` if `codex` is found via `which`
|
|
67
|
+
*/
|
|
68
|
+
async canSpawn(): Promise<boolean> {
|
|
69
|
+
try {
|
|
70
|
+
await execAsync('which codex');
|
|
71
|
+
return true;
|
|
72
|
+
} catch {
|
|
73
|
+
console.warn(
|
|
74
|
+
'[CodexSpawnProvider] codex CLI not found. ' +
|
|
75
|
+
'Install: npm install -g @openai/codex ' +
|
|
76
|
+
'Docs: https://github.com/openai/codex',
|
|
77
|
+
);
|
|
78
|
+
return false;
|
|
79
|
+
}
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
/**
|
|
83
|
+
* Spawn a subagent via the Codex CLI.
|
|
84
|
+
*
|
|
85
|
+
* Writes the prompt to a temporary file and spawns a detached Codex
|
|
86
|
+
* process. The process runs independently of the parent.
|
|
87
|
+
*
|
|
88
|
+
* @param context - Spawn context with taskId, prompt, and options
|
|
89
|
+
* @returns Spawn result with instance ID and status
|
|
90
|
+
*/
|
|
91
|
+
async spawn(context: SpawnContext): Promise<SpawnResult> {
|
|
92
|
+
const instanceId = `codex-${Date.now()}-${Math.random().toString(36).substring(2, 9)}`;
|
|
93
|
+
const startTime = new Date().toISOString();
|
|
94
|
+
let tmpFile: string | undefined;
|
|
95
|
+
|
|
96
|
+
try {
|
|
97
|
+
// Enrich prompt with CANT bundle, memory bridge, and mental model.
|
|
98
|
+
// Best-effort: if CANT context is unavailable, the raw prompt is used.
|
|
99
|
+
let enrichedPrompt = context.prompt;
|
|
100
|
+
try {
|
|
101
|
+
const { buildCantEnrichedPrompt } = await import('../../cant-context.js');
|
|
102
|
+
enrichedPrompt = await buildCantEnrichedPrompt({
|
|
103
|
+
projectDir: context.workingDirectory ?? process.cwd(),
|
|
104
|
+
basePrompt: context.prompt,
|
|
105
|
+
agentName: (context.options?.agentName as string) ?? undefined,
|
|
106
|
+
});
|
|
107
|
+
} catch {
|
|
108
|
+
// CANT enrichment unavailable — use raw prompt
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
tmpFile = `/tmp/codex-spawn-${instanceId}.txt`;
|
|
112
|
+
await writeFile(tmpFile, enrichedPrompt, 'utf-8');
|
|
113
|
+
|
|
114
|
+
// --full-auto: non-interactive batch mode (auto-approve all actions)
|
|
115
|
+
const args = ['--full-auto', tmpFile];
|
|
116
|
+
const spawnOpts: Parameters<typeof nodeSpawn>[2] = {
|
|
117
|
+
detached: true,
|
|
118
|
+
stdio: 'ignore',
|
|
119
|
+
};
|
|
120
|
+
|
|
121
|
+
if (context.workingDirectory) {
|
|
122
|
+
spawnOpts.cwd = context.workingDirectory;
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
const child = nodeSpawn('codex', args, spawnOpts);
|
|
126
|
+
child.unref();
|
|
127
|
+
|
|
128
|
+
if (child.pid) {
|
|
129
|
+
this.processMap.set(instanceId, {
|
|
130
|
+
pid: child.pid,
|
|
131
|
+
taskId: context.taskId,
|
|
132
|
+
startTime,
|
|
133
|
+
});
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
const capturedTmpFile = tmpFile;
|
|
137
|
+
child.on('exit', async () => {
|
|
138
|
+
this.processMap.delete(instanceId);
|
|
139
|
+
try {
|
|
140
|
+
await unlink(capturedTmpFile);
|
|
141
|
+
} catch {
|
|
142
|
+
// Ignore cleanup errors
|
|
143
|
+
}
|
|
144
|
+
});
|
|
145
|
+
|
|
146
|
+
return {
|
|
147
|
+
instanceId,
|
|
148
|
+
taskId: context.taskId,
|
|
149
|
+
providerId: 'codex',
|
|
150
|
+
status: 'running',
|
|
151
|
+
startTime,
|
|
152
|
+
};
|
|
153
|
+
} catch (error) {
|
|
154
|
+
console.error(`[CodexSpawnProvider] Failed to spawn: ${getErrorMessage(error)}`);
|
|
155
|
+
|
|
156
|
+
if (tmpFile) {
|
|
157
|
+
try {
|
|
158
|
+
await unlink(tmpFile);
|
|
159
|
+
} catch {
|
|
160
|
+
// Ignore cleanup errors
|
|
161
|
+
}
|
|
162
|
+
}
|
|
163
|
+
|
|
164
|
+
return {
|
|
165
|
+
instanceId,
|
|
166
|
+
taskId: context.taskId,
|
|
167
|
+
providerId: 'codex',
|
|
168
|
+
status: 'failed',
|
|
169
|
+
startTime,
|
|
170
|
+
endTime: new Date().toISOString(),
|
|
171
|
+
error: getErrorMessage(error),
|
|
172
|
+
};
|
|
173
|
+
}
|
|
174
|
+
}
|
|
175
|
+
|
|
176
|
+
/**
|
|
177
|
+
* List currently running Codex subagent processes.
|
|
178
|
+
*
|
|
179
|
+
* Checks each tracked process via kill(pid, 0) to verify it is still alive.
|
|
180
|
+
* Dead processes are automatically cleaned from the tracking map.
|
|
181
|
+
*
|
|
182
|
+
* @returns Array of spawn results for running processes
|
|
183
|
+
*/
|
|
184
|
+
async listRunning(): Promise<SpawnResult[]> {
|
|
185
|
+
const running: SpawnResult[] = [];
|
|
186
|
+
|
|
187
|
+
for (const [instanceId, tracked] of this.processMap.entries()) {
|
|
188
|
+
try {
|
|
189
|
+
process.kill(tracked.pid, 0);
|
|
190
|
+
running.push({
|
|
191
|
+
instanceId,
|
|
192
|
+
taskId: tracked.taskId,
|
|
193
|
+
providerId: 'codex',
|
|
194
|
+
status: 'running',
|
|
195
|
+
startTime: tracked.startTime,
|
|
196
|
+
});
|
|
197
|
+
} catch {
|
|
198
|
+
this.processMap.delete(instanceId);
|
|
199
|
+
}
|
|
200
|
+
}
|
|
201
|
+
|
|
202
|
+
return running;
|
|
203
|
+
}
|
|
204
|
+
|
|
205
|
+
/**
|
|
206
|
+
* Terminate a running spawn by instance ID.
|
|
207
|
+
*
|
|
208
|
+
* Sends SIGTERM to the tracked process. If the process is not found
|
|
209
|
+
* or has already exited, this is a no-op.
|
|
210
|
+
*
|
|
211
|
+
* @param instanceId - ID of the spawn instance to terminate
|
|
212
|
+
*/
|
|
213
|
+
async terminate(instanceId: string): Promise<void> {
|
|
214
|
+
const tracked = this.processMap.get(instanceId);
|
|
215
|
+
if (!tracked) return;
|
|
216
|
+
|
|
217
|
+
try {
|
|
218
|
+
process.kill(tracked.pid, 'SIGTERM');
|
|
219
|
+
} catch {
|
|
220
|
+
// Process may have already exited
|
|
221
|
+
}
|
|
222
|
+
this.processMap.delete(instanceId);
|
|
223
|
+
}
|
|
224
|
+
}
|
|
@@ -13,6 +13,7 @@ import { GeminiCliAdapter } from './adapter.js';
|
|
|
13
13
|
export { GeminiCliAdapter } from './adapter.js';
|
|
14
14
|
export { GeminiCliHookProvider } from './hooks.js';
|
|
15
15
|
export { GeminiCliInstallProvider } from './install.js';
|
|
16
|
+
export { GeminiCliSpawnProvider } from './spawn.js';
|
|
16
17
|
|
|
17
18
|
export default GeminiCliAdapter;
|
|
18
19
|
|