@excitedjs/agent-runtime-claude-code 0.2.0-alpha.g0ddd418597ca

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (67) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +32 -0
  3. package/dist/args.d.ts +71 -0
  4. package/dist/args.d.ts.map +1 -0
  5. package/dist/args.js +87 -0
  6. package/dist/args.js.map +1 -0
  7. package/dist/config.d.ts +71 -0
  8. package/dist/config.d.ts.map +1 -0
  9. package/dist/config.js +86 -0
  10. package/dist/config.js.map +1 -0
  11. package/dist/diagnostic.d.ts +12 -0
  12. package/dist/diagnostic.d.ts.map +1 -0
  13. package/dist/diagnostic.js +25 -0
  14. package/dist/diagnostic.js.map +1 -0
  15. package/dist/index.d.ts +18 -0
  16. package/dist/index.d.ts.map +1 -0
  17. package/dist/index.js +18 -0
  18. package/dist/index.js.map +1 -0
  19. package/dist/internal/completion-body.d.ts +38 -0
  20. package/dist/internal/completion-body.d.ts.map +1 -0
  21. package/dist/internal/completion-body.js +62 -0
  22. package/dist/internal/completion-body.js.map +1 -0
  23. package/dist/internal/config-validate.d.ts +23 -0
  24. package/dist/internal/config-validate.d.ts.map +1 -0
  25. package/dist/internal/config-validate.js +122 -0
  26. package/dist/internal/config-validate.js.map +1 -0
  27. package/dist/internal/os.d.ts +30 -0
  28. package/dist/internal/os.d.ts.map +1 -0
  29. package/dist/internal/os.js +81 -0
  30. package/dist/internal/os.js.map +1 -0
  31. package/dist/internal/turn-render.d.ts +22 -0
  32. package/dist/internal/turn-render.d.ts.map +1 -0
  33. package/dist/internal/turn-render.js +40 -0
  34. package/dist/internal/turn-render.js.map +1 -0
  35. package/dist/mcp-config.d.ts +19 -0
  36. package/dist/mcp-config.d.ts.map +1 -0
  37. package/dist/mcp-config.js +22 -0
  38. package/dist/mcp-config.js.map +1 -0
  39. package/dist/provider-ref.d.ts +8 -0
  40. package/dist/provider-ref.d.ts.map +1 -0
  41. package/dist/provider-ref.js +8 -0
  42. package/dist/provider-ref.js.map +1 -0
  43. package/dist/provider.d.ts +60 -0
  44. package/dist/provider.d.ts.map +1 -0
  45. package/dist/provider.js +110 -0
  46. package/dist/provider.js.map +1 -0
  47. package/dist/rpc.d.ts +45 -0
  48. package/dist/rpc.d.ts.map +1 -0
  49. package/dist/rpc.js +212 -0
  50. package/dist/rpc.js.map +1 -0
  51. package/dist/runtime.d.ts +174 -0
  52. package/dist/runtime.d.ts.map +1 -0
  53. package/dist/runtime.js +464 -0
  54. package/dist/runtime.js.map +1 -0
  55. package/dist/stream.d.ts +96 -0
  56. package/dist/stream.d.ts.map +1 -0
  57. package/dist/stream.js +289 -0
  58. package/dist/stream.js.map +1 -0
  59. package/dist/supervisor.d.ts +17 -0
  60. package/dist/supervisor.d.ts.map +1 -0
  61. package/dist/supervisor.js +170 -0
  62. package/dist/supervisor.js.map +1 -0
  63. package/dist/types.d.ts +133 -0
  64. package/dist/types.d.ts.map +1 -0
  65. package/dist/types.js +7 -0
  66. package/dist/types.js.map +1 -0
  67. package/package.json +53 -0
