kitty-hive 0.6.12 → 0.7.2

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.
@@ -4,8 +4,70 @@
4
4
  *
5
5
  * Auth: only accept connections from 127.0.0.1 / ::1 / ::ffff:127.0.0.1 (loopback).
6
6
  */
7
+ import { homedir } from 'node:os';
8
+ import { join } from 'node:path';
9
+ import { existsSync, readdirSync, statSync } from 'node:fs';
7
10
  import * as db from './db.js';
8
11
  import { log } from './log.js';
12
+ import { getDaemonSnapshots, markDaemonReady, notifyAgentCreated, notifyAgentRemoved, requestDaemonRespawn } from './codex-supervisor.js';
13
+ // Per-agent serialization for /admin/codex-set-thread. Two concurrent
14
+ // callers must not both SIGTERM the daemon — the second would race against
15
+ // the supervisor's respawn from the first. A simple promise-chain per
16
+ // agent_id is enough; calls await the previous chain head before starting.
17
+ const setThreadLocks = new Map();
18
+ function lockPerAgent(agentId, fn) {
19
+ const prev = setThreadLocks.get(agentId) ?? Promise.resolve();
20
+ const next = prev.catch(() => undefined).then(fn);
21
+ setThreadLocks.set(agentId, next);
22
+ // Cleanup map entry once this call settles AND no later call has chained
23
+ // onto it (we re-check identity before deleting).
24
+ next.finally(() => {
25
+ if (setThreadLocks.get(agentId) === next)
26
+ setThreadLocks.delete(agentId);
27
+ });
28
+ return next;
29
+ }
30
+ /** Locate the codex rollout jsonl for a given thread_id. Codex stores them
31
+ * under `~/.codex/sessions/YYYY/MM/DD/rollout-<ts>-<thread_id>.jsonl`. We
32
+ * don't know the date directory, so this walks `~/.codex/sessions/` looking
33
+ * for any file whose name ends in `-<thread_id>.jsonl`. Returns true if
34
+ * found. Used to validate set_thread requests so callers can't pin to a
35
+ * non-existent thread (which would otherwise fall through to thread/start
36
+ * and silently overwrite the intended thread_id). */
37
+ function codexRolloutExists(threadId) {
38
+ const base = join(homedir(), '.codex', 'sessions');
39
+ if (!existsSync(base))
40
+ return false;
41
+ const needle = `-${threadId}.jsonl`;
42
+ function scan(dir) {
43
+ let entries;
44
+ try {
45
+ entries = readdirSync(dir);
46
+ }
47
+ catch {
48
+ return false;
49
+ }
50
+ for (const e of entries) {
51
+ const full = join(dir, e);
52
+ let st;
53
+ try {
54
+ st = statSync(full);
55
+ }
56
+ catch {
57
+ continue;
58
+ }
59
+ if (st.isDirectory()) {
60
+ if (scan(full))
61
+ return true;
62
+ }
63
+ else if (e.endsWith(needle)) {
64
+ return true;
65
+ }
66
+ }
67
+ return false;
68
+ }
69
+ return scan(base);
70
+ }
9
71
  function isLoopback(req) {
10
72
  const addr = req.socket.remoteAddress || '';
11
73
  return addr === '127.0.0.1' || addr === '::1' || addr === '::ffff:127.0.0.1';
@@ -81,6 +143,210 @@ export async function handleAdmin(req, res, url) {
81
143
  res.end(JSON.stringify({ url }));
82
144
  return;
83
145
  }
146
+ // GET /admin/codex-daemons — snapshot of the codex daemon supervisor
147
+ if (url.pathname === '/admin/codex-daemons' && req.method === 'GET') {
148
+ res.writeHead(200, { 'Content-Type': 'application/json' });
149
+ res.end(JSON.stringify({ daemons: getDaemonSnapshots() }));
150
+ return;
151
+ }
152
+ // POST /admin/notify-agent-created — the CLI `agent register` calls this
153
+ // after it writes a new agent row, so the codex-supervisor (in serve's
154
+ // process) can dynamically spawn a daemon for new tool=codex agents without
155
+ // requiring a serve restart. The in-process onAgentCreated hook only fires
156
+ // when register goes through the live serve via MCP; this endpoint bridges
157
+ // the CLI-direct-DB-write path.
158
+ if (url.pathname === '/admin/notify-agent-created' && req.method === 'POST') {
159
+ try {
160
+ const body = JSON.parse(await readBody(req));
161
+ const { agent_id } = body;
162
+ if (typeof agent_id !== 'string') {
163
+ res.writeHead(400, { 'Content-Type': 'application/json' });
164
+ res.end(JSON.stringify({ error: 'agent_id (string) required' }));
165
+ return;
166
+ }
167
+ const spawned = notifyAgentCreated(agent_id);
168
+ res.writeHead(200, { 'Content-Type': 'application/json' });
169
+ res.end(JSON.stringify({ ok: true, spawned }));
170
+ }
171
+ catch (err) {
172
+ res.writeHead(500, { 'Content-Type': 'application/json' });
173
+ res.end(JSON.stringify({ error: String(err?.message || err) }));
174
+ }
175
+ return;
176
+ }
177
+ // POST /admin/notify-agent-removed — the CLI `agent remove` calls this
178
+ // after deleting an agent row so the codex-supervisor can kill the daemon
179
+ // (and its codex app-server + ws) right away. Without this, a removed
180
+ // agent leaves a ghost daemon running on the old ws_url, causing routing
181
+ // schisms when a new agent later self-registers with the same name. See
182
+ // Bug 1 reported on 2026-05-20.
183
+ if (url.pathname === '/admin/notify-agent-removed' && req.method === 'POST') {
184
+ try {
185
+ const body = JSON.parse(await readBody(req));
186
+ const { agent_id } = body;
187
+ if (typeof agent_id !== 'string') {
188
+ res.writeHead(400, { 'Content-Type': 'application/json' });
189
+ res.end(JSON.stringify({ error: 'agent_id (string) required' }));
190
+ return;
191
+ }
192
+ const killed = notifyAgentRemoved(agent_id);
193
+ res.writeHead(200, { 'Content-Type': 'application/json' });
194
+ res.end(JSON.stringify({ ok: true, killed }));
195
+ }
196
+ catch (err) {
197
+ res.writeHead(500, { 'Content-Type': 'application/json' });
198
+ res.end(JSON.stringify({ error: String(err?.message || err) }));
199
+ }
200
+ return;
201
+ }
202
+ // POST /admin/codex-daemon-ready — daemon announces (ws_url, thread_id) after
203
+ // its codex app-server is up. Lets external callers (kitty-kitty) discover
204
+ // where to point `codex --remote` to see the same thread the daemon is
205
+ // injecting into.
206
+ if (url.pathname === '/admin/codex-daemon-ready' && req.method === 'POST') {
207
+ try {
208
+ const body = JSON.parse(await readBody(req));
209
+ const { agent_id, ws_url, thread_id } = body;
210
+ if (typeof agent_id !== 'string' || typeof ws_url !== 'string' || typeof thread_id !== 'string') {
211
+ res.writeHead(400, { 'Content-Type': 'application/json' });
212
+ res.end(JSON.stringify({ error: 'agent_id, ws_url, thread_id all required (strings)' }));
213
+ return;
214
+ }
215
+ const ok = markDaemonReady(agent_id, ws_url, thread_id);
216
+ if (!ok) {
217
+ // Daemon wasn't in the supervisor's map — could be a manually-started
218
+ // codex-channel (not via supervisor). Accept the POST silently with a
219
+ // soft warning; admin endpoint is loopback-only so it's safe.
220
+ log('warn', `[admin] codex-daemon-ready for unknown agent_id=${agent_id}; not tracked by supervisor`);
221
+ res.writeHead(202, { 'Content-Type': 'application/json' });
222
+ res.end(JSON.stringify({ ok: false, tracked: false }));
223
+ return;
224
+ }
225
+ res.writeHead(200, { 'Content-Type': 'application/json' });
226
+ res.end(JSON.stringify({ ok: true, tracked: true }));
227
+ }
228
+ catch (err) {
229
+ res.writeHead(500, { 'Content-Type': 'application/json' });
230
+ res.end(JSON.stringify({ error: String(err?.message || err) }));
231
+ }
232
+ return;
233
+ }
234
+ // POST /admin/codex-set-thread — switch the daemon for a codex agent to a
235
+ // specific thread (resume) or to a fresh thread (reset).
236
+ //
237
+ // body: { agent_id: string, thread_id: string | null }
238
+ // thread_id non-empty string → resume that thread. jsonl must exist on
239
+ // disk in ~/.codex/sessions/.
240
+ // thread_id === null or "" → reset: clear agents.thread_id and let the
241
+ // daemon thread/start a new thread.
242
+ // thread_id field missing → 400 (use null explicitly to reset; prevents
243
+ // accidental reset from a serialization bug).
244
+ //
245
+ // Implementation:
246
+ // 1. UPDATE agents.thread_id (or '' for reset)
247
+ // 2. SIGTERM existing daemon (supervisor auto-respawns) OR spawn fresh if
248
+ // none exists. requestDaemonRespawn() handles both.
249
+ // 3. Wait up to 30s for the new daemon to report ready (which means it
250
+ // successfully resumed/started a thread and POSTed to
251
+ // /admin/codex-daemon-ready).
252
+ //
253
+ // Returns: { ok, thread_id, ws_url, ready, error? }
254
+ // thread_id is the ACTUAL one the new daemon now holds (matches the
255
+ // request on resume; on reset it's the codex-assigned new id).
256
+ // ws_url is the new daemon's ws://127.0.0.1:<port>; differs from any
257
+ // previous value if the daemon respawned with a new free port.
258
+ //
259
+ // Use cases (kitty UI):
260
+ // - User picks a historical thread from a session picker → resume
261
+ // - User clicks "🆕 new conversation" → reset
262
+ //
263
+ // Serialized per agent_id so two concurrent callers can't race the
264
+ // SIGTERM/respawn flow.
265
+ if (url.pathname === '/admin/codex-set-thread' && req.method === 'POST') {
266
+ try {
267
+ const body = JSON.parse(await readBody(req));
268
+ const { agent_id } = body;
269
+ if (typeof agent_id !== 'string' || !agent_id) {
270
+ res.writeHead(400, { 'Content-Type': 'application/json' });
271
+ res.end(JSON.stringify({ error: 'agent_id (string) required' }));
272
+ return;
273
+ }
274
+ // thread_id MUST be present. Accept string | null. A missing field is
275
+ // a 400 — never want a JSON-serialization bug (e.g. undefined dropped
276
+ // by JSON.stringify) to silently nuke an agent's thread.
277
+ if (!('thread_id' in body)) {
278
+ res.writeHead(400, { 'Content-Type': 'application/json' });
279
+ res.end(JSON.stringify({ error: 'thread_id required (pass null explicitly to reset)' }));
280
+ return;
281
+ }
282
+ const rawThreadId = body.thread_id;
283
+ if (rawThreadId !== null && typeof rawThreadId !== 'string') {
284
+ res.writeHead(400, { 'Content-Type': 'application/json' });
285
+ res.end(JSON.stringify({ error: 'thread_id must be string or null' }));
286
+ return;
287
+ }
288
+ const targetThreadId = (rawThreadId ?? '').trim(); // '' means reset
289
+ const agent = db.getAgentById(agent_id);
290
+ if (!agent) {
291
+ res.writeHead(404, { 'Content-Type': 'application/json' });
292
+ res.end(JSON.stringify({ error: `agent not found: ${agent_id}` }));
293
+ return;
294
+ }
295
+ if (agent.tool !== 'codex') {
296
+ res.writeHead(400, { 'Content-Type': 'application/json' });
297
+ res.end(JSON.stringify({ error: `agent.tool="${agent.tool}", expected "codex"` }));
298
+ return;
299
+ }
300
+ if (agent.origin_peer !== '') {
301
+ res.writeHead(400, { 'Content-Type': 'application/json' });
302
+ res.end(JSON.stringify({ error: 'cannot set thread for a remote (federated) agent' }));
303
+ return;
304
+ }
305
+ // For resume: verify the jsonl exists. If we just blindly trust the
306
+ // caller and the file is missing, the daemon's thread/resume will
307
+ // fail and fall back to thread/start — overwriting the intended
308
+ // thread_id with a fresh one (and from the caller's perspective the
309
+ // pin silently failed).
310
+ if (targetThreadId && !codexRolloutExists(targetThreadId)) {
311
+ res.writeHead(400, { 'Content-Type': 'application/json' });
312
+ res.end(JSON.stringify({
313
+ error: `no codex rollout jsonl found for thread_id=${targetThreadId} under ~/.codex/sessions/`,
314
+ }));
315
+ return;
316
+ }
317
+ // Serialize per-agent so concurrent set_thread calls don't trample
318
+ // each other's SIGTERM / respawn flow.
319
+ const result = await lockPerAgent(agent_id, async () => {
320
+ db.setAgentThreadId(agent_id, targetThreadId);
321
+ log('info', `[admin] codex-set-thread agent=${agent_id.slice(-12)} → ${targetThreadId || '(reset)'}`);
322
+ const snap = await requestDaemonRespawn(agent_id, 30_000);
323
+ return snap;
324
+ });
325
+ if (!result) {
326
+ res.writeHead(200, { 'Content-Type': 'application/json' });
327
+ res.end(JSON.stringify({
328
+ ok: false,
329
+ thread_id: targetThreadId || null,
330
+ ws_url: null,
331
+ ready: false,
332
+ error: 'daemon did not become ready within 30s; poll hive_codex_pane_ws or GET /admin/codex-daemons',
333
+ }));
334
+ return;
335
+ }
336
+ res.writeHead(200, { 'Content-Type': 'application/json' });
337
+ res.end(JSON.stringify({
338
+ ok: true,
339
+ thread_id: result.thread_id,
340
+ ws_url: result.ws_url,
341
+ ready: true,
342
+ }));
343
+ }
344
+ catch (err) {
345
+ res.writeHead(500, { 'Content-Type': 'application/json' });
346
+ res.end(JSON.stringify({ error: String(err?.message || err) }));
347
+ }
348
+ return;
349
+ }
84
350
  res.writeHead(404, { 'Content-Type': 'application/json' });
85
351
  res.end(JSON.stringify({ error: 'Unknown admin endpoint' }));
86
352
  }
