@kodizm/acp 0.5.7 → 0.6.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.
- package/README.md +29 -33
- package/dist/index.js +57390 -30946
- package/package.json +22 -7
package/README.md
CHANGED
|
@@ -1,12 +1,12 @@
|
|
|
1
1
|
# kodizm-acp
|
|
2
2
|
|
|
3
|
-
ACP bridge that drives Claude Code
|
|
3
|
+
ACP bridge that drives the Claude Code and opencode CLIs through one canonical wire.
|
|
4
4
|
|
|
5
5
|
## What it is
|
|
6
6
|
|
|
7
7
|
`@kodizm/acp` is the Kodizm runtime's Agent Client Protocol bridge. It speaks one canonical JSON-RPC surface to the orchestrator, then translates each turn down to whichever CLI backend the session was opened against. The orchestrator never branches on backend; the same `session/new`, `session/prompt`, and `sessionUpdate` shapes carry every feature across all three.
|
|
8
8
|
|
|
9
|
-
|
|
9
|
+
Two CLIs are supported: Claude Code (via `@anthropic-ai/claude-agent-sdk`) as the primary backend, and opencode (via `createOpencodeServer` from `@opencode-ai/sdk`) as the secondary one.
|
|
10
10
|
|
|
11
11
|
## How it works
|
|
12
12
|
|
|
@@ -25,27 +25,27 @@ The driver contract is a single TypeScript interface with seven methods. The ser
|
|
|
25
25
|
|
|
26
26
|
## Backend support
|
|
27
27
|
|
|
28
|
-
| Feature | Claude |
|
|
29
|
-
|
|
30
|
-
| `session/new`, `session/prompt`, `session/cancel` | yes | yes |
|
|
31
|
-
| `session/load` (resume) | yes | yes |
|
|
32
|
-
| `session/fork` | yes | yes |
|
|
33
|
-
| `session/compact` (manual) | yes | yes |
|
|
34
|
-
| Image content blocks | yes | yes |
|
|
35
|
-
| Token + cost rollup (`usage` event) | yes | yes |
|
|
36
|
-
| `additionalDirectories` (sandbox) | yes |
|
|
37
|
-
| `mcpServers` injection | yes | yes |
|
|
38
|
-
| `systemPrompt` replace + append | yes | yes |
|
|
39
|
-
| `skills` pre-load | yes | n/a |
|
|
40
|
-
| Permissions (`permission_request`) | yes | yes |
|
|
41
|
-
| `askUserQuestion` | yes | yes |
|
|
42
|
-
| Subagent events | yes | yes |
|
|
43
|
-
| Thinking events | yes | yes |
|
|
44
|
-
| Cross-process Pattern B resume | yes | yes |
|
|
45
|
-
| Debug capture | yes | yes |
|
|
28
|
+
| Feature | Claude | opencode |
|
|
29
|
+
|---------|:------:|:--------:|
|
|
30
|
+
| `session/new`, `session/prompt`, `session/cancel` | yes | yes |
|
|
31
|
+
| `session/load` (resume) | yes | yes |
|
|
32
|
+
| `session/fork` | yes | yes |
|
|
33
|
+
| `session/compact` (manual) | yes | yes |
|
|
34
|
+
| Image content blocks | yes | yes |
|
|
35
|
+
| Token + cost rollup (`usage` event) | yes | yes |
|
|
36
|
+
| `additionalDirectories` (sandbox) | yes | n/a |
|
|
37
|
+
| `mcpServers` injection | yes | yes |
|
|
38
|
+
| `systemPrompt` replace + append | yes | yes |
|
|
39
|
+
| `skills` pre-load | yes | n/a |
|
|
40
|
+
| Permissions (`permission_request`) | yes | yes |
|
|
41
|
+
| `askUserQuestion` | yes | yes |
|
|
42
|
+
| Subagent events | yes | yes |
|
|
43
|
+
| Thinking events | yes | yes |
|
|
44
|
+
| Cross-process Pattern B resume | yes | yes |
|
|
45
|
+
| Debug capture | yes | yes |
|
|
46
46
|
|
|
47
47
|
> [!NOTE]
|
|
48
|
-
> The published bin (`kodizm-acp` from `dist/index.js`)
|
|
48
|
+
> The published bin (`kodizm-acp` from `dist/index.js`) wires both backends: set `KODIZM_BACKEND` to `claude` or `opencode` and the bin resolves the matching driver itself.
|
|
49
49
|
|
|
50
50
|
## Install
|
|
51
51
|
|
|
@@ -53,7 +53,7 @@ The driver contract is a single TypeScript interface with seven methods. The ser
|
|
|
53
53
|
bun add @kodizm/acp
|
|
54
54
|
```
|
|
55
55
|
|
|
56
|
-
Requires Bun >= 1.1.0. The `
|
|
56
|
+
Requires Bun >= 1.1.0. The `opencode` CLI must be installed separately when you use that backend.
|
|
57
57
|
|
|
58
58
|
## Quick start
|
|
59
59
|
|
|
@@ -75,17 +75,16 @@ Replace the credential pair with `ANTHROPIC_API_KEY=...` for the api-key path.
|
|
|
75
75
|
|
|
76
76
|
| Variable | Required | Description |
|
|
77
77
|
|----------|:--------:|-------------|
|
|
78
|
-
| `KODIZM_BACKEND` | yes | `claude` / `
|
|
78
|
+
| `KODIZM_BACKEND` | yes | `claude` / `opencode` |
|
|
79
79
|
| `CLAUDE_CODE_OAUTH_TOKEN` + `CLAUDE_CODE_REMOTE=1` | claude (sub) | Subscription auth |
|
|
80
80
|
| `ANTHROPIC_API_KEY` | claude (api) | API key auth |
|
|
81
81
|
| `CLAUDE_CODE_PATH` | optional | Path to claude binary (default `/usr/local/bin/claude`) |
|
|
82
|
-
| `OPENAI_API_KEY` or `CODEX_API_KEY` | codex (api) | api-key path. Without it, codex falls back to chatgpt-mode auth in `~/.codex/auth.json` |
|
|
83
82
|
| `OPENCODE_AUTH_CONTENT` | opencode (env) | JSON keyed by providerID. Layered onto subprocess env for the bridge lifetime only. Without it, opencode reads `~/.local/share/opencode/auth.json` |
|
|
84
83
|
| `KODIZM_LOG_LEVEL` | optional | `debug` / `info` / `warn` / `error`. Default `info` |
|
|
85
84
|
| `KODIZM_DEBUG` | optional | `1` enables process-wide debug capture |
|
|
86
85
|
| `KODIZM_DEBUG_DIR` | optional | Forensic JSONL dir, default `/tmp/kodizm-debug` |
|
|
87
86
|
| `KODIZM_DEBUG_RAW_SECRETS` | incident-only | `1` disables redaction. Never set in production |
|
|
88
|
-
| `KODIZM_ACP_FORWARD_STDERR` | optional | `1` tees
|
|
87
|
+
| `KODIZM_ACP_FORWARD_STDERR` | optional | `1` tees a spawned backend subprocess's stderr to parent stderr |
|
|
89
88
|
|
|
90
89
|
Stdout is reserved for ACP frames. Logs go to stderr.
|
|
91
90
|
|
|
@@ -117,7 +116,7 @@ type NewSessionRequest = {
|
|
|
117
116
|
> `permissionTimeoutMs` and `permissionDeferTimeoutMs` are mutually exclusive. Pick hard-deny on timeout OR soft-defer on timeout, not both. The schema rejects the conflict with a clear error.
|
|
118
117
|
|
|
119
118
|
> [!NOTE]
|
|
120
|
-
> `settingSources` is the claude-only opt-out for filesystem config layering. When omitted the SDK's own default fires, matching the standalone Claude Code CLI: project `CLAUDE.md` + `.claude/CLAUDE.md` + `.claude/rules/*.md` load from `cwd` walking up; user `~/.claude/CLAUDE.md` + `~/.claude/rules/*.md` and `CLAUDE.local.md` load too. Pass `[]` to disable every fs scope; pass a selective subset like `['project']` to load only project-tracked files.
|
|
119
|
+
> `settingSources` is the claude-only opt-out for filesystem config layering. When omitted the SDK's own default fires, matching the standalone Claude Code CLI: project `CLAUDE.md` + `.claude/CLAUDE.md` + `.claude/rules/*.md` load from `cwd` walking up; user `~/.claude/CLAUDE.md` + `~/.claude/rules/*.md` and `CLAUDE.local.md` load too. Pass `[]` to disable every fs scope; pass a selective subset like `['project']` to load only project-tracked files. Opencode (`AGENTS.md` / `CLAUDE.md` / `CONTEXT.md` from session `directory`) has no parallel field and ignores this option.
|
|
121
120
|
|
|
122
121
|
### Tool policy
|
|
123
122
|
|
|
@@ -143,7 +142,7 @@ type McpServer = {
|
|
|
143
142
|
}
|
|
144
143
|
```
|
|
145
144
|
|
|
146
|
-
|
|
145
|
+
The `http` transport ships today. Opencode adds servers via `sdk.mcp.add` per session.
|
|
147
146
|
|
|
148
147
|
## API reference
|
|
149
148
|
|
|
@@ -183,7 +182,7 @@ The bin (`src/index.ts`) is the only public surface. Importers get the runtime h
|
|
|
183
182
|
|
|
184
183
|
| Export | Purpose |
|
|
185
184
|
|--------|---------|
|
|
186
|
-
| `SupportedBackend` | `'claude' \| '
|
|
185
|
+
| `SupportedBackend` | `'claude' \| 'opencode'` |
|
|
187
186
|
| `BackendNotConfiguredError`, `UnknownBackendError` | startup-time errors |
|
|
188
187
|
| `resolveBackendFromEnv(env)` | parse `KODIZM_BACKEND` from a captured env |
|
|
189
188
|
| `installShutdownHook()` | wire SIGTERM + SIGINT to graceful shutdown |
|
|
@@ -217,7 +216,7 @@ const server = createAcpServer({
|
|
|
217
216
|
await server.serve()
|
|
218
217
|
```
|
|
219
218
|
|
|
220
|
-
The `
|
|
219
|
+
The `opencode` driver follows the same shape; it takes no spawn factory, since the SDK helper handles the subprocess.
|
|
221
220
|
|
|
222
221
|
## Wire reference
|
|
223
222
|
|
|
@@ -251,7 +250,7 @@ The `SessionUpdateEvent` discriminated union has 21 variants:
|
|
|
251
250
|
| `subagent_spawn` / `subagent_complete` | nested agent lifecycle |
|
|
252
251
|
| `skill_activation` | a skill loaded mid-turn (claude only) |
|
|
253
252
|
| `model_advertisement` | the actual model the backend chose |
|
|
254
|
-
| `process_died` | subprocess crash (
|
|
253
|
+
| `process_died` | subprocess crash (opencode) |
|
|
255
254
|
| `cancelled` | turn was cancelled |
|
|
256
255
|
| `compaction_started` / `compaction_completed` | context compaction; `trigger: 'manual' \| 'auto'` |
|
|
257
256
|
| `debug_log` | one of 10 stages: `rpc.in`, `rpc.out`, `sdk.message`, `sdk.error`, `tool.permission_request`, `tool.permission_response`, `session.config`, `driver.state_change`, `transport.spawn`, `transport.exit` |
|
|
@@ -265,8 +264,6 @@ The `SessionUpdateEvent` discriminated union has 21 variants:
|
|
|
265
264
|
| `sessionUpdate` | every event above flows as a notification |
|
|
266
265
|
| `session/request_permission` | orchestrator decides on a `permission_request` |
|
|
267
266
|
| `session/ask_user_question` | orchestrator answers a `question_request` |
|
|
268
|
-
| `session/dynamic_tool_call` | codex orchestrator-hosted tool dispatch |
|
|
269
|
-
| `session/codex_chatgpt_token_refresh` | codex chatgpt-mode token rotation |
|
|
270
267
|
| `session/permission_deferred_persist` | Pattern B write fallback when no `deferredStore` |
|
|
271
268
|
| `session/permission_deferred_state` | Pattern B read fallback when no `deferredStore` |
|
|
272
269
|
|
|
@@ -277,7 +274,6 @@ The permission and ask-question RPC names have legacy aliases (`requestPermissio
|
|
|
277
274
|
A driver instance can resume a session that an earlier process started. Useful when a container restart, deploy, or crash interrupts an active turn.
|
|
278
275
|
|
|
279
276
|
- **claude**: standard `session/load` against the SDK's resume mode; the JSONL transcript on disk is authoritative.
|
|
280
|
-
- **codex**: `CodexDriver.hydrateSession({ sessionId, codexThreadId, ... })` replays codex's `thread/resume` against the persisted threadId.
|
|
281
277
|
- **opencode**: `OpencodeDriver.loadSession({ sessionId, _meta: { opencodeSessionId } })`; opencode's SQLite persistence survives process death.
|
|
282
278
|
|
|
283
279
|
Deferred permissions (the orchestrator decided to "ask later" on a tool gate) are persisted via either an injected `DeferredPermissionStore` or the `session/permission_deferred_persist` outbound RPC. The next process picks up where the prior one left off and emits `permission_resumed`.
|