package/dist/rpc.js ADDED
@@ -0,0 +1,212 @@
1
+ /**
2
+ * Claude Code stream-json turn RPC.
3
+ *
4
+ * The supervisor owns the child process. This class owns one in-flight turn,
5
+ * stdout line demux, turn aggregation, and defensive control-request replies.
6
+ */
7
+ import { randomUUID } from 'node:crypto';
8
+ import { buildCanUseToolAllow, buildControlAck, buildRemoteControlEnable, buildUserMessage, LineBuffer, parseLine, TurnAggregator, } from './stream.js';
9
+ export class ClaudeCodeStreamRpc {
10
+ stdin;
11
+ options;
12
+ lineBuf = new LineBuffer();
13
+ pending = null;
14
+ remoteControlRequestId = null;
15
+ constructor(stdin, options) {
16
+ this.stdin = stdin;
17
+ this.options = options;
18
+ }
19
+ async submitTurn(prompt, options = {}) {
20
+ if (!this.stdin.writable) {
21
+ return Promise.reject(new Error('claude resident child is not running'));
22
+ }
23
+ if (this.pending !== null) {
24
+ return Promise.reject(new Error('claude resident session is already mid-turn'));
25
+ }
26
+ return new Promise((resolve, reject) => {
27
+ const pending = {
28
+ resolve,
29
+ reject,
30
+ aggregator: new TurnAggregator(),
31
+ timer: null,
32
+ settleImmediate: null,
33
+ steered: false,
34
+ deferredOutcome: null,
35
+ };
36
+ this.pending = pending;
37
+ // Arm the idle deadline (reset on every inbound stream line in `onLine`).
38
+ this.armIdleTimer(pending);
39
+ this.stdin.write(`${buildUserMessage(prompt, options)}\n`, (err) => {
40
+ if (err != null && this.pending === pending) {
41
+ this.settlePending()?.reject(err instanceof Error ? err : new Error(String(err)));
42
+ }
43
+ });
44
+ });
45
+ }
46
+ async steerTurn(prompt, options = {}) {
47
+ if (!this.stdin.writable) {
48
+ return Promise.reject(new Error('claude resident child is not running'));
49
+ }
50
+ if (this.pending === null) {
51
+ return Promise.reject(new Error('claude resident session has no active turn'));
52
+ }
53
+ const pending = this.pending;
54
+ pending.steered = true;
55
+ return new Promise((resolve, reject) => {
56
+ this.stdin.write(`${buildUserMessage(prompt, { priority: 'now', ...options })}\n`, (err) => {
57
+ if (err != null) {
58
+ reject(err instanceof Error ? err : new Error(String(err)));
59
+ return;
60
+ }
61
+ resolve();
62
+ });
63
+ });
64
+ }
65
+ onStdoutChunk(chunk) {
66
+ for (const line of this.lineBuf.push(chunk))
67
+ this.onLine(parseLine(line));
68
+ }
69
+ failPending(err) {
70
+ this.settlePending()?.reject(err);
71
+ }
72
+ enableRemoteControl() {
73
+ if (!this.stdin.writable)
74
+ return;
75
+ this.remoteControlRequestId = randomUUID();
76
+ this.stdin.write(`${buildRemoteControlEnable(this.remoteControlRequestId)}\n`);
77
+ }
78
+ /**
79
+ * Detach the in-flight turn: clear its deadline timer and null `pending`,
80
+ * returning it so the caller can resolve or reject it exactly once.
81
+ */
82
+ settlePending() {
83
+ const pending = this.pending;
84
+ if (pending === null)
85
+ return null;
86
+ if (pending.timer !== null)
87
+ clearTimeout(pending.timer);
88
+ if (pending.settleImmediate !== null)
89
+ clearImmediate(pending.settleImmediate);
90
+ this.pending = null;
91
+ return pending;
92
+ }
93
+ /**
94
+ * (Re)arm the per-turn idle deadline. `turnTimeoutMs` is a *max-idle* window,
95
+ * not a total-turn cap: any inbound stream line for this turn pushes it out
96
+ * (see `onLine`). A genuinely wedged child (no stream activity for the whole
97
+ * window) is still reaped — preserving the #120 anti-hang intent — but a long
98
+ * but continuously-streaming turn never trips the deadline (#156).
99
+ */
100
+ armIdleTimer(pending) {
101
+ if (pending.timer !== null)
102
+ clearTimeout(pending.timer);
103
+ pending.timer = setTimeout(() => {
104
+ if (this.pending !== pending)
105
+ return;
106
+ this.pending = null;
107
+ this.options.log?.('error', `claude turn stalled: no stream activity for ${this.options.turnTimeoutMs}ms; reaping resident child`);
108
+ pending.reject(new Error(`claude resident turn stalled: no stream activity for ${this.options.turnTimeoutMs}ms`));
109
+ this.options.reapOnTimeout();
110
+ }, this.options.turnTimeoutMs);
111
+ }
112
+ onLine(line) {
113
+ // Idle-timeout reset: any inbound stream line for the pending turn is
114
+ // activity, so push the deadline out. The terminal `result` clears the
115
+ // timer via `settlePending` below.
116
+ if (this.pending !== null)
117
+ this.armIdleTimer(this.pending);
118
+ switch (line.kind) {
119
+ case 'init':
120
+ case 'assistant':
121
+ this.pending?.aggregator.accept(line);
122
+ break;
123
+ case 'result': {
124
+ if (this.pending === null)
125
+ break;
126
+ this.pending.aggregator.accept(line);
127
+ const outcome = this.pending.aggregator.outcome();
128
+ if (this.pending.steered) {
129
+ this.deferSteeredResult(this.pending, outcome);
130
+ break;
131
+ }
132
+ const pending = this.settlePending();
133
+ if (pending === null)
134
+ break;
135
+ if (outcome !== null)
136
+ pending.resolve(outcome);
137
+ else
138
+ pending.reject(new Error('claude turn ended without a result'));
139
+ break;
140
+ }
141
+ case 'control_request':
142
+ this.onControlRequest(line.requestId, line.subtype, line.request);
143
+ break;
144
+ case 'control_response':
145
+ this.onControlResponse(line.requestId, line.ok, line.response, line.error);
146
+ break;
147
+ case 'parse_error':
148
+ this.options.log?.('warn', `claude stream-json parse error: ${line.raw}`);
149
+ break;
150
+ default:
151
+ break;
152
+ }
153
+ }
154
+ deferSteeredResult(pending, outcome) {
155
+ pending.deferredOutcome = outcome;
156
+ if (pending.settleImmediate !== null)
157
+ return;
158
+ // A stream-json `priority` steer can cause Claude Code to close the
159
+ // interrupted run and immediately drain the queued steer in the same stdout
160
+ // flush. Resolve on the next tick so those follow-up lines are still folded
161
+ // into this one Dreamux logical turn instead of becoming a silent late result.
162
+ pending.settleImmediate = setImmediate(() => {
163
+ if (this.pending !== pending)
164
+ return;
165
+ const finalOutcome = pending.deferredOutcome;
166
+ const settled = this.settlePending();
167
+ if (settled === null)
168
+ return;
169
+ if (finalOutcome !== null)
170
+ settled.resolve(finalOutcome);
171
+ else
172
+ settled.reject(new Error('claude turn ended without a result'));
173
+ });
174
+ }
175
+ onControlRequest(requestId, subtype, request) {
176
+ if (requestId === null || !this.stdin.writable)
177
+ return;
178
+ // Unattended posture: answer permission callbacks so a turn never wedges
179
+ // waiting on a human.
180
+ let reply;
181
+ if (subtype === 'can_use_tool') {
182
+ const rawInput = request['input'];
183
+ const input = typeof rawInput === 'object' &&
184
+ rawInput !== null &&
185
+ !Array.isArray(rawInput)
186
+ ? rawInput
187
+ : {};
188
+ reply = buildCanUseToolAllow(requestId, input);
189
+ }
190
+ else {
191
+ reply = buildControlAck(requestId);
192
+ }
193
+ this.stdin.write(`${reply}\n`);
194
+ }
195
+ onControlResponse(requestId, ok, response, error) {
196
+ if (requestId === null || requestId !== this.remoteControlRequestId)
197
+ return;
198
+ this.remoteControlRequestId = null;
199
+ if (ok && response !== null) {
200
+ const url = response['session_url'] ?? response['connect_url'];
201
+ if (typeof url === 'string') {
202
+ this.options.onRemoteControlUrl?.(url);
203
+ }
204
+ else {
205
+ this.options.log?.('warn', 'claude remote control enable succeeded without a URL');
206
+ }
207
+ return;
208
+ }
209
+ this.options.log?.('warn', `claude remote control enable failed${error !== null ? `: ${error}` : ''}`);
210
+ }
211
+ }
212
+ //# sourceMappingURL=rpc.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"rpc.js","sourceRoot":"","sources":["../src/rpc.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,174 @@
1
+ /**
2
+ * `builtin:claude-code` AgentRuntime (issue #110 PR6, resident stream-json
3
+ * transport since issue #120; extracted into `@excitedjs/agent-runtime-claude-code`
4
+ * in issue #209).
5
+ *
6
+ * A real second agent runtime that proves the AgentRuntimeProvider abstraction
7
+ * is not "Codex renamed". Like Codex it runs a **resident child process**
8
+ * supervised for the runtime's lifetime — but it differs in every
9
+ * runtime-specific dimension:
10
+ *
11
+ * - **Stream-json over stdio, not an app-server WebSocket.** The resident child
12
+ * is `claude --print --input-format stream-json --output-format stream-json`
13
+ * (see `./args.ts`); turns are NDJSON `user` lines on stdin and
14
+ * `init`/`assistant`/`result` envelopes on stdout (see `./stream.ts`). There
15
+ * is no `initialize` handshake — the child emits `init` lazily with the first
16
+ * turn — so readiness is "child spawned", not "handshake completed".
17
+ * - **MCP injection is a JSON config document** (`--mcp-config <file>`), not
18
+ * Codex's `-c mcp_servers.*` TOML CLI flags.
19
+ * - **Runtime-owned config** is `DispatcherClaudeCodeConfig` (bin / model /
20
+ * permission_mode / remote_control / extra_args / extra_env), distinct from
21
+ * the Codex config.
22
+ * - **Completion delivery** is a plain user turn (no fake task-notification),
23
+ * not the Codex inbox-then-trigger path.
24
+ *
25
+ * Process spawning goes through an injectable {@link ClaudeCodeSessionFactory}
26
+ * seam (mirroring Codex's process-factory seam), so the lifecycle contract is
27
+ * fully unit-testable with a fake session. A live `claude` binary is exercised
28
+ * only by the opt-in live test.
29
+ *
30
+ * Failure contract (unchanged by #120): a turn failure (spawn error, child
31
+ * exit, error `result`) is never swallowed. For inbound/restart turns it drives
32
+ * the runtime to `degraded` with a persisted `last_error` (observable via
33
+ * status/doctor). For `completionInput` it surfaces as a `failed`
34
+ * result the caller can act on (PR8 delivery retry). `channelInput` still
35
+ * returns after accept (submit != completion) so the channel can ack promptly.
36
+ *
37
+ * Restart: an unexpected child exit marks the runtime `degraded`; the next turn
38
+ * re-spawns the resident child with `--resume <session_id>`, restoring the
39
+ * conversation. There is no background backoff timer — re-spawn is lazy and
40
+ * bound to the (serialized) turn queue, so it stays deterministic.
41
+ *
42
+ * Per-turn idle deadline: a turn whose still-alive child goes silent — never
43
+ * emitting another stream line (a stall, or a wait on input the runtime cannot
44
+ * satisfy) — would otherwise pend forever and wedge the serial queue, and behind
45
+ * it TeamMate completion delivery, which awaits this runtime. `turn_timeout_ms`
46
+ * is a *max-idle* window (issue #156): it is reset on every inbound stream line,
47
+ * so a long but continuously-streaming turn (e.g. a deep audit running many
48
+ * tool calls for far longer than the window) is never reaped, while a child that
49
+ * emits nothing for the whole window still is — turning an infinite hang into a
50
+ * normal degraded + `last_error` (inbound) or `failed` delivery result.
51
+ *
52
+ * Reference: the resident stream-json protocol model and process-supervision
53
+ * shape are adapted from the Claudemux `next` implementation; the AgentRuntime /
54
+ * Channel / DispatcherService boundaries (provider seam, runtime-owned MCP
55
+ * injection, degraded/last_error status, TeamMate delivery result contract) are
56
+ * Dreamux's own, per `.agents/decisions/agent-runtime-provider.md`.
57
+ */
58
+ import type { DispatcherClaudeCodeConfig } from './config.js';
59
+ import { type ClaudeCodeSessionFactory } from './supervisor.js';
60
+ import type { AgentRuntimeCapabilities, AgentRuntime, AgentRuntimeIdentity, AgentRuntimeLastResult, AgentRuntimeMcpServer, AgentRuntimePathContext, AgentRuntimeResumeInput, AgentRuntimeSkillSource, AgentRuntimeStateCallbacks, AgentRuntimeStatus, AgentRuntimeSystemInput, AgentRuntimeTurnResult, CompletionEnvelope, DreamuxLogger, InboundDeliveryHooks, InboundTurnInput, TeamMateCompletionDeliveryResult, TurnSettledSignal } from '@excitedjs/dreamux-types';
61
+ /**
62
+ * Everything the Claude Code runtime needs, assembled by the provider from the
63
+ * neutral create context plus host-supplied hooks. The host contracts the
64
+ * package must not reconstruct — the per-dispatcher path context, the durable
65
+ * state sink, and the base process env (`PATH` seeded with the host package
66
+ * bins) — arrive here; nothing references a Dreamux host module.
67
+ */
68
+ export interface ClaudeCodeRuntimeDeps {
69
+ /** Provider-parsed Claude Code runtime config. */
70
+ config: DispatcherClaudeCodeConfig;
71
+ /** Working directory the resident `claude` child runs in. */
72
+ cwd: string;
73
+ /** Neutral state sink for status/thread transitions. */
74
+ state: AgentRuntimeStateCallbacks;
75
+ /** Neutral path context: the runtime derives its mcp-config / log subpaths here. */
76
+ paths: AgentRuntimePathContext;
77
+ /** MCP server descriptors translated into the `--mcp-config` JSON document. */
78
+ mcpServers: readonly AgentRuntimeMcpServer[];
79
+ /** Resident-session factory (tests inject a fake). */
80
+ sessionFactory: ClaudeCodeSessionFactory;
81
+ /** Host-level bin resolver (default: identity on the config bin). */
82
+ resolveBinPath: (bin: string) => string;
83
+ /**
84
+ * The host's neutral env-injection entries from the create context, merged
85
+ * into the resident child env before this provider's own `extra_env`.
86
+ * Empty/omitted means inject nothing (the common case).
87
+ */
88
+ injectEnv?: Record<string, string>;
89
+ /**
90
+ * Launcher-supplied role/system-prompt content, applied as an APPEND via
91
+ * `--append-system-prompt`. Omitted for launches that supply none (teammates).
92
+ */
93
+ systemPromptContent?: string;
94
+ /**
95
+ * Role-gated skill sources core selected (issue #209 slice 6). The
96
+ * add-dir-compatible ones become `--add-dir` flags on every (re)spawn.
97
+ */
98
+ skillSources?: readonly AgentRuntimeSkillSource[];
99
+ /** Fired each time a delivered turn reaches a terminal state. */
100
+ onTurnSettled?: (settled: TurnSettledSignal) => void;
101
+ /** Structured logger; falls back to a minimal `console.error` sink. */
102
+ logger?: DreamuxLogger;
103
+ }
104
+ /**
105
+ * The Claude Code agent runtime for one dispatcher. A single resident
106
+ * stream-json child serves every turn. Turns run serially (one at a time) and
107
+ * `channelInput` returns after the message is accepted — not after the turn
108
+ * completes — matching the Codex runtime's submit-then-serialize contract.
109
+ */
110
+ export declare class ClaudeCodeRuntime implements AgentRuntime {
111
+ private readonly deps;
112
+ readonly providerRef = "builtin:claude-code";
113
+ private readonly dispatcherId;
114
+ private readonly config;
115
+ private readonly bin;
116
+ private readonly cwd;
117
+ private readonly mcpConfigPath;
118
+ private readonly mcpConfigDoc;
119
+ private readonly stderrLogPath;
120
+ private readonly completionSpillDir;
121
+ private readonly logger;
122
+ private status;
123
+ private threadId;
124
+ private resumed;
125
+ private stopped;
126
+ private readonly seen;
127
+ private queue;
128
+ private readonly runtimeInstanceId;
129
+ private turnCounter;
130
+ private session;
131
+ private lastResult;
132
+ private activeChannelTurn;
133
+ constructor(identity: AgentRuntimeIdentity, deps: ClaudeCodeRuntimeDeps);
134
+ getStatus(): AgentRuntimeStatus;
135
+ getCapabilities(): AgentRuntimeCapabilities;
136
+ getThreadId(): string | null;
137
+ wasThreadResumed(): boolean;
138
+ getLast(): Promise<AgentRuntimeLastResult | null>;
139
+ getContext(): Promise<null>;
140
+ resume(input?: AgentRuntimeResumeInput): Promise<void>;
141
+ start(): Promise<void>;
142
+ stop(): Promise<void>;
143
+ systemInput(notice: AgentRuntimeSystemInput): Promise<AgentRuntimeTurnResult>;
144
+ channelInput(input: InboundTurnInput, hooks?: InboundDeliveryHooks): Promise<AgentRuntimeTurnResult>;
145
+ completionInput(completion: CompletionEnvelope): Promise<TeamMateCompletionDeliveryResult>;
146
+ /**
147
+ * Chain a turn onto the serial queue. Returns a promise that resolves when
148
+ * this turn completes and rejects when it fails, so awaiting callers (delivery)
149
+ * see the real outcome. The queue itself continues regardless of outcome so a
150
+ * failed turn does not wedge later turns.
151
+ */
152
+ private runTurnOnQueue;
153
+ private runChannelTurnOnQueue;
154
+ private runChannelTurn;
155
+ private steerChannelTurn;
156
+ private markTurnSucceeded;
157
+ private markTurnFailed;
158
+ /**
159
+ * Ensure a live resident session exists, spawning (or re-spawning after an
160
+ * unexpected exit) as needed. Re-spawn resumes the persisted session id so the
161
+ * conversation survives a crash.
162
+ */
163
+ private ensureSession;
164
+ /** React to an unexpected resident-child exit: degrade and drop the session. */
165
+ private onSessionExit;
166
+ private runTurn;
167
+ private runTurnWithSession;
168
+ private applyTurnOutcome;
169
+ private nextTurnId;
170
+ private buildProcessEnv;
171
+ private setStatus;
172
+ private log;
173
+ }
174
+ //# sourceMappingURL=runtime.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"runtime.d.ts","sourceRoot":"","sources":["../src/runtime.ts"],"names":[],"mappings":"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"}