@@ -1 +1 @@
1
- {"version":3,"file":"admin-http.js","sourceRoot":"","sources":["../src/admin-http.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"admin-http.js","sourceRoot":"","sources":["../src/admin-http.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,126 @@
1
+ /**
2
+ * codex-channel-runtime — the testable core of codex-channel.ts.
3
+ *
4
+ * Encapsulates everything that talks to a codex app-server's JSON-RPC v2
5
+ * protocol (https://github.com/openai/codex 0.124+): issuing `turn/start`,
6
+ * tracking in-flight turns by their server-assigned turn id, and reacting to
7
+ * `turn/completed` / `turn/interrupt` / `error` notifications.
8
+ *
9
+ * The 2026-05-26 monkeys-tester incident exposed two bugs in the previous
10
+ * implementation that this module replaces:
11
+ *
12
+ * 1. **FIFO waiter mismatch.** sendTurn pushed a bare `resolve` onto an
13
+ * array; the WS handler shifted from the front on any `turn/completed`.
14
+ * A timeout left orphan resolvers behind, so later `turn/completed`s
15
+ * woke the wrong waiter — cascading misroutes silently failed all
16
+ * subsequent turns.
17
+ *
18
+ * 2. **Retry-after-turn/start duplication.** When the daemon's wait for
19
+ * `turn/completed` timed out at 10 min, the old retry loop issued a
20
+ * fresh `turn/start` — but codex had already created the turn and
21
+ * written the input text into the thread. Each retry produced another
22
+ * duplicate turn. Affected agent saw the same DM 2-3× in their codex
23
+ * thread, sometimes more.
24
+ *
25
+ * Design:
26
+ *
27
+ * - One `TurnTracker` instance per daemon, owns a `Map<turnId, Waiter>`
28
+ * keyed by the turn id from `turn/start` response. WS notifications are
29
+ * routed by `turnId` (or `turn.id`) — no FIFO assumption.
30
+ *
31
+ * - `sendTurn(text)` returns a `TurnOutcome` discriminated-union. Callers
32
+ * branch on `outcome.kind` instead of catching errors. The kind is one of
33
+ * `completed | failed | interrupted | timeout | rpc_send_error |
34
+ * skipped_duplicate`. This makes the "do not retry on timeout" rule
35
+ * explicit in the type rather than relying on caller discipline.
36
+ *
37
+ * - `sendTurn(text, {eventId})` dedups by `eventId`. Once a turn/start has
38
+ * been issued for an eventId (whether successful, timeout, or anything
39
+ * else short of a pre-send error), the tracker refuses to issue another
40
+ * turn/start for the same eventId in this process lifetime. Conservative
41
+ * trade-off: prefer losing one event over duplicating it. Hive's SSE
42
+ * replay/pending_pushes can recover lost events; nothing recovers a
43
+ * duplicated turn from a user's codex thread.
44
+ */
45
+ export interface CodexTurn {
46
+ id: string;
47
+ status?: string;
48
+ [k: string]: unknown;
49
+ }
50
+ export interface TurnStartResponse {
51
+ turn: CodexTurn;
52
+ }
53
+ export interface ErrorNotificationParams {
54
+ error: unknown;
55
+ threadId: string;
56
+ turnId: string;
57
+ willRetry: boolean;
58
+ }
59
+ export type TurnOutcome = {
60
+ kind: 'completed';
61
+ turnId: string;
62
+ turn: CodexTurn;
63
+ } | {
64
+ kind: 'failed';
65
+ turnId: string;
66
+ willRetry: boolean;
67
+ error: unknown;
68
+ } | {
69
+ kind: 'interrupted';
70
+ turnId: string;
71
+ turn?: CodexTurn;
72
+ } | {
73
+ kind: 'timeout';
74
+ turnId: string;
75
+ afterMs: number;
76
+ } | {
77
+ kind: 'rpc_send_error';
78
+ error: Error;
79
+ } | {
80
+ kind: 'skipped_duplicate';
81
+ eventId: string;
82
+ };
83
+ /** Adapter so the tracker can stay agnostic about whether the underlying
84
+ * transport is a real WebSocket (codex-channel.ts) or a stub (tests). */
85
+ export interface RpcTransport {
86
+ /** Send a JSON-RPC request and resolve to its `result`. Reject with Error
87
+ * on network failure, RPC-level error, or timeout. */
88
+ call(method: string, params: unknown, timeoutMs?: number): Promise<unknown>;
89
+ }
90
+ export interface TurnTrackerOptions {
91
+ /** How long to wait for `turn/completed` after `turn/start` succeeds.
92
+ * Default 10 min — matches codex's typical long-running turn budget. */
93
+ turnTimeoutMs?: number;
94
+ /** Hook for tests / observability. Called once per terminal outcome. */
95
+ onOutcome?: (outcome: TurnOutcome, eventId?: string) => void;
96
+ }
97
+ export declare class TurnTracker {
98
+ private readonly transport;
99
+ private readonly threadId;
100
+ private waiters;
101
+ private injectedEventIds;
102
+ private readonly turnTimeoutMs;
103
+ private readonly onOutcome?;
104
+ constructor(transport: RpcTransport, threadId: string, opts?: TurnTrackerOptions);
105
+ /** Issue `turn/start` and resolve when codex reports the turn's terminal
106
+ * state. Never throws — failure modes are encoded in the returned
107
+ * `TurnOutcome.kind` so callers can branch declaratively. */
108
+ sendTurn(text: string, opts?: {
109
+ eventId?: string;
110
+ }): Promise<TurnOutcome>;
111
+ /** Route a codex JSON-RPC notification (anything that isn't an RPC response
112
+ * to a request the daemon issued). The caller — typically the WS message
113
+ * handler — should invoke this for every parsed notification. Returns
114
+ * true if the notification matched a waiter, false otherwise (useful for
115
+ * diagnostic logging). */
116
+ handleNotification(method: string, params: unknown): boolean;
117
+ /** Diagnostic snapshot of in-flight turns. Not used at runtime; exposed
118
+ * for the optional `/admin/codex-daemons` extension and tests. */
119
+ snapshot(): {
120
+ activeTurns: string[];
121
+ injectedEventIds: number;
122
+ };
123
+ /** Test-only: drop all pending waiters (no resolution). Use to simulate
124
+ * daemon shutdown for cleanup tests. */
125
+ destroyForTest(): void;
126
+ }
@@ -0,0 +1,203 @@
1
+ /**
2
+ * codex-channel-runtime — the testable core of codex-channel.ts.
3
+ *
4
+ * Encapsulates everything that talks to a codex app-server's JSON-RPC v2
5
+ * protocol (https://github.com/openai/codex 0.124+): issuing `turn/start`,
6
+ * tracking in-flight turns by their server-assigned turn id, and reacting to
7
+ * `turn/completed` / `turn/interrupt` / `error` notifications.
8
+ *
9
+ * The 2026-05-26 monkeys-tester incident exposed two bugs in the previous
10
+ * implementation that this module replaces:
11
+ *
12
+ * 1. **FIFO waiter mismatch.** sendTurn pushed a bare `resolve` onto an
13
+ * array; the WS handler shifted from the front on any `turn/completed`.
14
+ * A timeout left orphan resolvers behind, so later `turn/completed`s
15
+ * woke the wrong waiter — cascading misroutes silently failed all
16
+ * subsequent turns.
17
+ *
18
+ * 2. **Retry-after-turn/start duplication.** When the daemon's wait for
19
+ * `turn/completed` timed out at 10 min, the old retry loop issued a
20
+ * fresh `turn/start` — but codex had already created the turn and
21
+ * written the input text into the thread. Each retry produced another
22
+ * duplicate turn. Affected agent saw the same DM 2-3× in their codex
23
+ * thread, sometimes more.
24
+ *
25
+ * Design:
26
+ *
27
+ * - One `TurnTracker` instance per daemon, owns a `Map<turnId, Waiter>`
28
+ * keyed by the turn id from `turn/start` response. WS notifications are
29
+ * routed by `turnId` (or `turn.id`) — no FIFO assumption.
30
+ *
31
+ * - `sendTurn(text)` returns a `TurnOutcome` discriminated-union. Callers
32
+ * branch on `outcome.kind` instead of catching errors. The kind is one of
33
+ * `completed | failed | interrupted | timeout | rpc_send_error |
34
+ * skipped_duplicate`. This makes the "do not retry on timeout" rule
35
+ * explicit in the type rather than relying on caller discipline.
36
+ *
37
+ * - `sendTurn(text, {eventId})` dedups by `eventId`. Once a turn/start has
38
+ * been issued for an eventId (whether successful, timeout, or anything
39
+ * else short of a pre-send error), the tracker refuses to issue another
40
+ * turn/start for the same eventId in this process lifetime. Conservative
41
+ * trade-off: prefer losing one event over duplicating it. Hive's SSE
42
+ * replay/pending_pushes can recover lost events; nothing recovers a
43
+ * duplicated turn from a user's codex thread.
44
+ */
45
+ export class TurnTracker {
46
+ transport;
47
+ threadId;
48
+ waiters = new Map();
49
+ injectedEventIds = new Set();
50
+ turnTimeoutMs;
51
+ onOutcome;
52
+ constructor(transport, threadId, opts = {}) {
53
+ this.transport = transport;
54
+ this.threadId = threadId;
55
+ this.turnTimeoutMs = opts.turnTimeoutMs ?? 600_000;
56
+ this.onOutcome = opts.onOutcome;
57
+ }
58
+ /** Issue `turn/start` and resolve when codex reports the turn's terminal
59
+ * state. Never throws — failure modes are encoded in the returned
60
+ * `TurnOutcome.kind` so callers can branch declaratively. */
61
+ async sendTurn(text, opts = {}) {
62
+ const { eventId } = opts;
63
+ // Idempotency: refuse to re-issue turn/start for an event we've already
64
+ // tried, regardless of how that prior attempt ended. Without this, a
65
+ // caller that catches an outcome.kind === 'timeout' and re-queues the
66
+ // event would re-trigger the original duplication bug — codex would
67
+ // create a second turn in the thread for the same logical hive event.
68
+ if (eventId && this.injectedEventIds.has(eventId)) {
69
+ const outcome = { kind: 'skipped_duplicate', eventId };
70
+ this.onOutcome?.(outcome, eventId);
71
+ return outcome;
72
+ }
73
+ if (eventId)
74
+ this.injectedEventIds.add(eventId);
75
+ let resp;
76
+ try {
77
+ resp = (await this.transport.call('turn/start', {
78
+ threadId: this.threadId,
79
+ input: [{ type: 'text', text }],
80
+ }));
81
+ }
82
+ catch (err) {
83
+ // Pre-RPC-response failure: TCP/WS error, or rpcCall timeout (codex
84
+ // didn't reply within rpcCall's own deadline — much shorter than the
85
+ // turn deadline). NOTE we still keep the eventId in injectedEventIds
86
+ // because we cannot prove codex didn't receive the start; resending
87
+ // the same eventId might create a duplicate turn there. Conservative
88
+ // by design.
89
+ const outcome = {
90
+ kind: 'rpc_send_error',
91
+ error: err instanceof Error ? err : new Error(String(err)),
92
+ };
93
+ this.onOutcome?.(outcome, eventId);
94
+ return outcome;
95
+ }
96
+ const turnId = resp?.turn?.id;
97
+ if (!turnId) {
98
+ const outcome = {
99
+ kind: 'rpc_send_error',
100
+ error: new Error(`turn/start response missing turn.id: ${JSON.stringify(resp)}`),
101
+ };
102
+ this.onOutcome?.(outcome, eventId);
103
+ return outcome;
104
+ }
105
+ // Register waiter keyed by turn id. Codex's notifications include turnId
106
+ // — we use that to route, not the FIFO order. Multiple concurrent turns
107
+ // on the same thread (rare for our use case but supported by codex) work
108
+ // correctly because each waiter is independently identified.
109
+ return new Promise((resolve) => {
110
+ const timer = setTimeout(() => {
111
+ // Codex never fired turn/completed within budget. The turn is still
112
+ // (possibly) in-flight on codex's side and the input text is in
113
+ // thread history. We do NOT re-issue turn/start. Caller drops the
114
+ // event; if codex eventually completes the turn, that completion
115
+ // notification will hit our handler with no waiter to resolve, and
116
+ // is safely ignored.
117
+ if (this.waiters.has(turnId)) {
118
+ this.waiters.delete(turnId);
119
+ const outcome = { kind: 'timeout', turnId, afterMs: this.turnTimeoutMs };
120
+ this.onOutcome?.(outcome, eventId);
121
+ resolve(outcome);
122
+ }
123
+ }, this.turnTimeoutMs);
124
+ this.waiters.set(turnId, {
125
+ turnId,
126
+ resolve: (outcome) => {
127
+ clearTimeout(timer);
128
+ this.waiters.delete(turnId);
129
+ this.onOutcome?.(outcome, eventId);
130
+ resolve(outcome);
131
+ },
132
+ timer,
133
+ });
134
+ });
135
+ }
136
+ /** Route a codex JSON-RPC notification (anything that isn't an RPC response
137
+ * to a request the daemon issued). The caller — typically the WS message
138
+ * handler — should invoke this for every parsed notification. Returns
139
+ * true if the notification matched a waiter, false otherwise (useful for
140
+ * diagnostic logging). */
141
+ handleNotification(method, params) {
142
+ if (method === 'turn/completed') {
143
+ const p = params;
144
+ const turnId = p?.turn?.id;
145
+ if (!turnId)
146
+ return false;
147
+ const w = this.waiters.get(turnId);
148
+ if (!w)
149
+ return false; // unknown turn (late completion after timeout etc.)
150
+ w.resolve({ kind: 'completed', turnId, turn: p.turn });
151
+ return true;
152
+ }
153
+ if (method === 'turn/interrupt') {
154
+ const p = params;
155
+ const turnId = p?.turn?.id;
156
+ if (!turnId)
157
+ return false;
158
+ const w = this.waiters.get(turnId);
159
+ if (!w)
160
+ return false;
161
+ w.resolve({ kind: 'interrupted', turnId, turn: p.turn });
162
+ return true;
163
+ }
164
+ if (method === 'error') {
165
+ const p = params;
166
+ const turnId = p?.turnId;
167
+ if (!turnId)
168
+ return false;
169
+ const w = this.waiters.get(turnId);
170
+ if (!w)
171
+ return false;
172
+ // willRetry === true means codex's own retry layer will try the turn
173
+ // again internally — leave the waiter pending and wait for the eventual
174
+ // completion / final error. Only resolve when willRetry is false.
175
+ if (p.willRetry === true)
176
+ return false;
177
+ w.resolve({
178
+ kind: 'failed',
179
+ turnId,
180
+ willRetry: !!p.willRetry,
181
+ error: p.error ?? null,
182
+ });
183
+ return true;
184
+ }
185
+ return false;
186
+ }
187
+ /** Diagnostic snapshot of in-flight turns. Not used at runtime; exposed
188
+ * for the optional `/admin/codex-daemons` extension and tests. */
189
+ snapshot() {
190
+ return {
191
+ activeTurns: [...this.waiters.keys()],
192
+ injectedEventIds: this.injectedEventIds.size,
193
+ };
194
+ }
195
+ /** Test-only: drop all pending waiters (no resolution). Use to simulate
196
+ * daemon shutdown for cleanup tests. */
197
+ destroyForTest() {
198
+ for (const w of this.waiters.values())
199
+ clearTimeout(w.timer);
200
+ this.waiters.clear();
201
+ }
202
+ }
203
+ //# sourceMappingURL=codex-channel-runtime.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"codex-channel-runtime.js","sourceRoot":"","sources":["../src/codex-channel-runtime.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA2CG;AAiDH,MAAM,OAAO,WAAW;IAOH;IACA;IAPX,OAAO,GAAG,IAAI,GAAG,EAAkB,CAAC;IACpC,gBAAgB,GAAG,IAAI,GAAG,EAAU,CAAC;IAC5B,aAAa,CAAS;IACtB,SAAS,CAAmC;IAE7D,YACmB,SAAuB,EACvB,QAAgB,EACjC,OAA2B,EAAE;QAFZ,cAAS,GAAT,SAAS,CAAc;QACvB,aAAQ,GAAR,QAAQ,CAAQ;QAGjC,IAAI,CAAC,aAAa,GAAG,IAAI,CAAC,aAAa,IAAI,OAAO,CAAC;QACnD,IAAI,CAAC,SAAS,GAAG,IAAI,CAAC,SAAS,CAAC;IAClC,CAAC;IAED;;kEAE8D;IAC9D,KAAK,CAAC,QAAQ,CAAC,IAAY,EAAE,OAA6B,EAAE;QAC1D,MAAM,EAAE,OAAO,EAAE,GAAG,IAAI,CAAC;QAEzB,wEAAwE;QACxE,qEAAqE;QACrE,sEAAsE;QACtE,oEAAoE;QACpE,sEAAsE;QACtE,IAAI,OAAO,IAAI,IAAI,CAAC,gBAAgB,CAAC,GAAG,CAAC,OAAO,CAAC,EAAE,CAAC;YAClD,MAAM,OAAO,GAAgB,EAAE,IAAI,EAAE,mBAAmB,EAAE,OAAO,EAAE,CAAC;YACpE,IAAI,CAAC,SAAS,EAAE,CAAC,OAAO,EAAE,OAAO,CAAC,CAAC;YACnC,OAAO,OAAO,CAAC;QACjB,CAAC;QACD,IAAI,OAAO;YAAE,IAAI,CAAC,gBAAgB,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC;QAEhD,IAAI,IAAuB,CAAC;QAC5B,IAAI,CAAC;YACH,IAAI,GAAG,CAAC,MAAM,IAAI,CAAC,SAAS,CAAC,IAAI,CAAC,YAAY,EAAE;gBAC9C,QAAQ,EAAE,IAAI,CAAC,QAAQ;gBACvB,KAAK,EAAE,CAAC,EAAE,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,CAAC;aAChC,CAAC,CAAsB,CAAC;QAC3B,CAAC;QAAC,OAAO,GAAG,EAAE,CAAC;YACb,oEAAoE;YACpE,qEAAqE;YACrE,qEAAqE;YACrE,oEAAoE;YACpE,qEAAqE;YACrE,aAAa;YACb,MAAM,OAAO,GAAgB;gBAC3B,IAAI,EAAE,gBAAgB;gBACtB,KAAK,EAAE,GAAG,YAAY,KAAK,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,IAAI,KAAK,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC;aAC3D,CAAC;YACF,IAAI,CAAC,SAAS,EAAE,CAAC,OAAO,EAAE,OAAO,CAAC,CAAC;YACnC,OAAO,OAAO,CAAC;QACjB,CAAC;QAED,MAAM,MAAM,GAAG,IAAI,EAAE,IAAI,EAAE,EAAE,CAAC;QAC9B,IAAI,CAAC,MAAM,EAAE,CAAC;YACZ,MAAM,OAAO,GAAgB;gBAC3B,IAAI,EAAE,gBAAgB;gBACtB,KAAK,EAAE,IAAI,KAAK,CAAC,wCAAwC,IAAI,CAAC,SAAS,CAAC,IAAI,CAAC,EAAE,CAAC;aACjF,CAAC;YACF,IAAI,CAAC,SAAS,EAAE,CAAC,OAAO,EAAE,OAAO,CAAC,CAAC;YACnC,OAAO,OAAO,CAAC;QACjB,CAAC;QAED,yEAAyE;QACzE,wEAAwE;QACxE,yEAAyE;QACzE,6DAA6D;QAC7D,OAAO,IAAI,OAAO,CAAc,CAAC,OAAO,EAAE,EAAE;YAC1C,MAAM,KAAK,GAAG,UAAU,CAAC,GAAG,EAAE;gBAC5B,oEAAoE;gBACpE,gEAAgE;gBAChE,kEAAkE;gBAClE,iEAAiE;gBACjE,mEAAmE;gBACnE,qBAAqB;gBACrB,IAAI,IAAI,CAAC,OAAO,CAAC,GAAG,CAAC,MAAM,CAAC,EAAE,CAAC;oBAC7B,IAAI,CAAC,OAAO,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC;oBAC5B,MAAM,OAAO,GAAgB,EAAE,IAAI,EAAE,SAAS,EAAE,MAAM,EAAE,OAAO,EAAE,IAAI,CAAC,aAAa,EAAE,CAAC;oBACtF,IAAI,CAAC,SAAS,EAAE,CAAC,OAAO,EAAE,OAAO,CAAC,CAAC;oBACnC,OAAO,CAAC,OAAO,CAAC,CAAC;gBACnB,CAAC;YACH,CAAC,EAAE,IAAI,CAAC,aAAa,CAAC,CAAC;YAEvB,IAAI,CAAC,OAAO,CAAC,GAAG,CAAC,MAAM,EAAE;gBACvB,MAAM;gBACN,OAAO,EAAE,CAAC,OAAO,EAAE,EAAE;oBACnB,YAAY,CAAC,KAAK,CAAC,CAAC;oBACpB,IAAI,CAAC,OAAO,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC;oBAC5B,IAAI,CAAC,SAAS,EAAE,CAAC,OAAO,EAAE,OAAO,CAAC,CAAC;oBACnC,OAAO,CAAC,OAAO,CAAC,CAAC;gBACnB,CAAC;gBACD,KAAK;aACN,CAAC,CAAC;QACL,CAAC,CAAC,CAAC;IACL,CAAC;IAED;;;;+BAI2B;IAC3B,kBAAkB,CAAC,MAAc,EAAE,MAAe;QAChD,IAAI,MAAM,KAAK,gBAAgB,EAAE,CAAC;YAChC,MAAM,CAAC,GAAG,MAAiD,CAAC;YAC5D,MAAM,MAAM,GAAG,CAAC,EAAE,IAAI,EAAE,EAAE,CAAC;YAC3B,IAAI,CAAC,MAAM;gBAAE,OAAO,KAAK,CAAC;YAC1B,MAAM,CAAC,GAAG,IAAI,CAAC,OAAO,CAAC,GAAG,CAAC,MAAM,CAAC,CAAC;YACnC,IAAI,CAAC,CAAC;gBAAE,OAAO,KAAK,CAAC,CAAE,oDAAoD;YAC3E,CAAC,CAAC,OAAO,CAAC,EAAE,IAAI,EAAE,WAAW,EAAE,MAAM,EAAE,IAAI,EAAE,CAAC,CAAC,IAAK,EAAE,CAAC,CAAC;YACxD,OAAO,IAAI,CAAC;QACd,CAAC;QACD,IAAI,MAAM,KAAK,gBAAgB,EAAE,CAAC;YAChC,MAAM,CAAC,GAAG,MAAiD,CAAC;YAC5D,MAAM,MAAM,GAAG,CAAC,EAAE,IAAI,EAAE,EAAE,CAAC;YAC3B,IAAI,CAAC,MAAM;gBAAE,OAAO,KAAK,CAAC;YAC1B,MAAM,CAAC,GAAG,IAAI,CAAC,OAAO,CAAC,GAAG,CAAC,MAAM,CAAC,CAAC;YACnC,IAAI,CAAC,CAAC;gBAAE,OAAO,KAAK,CAAC;YACrB,CAAC,CAAC,OAAO,CAAC,EAAE,IAAI,EAAE,aAAa,EAAE,MAAM,EAAE,IAAI,EAAE,CAAC,CAAC,IAAI,EAAE,CAAC,CAAC;YACzD,OAAO,IAAI,CAAC;QACd,CAAC;QACD,IAAI,MAAM,KAAK,OAAO,EAAE,CAAC;YACvB,MAAM,CAAC,GAAG,MAA0C,CAAC;YACrD,MAAM,MAAM,GAAG,CAAC,EAAE,MAAM,CAAC;YACzB,IAAI,CAAC,MAAM;gBAAE,OAAO,KAAK,CAAC;YAC1B,MAAM,CAAC,GAAG,IAAI,CAAC,OAAO,CAAC,GAAG,CAAC,MAAM,CAAC,CAAC;YACnC,IAAI,CAAC,CAAC;gBAAE,OAAO,KAAK,CAAC;YACrB,qEAAqE;YACrE,wEAAwE;YACxE,kEAAkE;YAClE,IAAI,CAAC,CAAC,SAAS,KAAK,IAAI;gBAAE,OAAO,KAAK,CAAC;YACvC,CAAC,CAAC,OAAO,CAAC;gBACR,IAAI,EAAE,QAAQ;gBACd,MAAM;gBACN,SAAS,EAAE,CAAC,CAAC,CAAC,CAAC,SAAS;gBACxB,KAAK,EAAE,CAAC,CAAC,KAAK,IAAI,IAAI;aACvB,CAAC,CAAC;YACH,OAAO,IAAI,CAAC;QACd,CAAC;QACD,OAAO,KAAK,CAAC;IACf,CAAC;IAED;uEACmE;IACnE,QAAQ;QACN,OAAO;YACL,WAAW,EAAE,CAAC,GAAG,IAAI,CAAC,OAAO,CAAC,IAAI,EAAE,CAAC;YACrC,gBAAgB,EAAE,IAAI,CAAC,gBAAgB,CAAC,IAAI;SAC7C,CAAC;IACJ,CAAC;IAED;6CACyC;IACzC,cAAc;QACZ,KAAK,MAAM,CAAC,IAAI,IAAI,CAAC,OAAO,CAAC,MAAM,EAAE;YAAE,YAAY,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC;QAC7D,IAAI,CAAC,OAAO,CAAC,KAAK,EAAE,CAAC;IACvB,CAAC;CACF"}