@gkorepanov/ccodex 0.4.17 → 0.4.18

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.
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "schemaVersion": 1,
3
- "productVersion": "0.4.17",
3
+ "productVersion": "0.4.18",
4
4
  "node": ">=22.13 <27",
5
5
  "codexCli": "0.146.0",
6
6
  "codexGitRevision": "be449751a978f02e5bbba886999662956c7f38f5",
@@ -9,6 +9,7 @@ const mediaTypes = {
9
9
  ".png": "image/png",
10
10
  ".webp": "image/webp",
11
11
  };
12
+ const dataImageUrl = /^data:(image\/[a-z+.-]+);base64,([\s\S]*)$/i;
12
13
  async function allowedImagePath(path, context) {
13
14
  const candidate = await realpath(isAbsolute(path) ? path : resolve(context.cwd, path));
14
15
  const sandbox = context.sandboxPolicy && typeof context.sandboxPolicy === "object" && "type" in context.sandboxPolicy
@@ -43,6 +44,14 @@ export async function mapUserInput(input, uuid, context) {
43
44
  throw invalidParams("Codex skills are not available in Claude threads.");
44
45
  }
45
46
  else if (item.type === "image") {
47
+ const inline = dataImageUrl.exec(item.url);
48
+ if (inline) {
49
+ const mediaType = inline[1].toLocaleLowerCase();
50
+ if (!Object.values(mediaTypes).includes(mediaType))
51
+ throw invalidParams(`Unsupported Claude image type '${mediaType}'.`);
52
+ content.push({ type: "image", source: { type: "base64", media_type: mediaType, data: inline[2].replace(/\s+/g, "") } });
53
+ continue;
54
+ }
46
55
  const url = new URL(item.url);
47
56
  if (url.protocol !== "https:" && url.protocol !== "http:")
48
57
  throw invalidParams(`Unsupported Claude image URL scheme '${url.protocol}'.`);
@@ -1 +1 @@
1
- {"version":3,"file":"inputMapper.js","sourceRoot":"","sources":["../../src/claude/inputMapper.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"inputMapper.js","sourceRoot":"","sources":["../../src/claude/inputMapper.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,26 @@
1
+ export declare const CODEX_MCP_TOOLS: Set<string>;
2
+ export declare const CODEX_MCP_PROMPT_LABEL = "\u25C6 CCodex \u2502 Codex MCP prompt";
3
+ export declare const CODEX_MCP_MESSAGE_LABEL = "\u25C6 CCodex \u2502 Codex MCP message";
4
+ export declare const CODEX_MCP_REASONING_LABEL = "\u25C6 CCodex \u2502 Codex MCP reasoning";
5
+ export type CodexRolloutEvent = {
6
+ readonly kind: "message";
7
+ readonly text: string;
8
+ } | {
9
+ readonly kind: "reasoning";
10
+ readonly text: string;
11
+ } | {
12
+ readonly kind: "turnComplete";
13
+ };
14
+ /** Locates the rollout journal for a codex MCP call; injectable for tests. */
15
+ export interface CodexRolloutLocator {
16
+ /** Journal of an existing codex thread (codex-reply), by thread id. */
17
+ byThreadId(threadId: string): string | undefined;
18
+ /** Journal of a fresh MCP-sourced codex session started at or after `notBeforeMs`, excluding `claimed` paths. */
19
+ freshMcpSession(notBeforeMs: number, claimed: ReadonlySet<string>): string | undefined;
20
+ }
21
+ export declare function defaultCodexRolloutLocator(sessionsDir?: string): CodexRolloutLocator;
22
+ /** Consumes complete journal lines from `buffer` + `chunk`, returning mapped events and the unparsed tail. */
23
+ export declare function parseRolloutChunk(buffer: string, chunk: string): {
24
+ rest: string;
25
+ events: CodexRolloutEvent[];
26
+ };
@@ -0,0 +1,139 @@
1
+ import { closeSync, openSync, readSync, readdirSync, statSync } from "node:fs";
2
+ import { homedir } from "node:os";
3
+ import { join } from "node:path";
4
+ export const CODEX_MCP_TOOLS = new Set(["mcp__codex__codex", "mcp__codex__codex-reply"]);
5
+ export const CODEX_MCP_PROMPT_LABEL = "◆ CCodex │ Codex MCP prompt";
6
+ export const CODEX_MCP_MESSAGE_LABEL = "◆ CCodex │ Codex MCP message";
7
+ export const CODEX_MCP_REASONING_LABEL = "◆ CCodex │ Codex MCP reasoning";
8
+ function codexSessionsDir() {
9
+ return join(process.env.CODEX_HOME ?? join(homedir(), ".codex"), "sessions");
10
+ }
11
+ function dayDirsNewestFirst(root, limit) {
12
+ const numericDesc = (values) => values.filter((value) => /^\d+$/.test(value)).sort((a, b) => Number(b) - Number(a));
13
+ const days = [];
14
+ let entries;
15
+ try {
16
+ entries = readdirSync(root);
17
+ }
18
+ catch {
19
+ return [];
20
+ }
21
+ for (const year of numericDesc(entries)) {
22
+ for (const month of numericDesc(readdirSync(join(root, year)))) {
23
+ for (const day of numericDesc(readdirSync(join(root, year, month)))) {
24
+ days.push(join(root, year, month, day));
25
+ if (days.length >= limit)
26
+ return days;
27
+ }
28
+ }
29
+ }
30
+ return days;
31
+ }
32
+ function sessionMeta(path) {
33
+ // The session_meta line embeds the full codex base instructions, so it can be
34
+ // tens of kilobytes long — read a bounded head and require a complete line.
35
+ let head;
36
+ try {
37
+ const buffer = Buffer.alloc(262_144);
38
+ const fd = openSync(path, "r");
39
+ try {
40
+ head = buffer.subarray(0, readSync(fd, buffer, 0, buffer.length, 0)).toString("utf8");
41
+ }
42
+ finally {
43
+ closeSync(fd);
44
+ }
45
+ }
46
+ catch {
47
+ return undefined;
48
+ }
49
+ const end = head.indexOf("\n");
50
+ if (end === -1)
51
+ return undefined;
52
+ const line = head.slice(0, end);
53
+ try {
54
+ const parsed = JSON.parse(line);
55
+ if (parsed.type !== "session_meta")
56
+ return undefined;
57
+ const timestamp = parsed.payload?.timestamp ? Date.parse(parsed.payload.timestamp) : Number.NaN;
58
+ return {
59
+ ...(parsed.payload?.source === undefined ? {} : { source: parsed.payload.source }),
60
+ ...(Number.isNaN(timestamp) ? {} : { timestampMs: timestamp }),
61
+ };
62
+ }
63
+ catch {
64
+ return undefined;
65
+ }
66
+ }
67
+ export function defaultCodexRolloutLocator(sessionsDir = codexSessionsDir()) {
68
+ return {
69
+ byThreadId(threadId) {
70
+ const suffix = `-${threadId}.jsonl`;
71
+ for (const day of dayDirsNewestFirst(sessionsDir, 366)) {
72
+ for (const entry of readdirSync(day)) {
73
+ if (entry.endsWith(suffix))
74
+ return join(day, entry);
75
+ }
76
+ }
77
+ return undefined;
78
+ },
79
+ freshMcpSession(notBeforeMs, claimed) {
80
+ const candidates = [];
81
+ for (const day of dayDirsNewestFirst(sessionsDir, 2)) {
82
+ for (const entry of readdirSync(day)) {
83
+ if (!entry.endsWith(".jsonl"))
84
+ continue;
85
+ const path = join(day, entry);
86
+ if (claimed.has(path))
87
+ continue;
88
+ try {
89
+ if (statSync(path).mtimeMs < notBeforeMs - 5_000)
90
+ continue;
91
+ }
92
+ catch {
93
+ continue;
94
+ }
95
+ const meta = sessionMeta(path);
96
+ if (meta?.source !== "mcp")
97
+ continue;
98
+ if (meta.timestampMs === undefined || meta.timestampMs < notBeforeMs - 5_000)
99
+ continue;
100
+ candidates.push({ path, timestampMs: meta.timestampMs });
101
+ }
102
+ }
103
+ return candidates.sort((a, b) => a.timestampMs - b.timestampMs)[0]?.path;
104
+ },
105
+ };
106
+ }
107
+ /** Consumes complete journal lines from `buffer` + `chunk`, returning mapped events and the unparsed tail. */
108
+ export function parseRolloutChunk(buffer, chunk) {
109
+ const combined = buffer + chunk;
110
+ const boundary = combined.lastIndexOf("\n");
111
+ if (boundary === -1)
112
+ return { rest: combined, events: [] };
113
+ const events = [];
114
+ for (const line of combined.slice(0, boundary).split("\n")) {
115
+ if (!line.trim())
116
+ continue;
117
+ let parsed;
118
+ try {
119
+ parsed = JSON.parse(line);
120
+ }
121
+ catch {
122
+ continue;
123
+ }
124
+ if (parsed.type !== "event_msg")
125
+ continue;
126
+ const payload = parsed.payload;
127
+ if (payload?.type === "agent_message" && typeof payload.message === "string" && payload.message) {
128
+ events.push({ kind: "message", text: payload.message });
129
+ }
130
+ else if (payload?.type === "agent_reasoning" && typeof payload.text === "string" && payload.text) {
131
+ events.push({ kind: "reasoning", text: payload.text });
132
+ }
133
+ else if (payload?.type === "task_complete") {
134
+ events.push({ kind: "turnComplete" });
135
+ }
136
+ }
137
+ return { rest: combined.slice(boundary + 1), events };
138
+ }
139
+ //# sourceMappingURL=codexRollout.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"codexRollout.js","sourceRoot":"","sources":["../../../src/claude/session/codexRollout.ts"],"names":[],"mappings":"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"}
@@ -110,6 +110,9 @@ export type MainStreamFact = {
110
110
  } | {
111
111
  readonly kind: "instantAgent";
112
112
  readonly text: string;
113
+ } | {
114
+ readonly kind: "instantReasoning";
115
+ readonly text: string;
113
116
  } | {
114
117
  readonly kind: "settle";
115
118
  readonly phase: "commentary" | "final_answer";
@@ -727,6 +730,12 @@ export type ClaudeSessionCommand = {
727
730
  readonly type: "captureToolFileAfter";
728
731
  readonly runtimeGeneration: number;
729
732
  readonly providerId: string;
733
+ } | {
734
+ readonly type: "codexMcpCallBegin";
735
+ readonly runtimeGeneration: number;
736
+ readonly providerId: string;
737
+ readonly ownerProviderId?: string;
738
+ readonly input: Record<string, unknown>;
730
739
  } | {
731
740
  readonly type: "hook";
732
741
  readonly runtimeGeneration: number;
@@ -6,6 +6,7 @@ import type { ClaudeOutputAdapter } from "./outputAdapter.js";
6
6
  import { type ClaudeSessionRepository } from "./repository.js";
7
7
  import { ShellRunner } from "./shellRunner.js";
8
8
  import { type BackgroundOutputReader } from "./backgroundOutput.js";
9
+ import { type CodexRolloutLocator } from "./codexRollout.js";
9
10
  import type { TurnStartParams } from "../../codex/generated/v2/TurnStartParams.js";
10
11
  import type { TurnSteerParams } from "../../codex/generated/v2/TurnSteerParams.js";
11
12
  import type { ThreadBackgroundTerminal } from "../../codex/generated/v2/ThreadBackgroundTerminal.js";
@@ -47,6 +48,7 @@ export declare class ClaudeSession implements ClaudeSessionHandle<ClaudeSessionC
47
48
  private readonly shellRunner;
48
49
  private readonly backgroundOutputReader;
49
50
  private readonly runtimeDependencies?;
51
+ private readonly codexRolloutLocator;
50
52
  private readonly mailbox;
51
53
  private readonly consumer;
52
54
  private runtimeLineage;
@@ -63,6 +65,8 @@ export declare class ClaudeSession implements ClaudeSessionHandle<ClaudeSessionC
63
65
  private runtimeGeneration;
64
66
  private readonly scopes;
65
67
  private readonly tasks;
68
+ private readonly codexMcpTailers;
69
+ private readonly codexRolloutClaims;
66
70
  private compaction;
67
71
  private automaticCompaction;
68
72
  private readonly compactionActions;
@@ -93,7 +97,7 @@ export declare class ClaudeSession implements ClaudeSessionHandle<ClaudeSessionC
93
97
  private hookDisplayOrder;
94
98
  private adminOperation;
95
99
  private shell;
96
- constructor(threadId: string, repository: ClaudeSessionRepository, output: ClaudeOutputAdapter, capacity?: number, metrics?: MetricsRegistry, onLifecycle?: (update: SessionLifecycleUpdate) => void, onChildCreated?: (threadId: string) => void, onChildRemoved?: (threadId: string) => void, shellRunner?: ShellRunner, backgroundOutputReader?: BackgroundOutputReader, runtimeDependencies?: ClaudeSessionRuntimeDependencies | undefined);
100
+ constructor(threadId: string, repository: ClaudeSessionRepository, output: ClaudeOutputAdapter, capacity?: number, metrics?: MetricsRegistry, onLifecycle?: (update: SessionLifecycleUpdate) => void, onChildCreated?: (threadId: string) => void, onChildRemoved?: (threadId: string) => void, shellRunner?: ShellRunner, backgroundOutputReader?: BackgroundOutputReader, runtimeDependencies?: ClaudeSessionRuntimeDependencies | undefined, codexRolloutLocator?: CodexRolloutLocator);
97
101
  submit<Result>(command: ClaudeSessionCommand): Promise<Result>;
98
102
  private submitLineage;
99
103
  private submitRuntimeEffect;
@@ -262,6 +266,11 @@ export declare class ClaudeSession implements ClaudeSessionHandle<ClaudeSessionC
262
266
  private findTool;
263
267
  private toolOwner;
264
268
  private captureToolFileBefore;
269
+ private codexMcpCallBegin;
270
+ private ensureCodexRolloutTailer;
271
+ private drainCodexRollout;
272
+ private finishCodexRolloutTailer;
273
+ private stopCodexRolloutTailer;
265
274
  private captureToolFileAfter;
266
275
  private acceptHook;
267
276
  private syncInteractionStatus;
@@ -17,7 +17,9 @@ import { bindGoalTurn, consumeGoalContinuation, dispatchGoal, finishGoalTurn, go
17
17
  import { ShellRunner } from "./shellRunner.js";
18
18
  import { diffFile, snapshotFile } from "../fileSnapshots.js";
19
19
  import { appendHookProgress, completeHookRun, startHookRun } from "../hookMapper.js";
20
+ import { stat } from "node:fs/promises";
20
21
  import { readBackgroundOutput } from "./backgroundOutput.js";
22
+ import { CODEX_MCP_MESSAGE_LABEL, CODEX_MCP_PROMPT_LABEL, CODEX_MCP_REASONING_LABEL, CODEX_MCP_TOOLS, defaultCodexRolloutLocator, parseRolloutChunk, } from "./codexRollout.js";
21
23
  import { createGoalMcpServer } from "../goalTools.js";
22
24
  import { mapUserInput } from "../inputMapper.js";
23
25
  import { bashCommandActions } from "../commandActions.js";
@@ -118,6 +120,7 @@ export class ClaudeSession {
118
120
  shellRunner;
119
121
  backgroundOutputReader;
120
122
  runtimeDependencies;
123
+ codexRolloutLocator;
121
124
  mailbox;
122
125
  consumer;
123
126
  runtimeLineage = { state: "absent" };
@@ -134,6 +137,8 @@ export class ClaudeSession {
134
137
  runtimeGeneration;
135
138
  scopes = new Map();
136
139
  tasks = new Map();
140
+ codexMcpTailers = new Map();
141
+ codexRolloutClaims = new Set();
137
142
  compaction;
138
143
  automaticCompaction;
139
144
  compactionActions = [];
@@ -164,7 +169,7 @@ export class ClaudeSession {
164
169
  hookDisplayOrder = 0;
165
170
  adminOperation;
166
171
  shell;
167
- constructor(threadId, repository, output, capacity, metrics = new MetricsRegistry(), onLifecycle = () => undefined, onChildCreated = () => undefined, onChildRemoved = () => undefined, shellRunner = new ShellRunner(), backgroundOutputReader = readBackgroundOutput, runtimeDependencies) {
172
+ constructor(threadId, repository, output, capacity, metrics = new MetricsRegistry(), onLifecycle = () => undefined, onChildCreated = () => undefined, onChildRemoved = () => undefined, shellRunner = new ShellRunner(), backgroundOutputReader = readBackgroundOutput, runtimeDependencies, codexRolloutLocator = defaultCodexRolloutLocator()) {
168
173
  this.threadId = threadId;
169
174
  this.repository = repository;
170
175
  this.output = output;
@@ -175,6 +180,7 @@ export class ClaudeSession {
175
180
  this.shellRunner = shellRunner;
176
181
  this.backgroundOutputReader = backgroundOutputReader;
177
182
  this.runtimeDependencies = runtimeDependencies;
183
+ this.codexRolloutLocator = codexRolloutLocator;
178
184
  this.mailbox = new ClaudeMailbox(capacity);
179
185
  this.consumer = this.run();
180
186
  }
@@ -2089,6 +2095,15 @@ export class ClaudeSession {
2089
2095
  toolName: input.tool_name,
2090
2096
  input: toolInput,
2091
2097
  });
2098
+ if (CODEX_MCP_TOOLS.has(input.tool_name)) {
2099
+ await this.submitProviderProjection(runtimeGeneration, {
2100
+ type: "codexMcpCallBegin",
2101
+ runtimeGeneration,
2102
+ providerId: toolUseId,
2103
+ ...(input.agent_id ? { ownerProviderId: input.agent_id } : {}),
2104
+ input: toolInput,
2105
+ });
2106
+ }
2092
2107
  }
2093
2108
  if (policy.decision === "defer" || policy.decision === "ask")
2094
2109
  return { continue: true };
@@ -2284,6 +2299,9 @@ export class ClaudeSession {
2284
2299
  const backgroundId = backgroundTaskId(message);
2285
2300
  const itemIds = [];
2286
2301
  for (const result of toolResults(message)) {
2302
+ if (this.codexMcpTailers.has(result.toolUseId)) {
2303
+ await this.finishCodexRolloutTailer(result.toolUseId);
2304
+ }
2287
2305
  const outputFile = backgroundOutputFile(result.output);
2288
2306
  const projected = backgroundId
2289
2307
  ? await this.applyProviderMainStream(projection, runtimeGeneration, {
@@ -4248,6 +4266,8 @@ export class ClaudeSession {
4248
4266
  }
4249
4267
  case "captureToolFileBefore":
4250
4268
  return this.captureToolFileBefore(command);
4269
+ case "codexMcpCallBegin":
4270
+ return this.codexMcpCallBegin(command);
4251
4271
  case "captureToolFileAfter":
4252
4272
  return this.captureToolFileAfter(command.runtimeGeneration, command.providerId);
4253
4273
  case "hook":
@@ -5995,6 +6015,131 @@ export class ClaudeSession {
5995
6015
  tool.fileSnapshot = snapshot;
5996
6016
  return true;
5997
6017
  }
6018
+ codexMcpCallBegin(command) {
6019
+ if (command.runtimeGeneration !== this.runtimeGeneration || this.interruptFence || this.dropLateFacts)
6020
+ return false;
6021
+ let owner = this.toolOwner(command.providerId);
6022
+ if (!owner && command.ownerProviderId) {
6023
+ owner = this.toolOwner(command.ownerProviderId);
6024
+ const task = [...this.tasks.values()].find((candidate) => taskUsesProvider(candidate, command.ownerProviderId) || candidate.taskId === command.ownerProviderId);
6025
+ if (task?.childThreadId)
6026
+ owner = this.scopes.get(task.childThreadId);
6027
+ }
6028
+ owner ??= this.scopes.get(this.threadId);
6029
+ if (!owner)
6030
+ return false;
6031
+ const prompt = typeof command.input.prompt === "string" ? command.input.prompt : "";
6032
+ if (prompt) {
6033
+ this.projectMainStream(owner.ownerThreadId, {
6034
+ kind: "instantAgent",
6035
+ text: `${CODEX_MCP_PROMPT_LABEL}\n\n${prompt}`,
6036
+ }, nullSource);
6037
+ }
6038
+ this.ensureCodexRolloutTailer(command.providerId, owner.ownerThreadId, typeof command.input.threadId === "string" ? command.input.threadId : undefined);
6039
+ return true;
6040
+ }
6041
+ ensureCodexRolloutTailer(providerId, ownerThreadId, codexThreadId) {
6042
+ if (this.codexMcpTailers.has(providerId))
6043
+ return;
6044
+ const runtimeGeneration = this.runtimeGeneration;
6045
+ if (runtimeGeneration === undefined)
6046
+ return;
6047
+ const tailer = {
6048
+ runtimeGeneration, ownerThreadId, codexThreadId,
6049
+ notBeforeMs: Date.now(), offset: 0, buffer: "",
6050
+ decoder: new TextDecoder(),
6051
+ timer: setInterval(() => { void this.drainCodexRollout(providerId).catch(() => undefined); }, 250),
6052
+ stopped: false, sawTurnComplete: false,
6053
+ };
6054
+ tailer.timer.unref();
6055
+ this.codexMcpTailers.set(providerId, tailer);
6056
+ void this.drainCodexRollout(providerId).catch(() => undefined);
6057
+ }
6058
+ async drainCodexRollout(providerId, final = false) {
6059
+ const tailer = this.codexMcpTailers.get(providerId);
6060
+ if (!tailer || tailer.stopped)
6061
+ return;
6062
+ if (tailer.reading) {
6063
+ const reading = tailer.reading;
6064
+ await reading;
6065
+ if (tailer.reading === reading)
6066
+ tailer.reading = undefined;
6067
+ if (final)
6068
+ await this.drainCodexRollout(providerId, true);
6069
+ return;
6070
+ }
6071
+ const reading = (async () => {
6072
+ if (!tailer.file) {
6073
+ if (tailer.codexThreadId) {
6074
+ // Continuation of an existing codex thread: the journal already holds
6075
+ // prior turns, so start from its current end.
6076
+ const file = this.codexRolloutLocator.byThreadId(tailer.codexThreadId);
6077
+ if (!file)
6078
+ return;
6079
+ tailer.offset = await stat(file).then((info) => info.size, () => 0);
6080
+ tailer.file = file;
6081
+ }
6082
+ else {
6083
+ const file = this.codexRolloutLocator.freshMcpSession(tailer.notBeforeMs, this.codexRolloutClaims);
6084
+ if (!file)
6085
+ return;
6086
+ tailer.file = file;
6087
+ }
6088
+ this.codexRolloutClaims.add(tailer.file);
6089
+ }
6090
+ tailer.offset = await this.backgroundOutputReader(tailer.file, tailer.offset, async (bytes) => {
6091
+ if (tailer.stopped)
6092
+ return;
6093
+ const { rest, events } = parseRolloutChunk(tailer.buffer, tailer.decoder.decode(bytes, { stream: true }));
6094
+ tailer.buffer = rest;
6095
+ for (const event of events) {
6096
+ if (event.kind === "turnComplete") {
6097
+ tailer.sawTurnComplete = true;
6098
+ continue;
6099
+ }
6100
+ await this.submit({
6101
+ type: "mainStream",
6102
+ runtimeGeneration: tailer.runtimeGeneration,
6103
+ ownerThreadId: tailer.ownerThreadId,
6104
+ source: { providerEventId: null, providerEventType: "codex_rollout" },
6105
+ fact: event.kind === "message"
6106
+ ? { kind: "instantAgent", text: `${CODEX_MCP_MESSAGE_LABEL}\n\n${event.text}` }
6107
+ : { kind: "instantReasoning", text: `${CODEX_MCP_REASONING_LABEL}\n\n${event.text}` },
6108
+ });
6109
+ }
6110
+ });
6111
+ })();
6112
+ tailer.reading = reading;
6113
+ try {
6114
+ await reading;
6115
+ }
6116
+ finally {
6117
+ if (tailer.reading === reading)
6118
+ tailer.reading = undefined;
6119
+ }
6120
+ }
6121
+ async finishCodexRolloutTailer(providerId) {
6122
+ const tailer = this.codexMcpTailers.get(providerId);
6123
+ if (!tailer)
6124
+ return;
6125
+ for (let attempt = 0; attempt < 3 && !tailer.stopped; attempt += 1) {
6126
+ await this.drainCodexRollout(providerId, true).catch(() => undefined);
6127
+ if (tailer.sawTurnComplete)
6128
+ break;
6129
+ await new Promise((resolve) => setTimeout(resolve, 250));
6130
+ }
6131
+ this.stopCodexRolloutTailer(providerId);
6132
+ }
6133
+ stopCodexRolloutTailer(providerId) {
6134
+ const tailer = this.codexMcpTailers.get(providerId);
6135
+ if (!tailer)
6136
+ return;
6137
+ tailer.stopped = true;
6138
+ clearInterval(tailer.timer);
6139
+ if (tailer.file)
6140
+ this.codexRolloutClaims.delete(tailer.file);
6141
+ this.codexMcpTailers.delete(providerId);
6142
+ }
5998
6143
  async captureToolFileAfter(runtimeGeneration, providerId) {
5999
6144
  if (runtimeGeneration !== this.runtimeGeneration || this.interruptFence || this.dropLateFacts)
6000
6145
  return false;
@@ -6299,6 +6444,19 @@ export class ClaudeSession {
6299
6444
  itemIds = [item.id];
6300
6445
  break;
6301
6446
  }
6447
+ case "instantReasoning": {
6448
+ const item = { type: "reasoning", id: uuidv7(), summary: [fact.text], content: [] };
6449
+ turn.items.push(item);
6450
+ this.publishTurn(turn, "item/started", {
6451
+ item, threadId: state.ownerThreadId, turnId: turn.id, startedAtMs: Date.now(),
6452
+ }, source);
6453
+ this.publishTurn(turn, "item/reasoning/summaryTextDelta", {
6454
+ threadId: state.ownerThreadId, turnId: turn.id, itemId: item.id, delta: fact.text, summaryIndex: 0,
6455
+ }, source);
6456
+ this.completeStreamItem(turn, state, item.id, source);
6457
+ itemIds = [item.id];
6458
+ break;
6459
+ }
6302
6460
  case "settle":
6303
6461
  this.settleAgentMessages(turn, state, fact.phase, source);
6304
6462
  break;
@@ -6431,8 +6589,10 @@ export class ClaudeSession {
6431
6589
  if (itemIds.has(id))
6432
6590
  state.blockItems.delete(index);
6433
6591
  for (const [id, candidate] of state.tools)
6434
- if (itemIds.has(candidate.itemId))
6592
+ if (itemIds.has(candidate.itemId)) {
6435
6593
  state.tools.delete(id);
6594
+ this.stopCodexRolloutTailer(id);
6595
+ }
6436
6596
  for (const [id, task] of this.tasks)
6437
6597
  if (itemIds.has(task.itemId)) {
6438
6598
  this.stopBackgroundTailer(task);
@@ -6535,6 +6695,8 @@ export class ClaudeSession {
6535
6695
  disposeRuntimeOperations() {
6536
6696
  for (const task of this.tasks.values())
6537
6697
  this.stopBackgroundTailer(task);
6698
+ for (const providerId of [...this.codexMcpTailers.keys()])
6699
+ this.stopCodexRolloutTailer(providerId);
6538
6700
  for (const state of this.scopes.values()) {
6539
6701
  for (const tool of state.tools.values())
6540
6702
  delete tool.fileSnapshot;