@cjhyy/code-shell-core 0.7.0-beta.1 → 0.7.1
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/arena/arena.d.ts +2 -0
- package/dist/arena/arena.js +30 -1
- package/dist/arena/phases/adjudication.d.ts +2 -1
- package/dist/arena/phases/adjudication.js +2 -1
- package/dist/arena/phases/build-consensus.d.ts +2 -1
- package/dist/arena/phases/build-consensus.js +3 -1
- package/dist/arena/phases/cross-review.d.ts +3 -1
- package/dist/arena/phases/cross-review.js +8 -2
- package/dist/arena/phases/debate-rounds.d.ts +2 -1
- package/dist/arena/phases/debate-rounds.js +4 -2
- package/dist/arena/phases/participant-research.d.ts +2 -1
- package/dist/arena/phases/participant-research.js +3 -1
- package/dist/arena/phases/planning-detail-expansion.d.ts +2 -1
- package/dist/arena/phases/planning-detail-expansion.js +2 -1
- package/dist/arena/planner.d.ts +2 -1
- package/dist/arena/planner.js +2 -1
- package/dist/arena/types.d.ts +5 -1
- package/dist/cc-orchestrator/agent-adapter.d.ts +2 -0
- package/dist/cc-orchestrator/agent-adapter.js +4 -0
- package/dist/cc-orchestrator/codex-session-history.d.ts +14 -1
- package/dist/cc-orchestrator/codex-session-history.js +64 -4
- package/dist/cc-orchestrator/external-agent-changes.js +22 -5
- package/dist/cc-orchestrator/external-agent-driver.d.ts +1 -1
- package/dist/cc-orchestrator/external-agent-driver.js +202 -38
- package/dist/cc-orchestrator/session-history.d.ts +35 -0
- package/dist/cc-orchestrator/session-history.js +96 -13
- package/dist/cli/agent-server-tcp.js +13 -2
- package/dist/context/manager.d.ts +3 -3
- package/dist/context/manager.js +6 -6
- package/dist/context/token-counter.js +5 -3
- package/dist/context/tool-result-storage.d.ts +6 -0
- package/dist/context/tool-result-storage.js +25 -4
- package/dist/credentials/access.d.ts +11 -1
- package/dist/credentials/access.js +77 -1
- package/dist/credentials/index.d.ts +3 -1
- package/dist/credentials/index.js +2 -0
- package/dist/credentials/oauth.d.ts +25 -0
- package/dist/credentials/oauth.js +179 -0
- package/dist/credentials/store.d.ts +2 -1
- package/dist/credentials/store.js +19 -8
- package/dist/credentials/types.d.ts +84 -1
- package/dist/credentials/types.js +16 -1
- package/dist/engine/engine.d.ts +67 -34
- package/dist/engine/engine.js +448 -247
- package/dist/engine/goal.d.ts +19 -0
- package/dist/engine/goal.js +16 -6
- package/dist/engine/input-attachments.js +156 -13
- package/dist/engine/run-image-input.d.ts +22 -0
- package/dist/engine/run-image-input.js +195 -0
- package/dist/engine/session-title.d.ts +2 -1
- package/dist/engine/session-title.js +4 -1
- package/dist/engine/steer-queue.d.ts +3 -1
- package/dist/engine/steer-queue.js +10 -2
- package/dist/engine/turn-loop.d.ts +48 -1
- package/dist/engine/turn-loop.js +307 -37
- package/dist/engine/types.d.ts +6 -2
- package/dist/git/worktree/crud.d.ts +3 -0
- package/dist/git/worktree/crud.js +32 -3
- package/dist/git/worktree/git-exec.d.ts +2 -2
- package/dist/git/worktree/git-exec.js +47 -11
- package/dist/git/worktree/query.d.ts +8 -7
- package/dist/git/worktree/query.js +27 -20
- package/dist/hooks/events.d.ts +3 -0
- package/dist/hooks/events.js +0 -3
- package/dist/hooks/goal-stop-hook.d.ts +44 -2
- package/dist/hooks/goal-stop-hook.js +775 -52
- package/dist/hooks/registry.js +3 -0
- package/dist/hooks/shell-runner.d.ts +12 -1
- package/dist/hooks/shell-runner.js +160 -9
- package/dist/index.d.ts +7 -6
- package/dist/index.js +6 -5
- package/dist/llm/client-base.js +12 -10
- package/dist/llm/types.d.ts +12 -5
- package/dist/plugins/pluginCommandHook.d.ts +4 -4
- package/dist/plugins/pluginCommandHook.js +111 -13
- package/dist/preset/index.js +14 -4
- package/dist/protocol/chat-session-manager.d.ts +13 -2
- package/dist/protocol/chat-session-manager.js +90 -18
- package/dist/protocol/chat-session.d.ts +12 -0
- package/dist/protocol/chat-session.js +30 -5
- package/dist/protocol/client.d.ts +5 -2
- package/dist/protocol/client.js +22 -1
- package/dist/protocol/server.d.ts +25 -11
- package/dist/protocol/server.js +291 -73
- package/dist/protocol/types.d.ts +36 -2
- package/dist/protocol/types.js +2 -0
- package/dist/services/dream-consolidation.d.ts +3 -0
- package/dist/services/dream-consolidation.js +4 -1
- package/dist/services/index.d.ts +1 -1
- package/dist/services/index.js +1 -1
- package/dist/services/oauth.d.ts +34 -10
- package/dist/services/oauth.js +233 -98
- package/dist/session/session-manager.d.ts +35 -6
- package/dist/session/session-manager.js +396 -27
- package/dist/session/transcript.d.ts +30 -1
- package/dist/session/transcript.js +119 -4
- package/dist/tool-system/builtin/agent-notifications.d.ts +11 -4
- package/dist/tool-system/builtin/agent-notifications.js +19 -7
- package/dist/tool-system/builtin/agent.js +5 -1
- package/dist/tool-system/builtin/arena.js +1 -0
- package/dist/tool-system/builtin/background-jobs.d.ts +28 -5
- package/dist/tool-system/builtin/background-jobs.js +109 -7
- package/dist/tool-system/builtin/background-work.d.ts +6 -1
- package/dist/tool-system/builtin/background-work.js +5 -1
- package/dist/tool-system/builtin/bash.d.ts +3 -5
- package/dist/tool-system/builtin/bash.js +10 -5
- package/dist/tool-system/builtin/browser-tools.d.ts +2 -2
- package/dist/tool-system/builtin/cron-list.definition.d.ts +3 -0
- package/dist/tool-system/builtin/cron-list.definition.js +6 -0
- package/dist/tool-system/builtin/cron.d.ts +1 -2
- package/dist/tool-system/builtin/cron.js +9 -7
- package/dist/tool-system/builtin/drive-claude-code.d.ts +7 -0
- package/dist/tool-system/builtin/drive-claude-code.js +307 -20
- package/dist/tool-system/builtin/edit.d.ts +2 -1
- package/dist/tool-system/builtin/edit.js +12 -4
- package/dist/tool-system/builtin/generate-video.d.ts +4 -0
- package/dist/tool-system/builtin/generate-video.js +138 -21
- package/dist/tool-system/builtin/glob.d.ts +2 -1
- package/dist/tool-system/builtin/glob.js +28 -3
- package/dist/tool-system/builtin/grep.d.ts +1 -0
- package/dist/tool-system/builtin/grep.js +82 -17
- package/dist/tool-system/builtin/index.d.ts +25 -11
- package/dist/tool-system/builtin/index.js +60 -5
- package/dist/tool-system/builtin/sleep.d.ts +1 -2
- package/dist/tool-system/builtin/sleep.definition.d.ts +8 -0
- package/dist/tool-system/builtin/sleep.definition.js +28 -0
- package/dist/tool-system/builtin/sleep.js +1 -22
- package/dist/tool-system/builtin/video-providers.d.ts +12 -15
- package/dist/tool-system/builtin/video-providers.js +1 -0
- package/dist/tool-system/builtin/view-image.d.ts +2 -2
- package/dist/tool-system/builtin/web-fetch.js +44 -3
- package/dist/tool-system/builtin/worktree.js +25 -7
- package/dist/tool-system/builtin/write.d.ts +2 -1
- package/dist/tool-system/builtin/write.js +14 -4
- package/dist/tool-system/context.d.ts +35 -5
- package/dist/tool-system/executor.js +24 -8
- package/dist/tool-system/mcp-manager.d.ts +20 -2
- package/dist/tool-system/mcp-manager.js +111 -12
- package/dist/tool-system/path-policy.d.ts +19 -0
- package/dist/tool-system/path-policy.js +62 -1
- package/dist/tool-system/permission.d.ts +43 -3
- package/dist/tool-system/permission.js +383 -30
- package/dist/tool-system/registry.d.ts +3 -2
- package/dist/tool-system/registry.js +52 -34
- package/dist/types.d.ts +38 -7
- package/package.json +1 -1
package/dist/arena/arena.d.ts
CHANGED
package/dist/arena/arena.js
CHANGED
|
@@ -28,6 +28,7 @@ import { runDetailExpansion } from "./phases/planning-detail-expansion.js";
|
|
|
28
28
|
import { withLanguage } from "./strategies/language-wrapper.js";
|
|
29
29
|
import { ArenaLedger } from "./ledger.js";
|
|
30
30
|
import { registerClaims } from "./phases/claim-registry.js";
|
|
31
|
+
import { addTokenUsage } from "../engine/session-usage.js";
|
|
31
32
|
/** Bucket claims by status. Shared by the two consensus phases. */
|
|
32
33
|
function summarizeClaims(all) {
|
|
33
34
|
return {
|
|
@@ -41,6 +42,17 @@ export class Arena {
|
|
|
41
42
|
config;
|
|
42
43
|
strategy;
|
|
43
44
|
limits;
|
|
45
|
+
usage = {
|
|
46
|
+
promptTokens: 0,
|
|
47
|
+
completionTokens: 0,
|
|
48
|
+
totalTokens: 0,
|
|
49
|
+
cacheReadTokens: 0,
|
|
50
|
+
cacheCreationTokens: 0,
|
|
51
|
+
};
|
|
52
|
+
recordUsage = (usage) => {
|
|
53
|
+
if (usage)
|
|
54
|
+
this.usage = addTokenUsage(this.usage, usage);
|
|
55
|
+
};
|
|
44
56
|
constructor(config) {
|
|
45
57
|
if (config.participants.length < 2) {
|
|
46
58
|
throw new Error("Arena requires at least 2 participants");
|
|
@@ -63,13 +75,20 @@ export class Arena {
|
|
|
63
75
|
* @param flags - Optional explicit overrides (mode, base, head)
|
|
64
76
|
*/
|
|
65
77
|
async run(topic, flags) {
|
|
78
|
+
this.usage = {
|
|
79
|
+
promptTokens: 0,
|
|
80
|
+
completionTokens: 0,
|
|
81
|
+
totalTokens: 0,
|
|
82
|
+
cacheReadTokens: 0,
|
|
83
|
+
cacheCreationTokens: 0,
|
|
84
|
+
};
|
|
66
85
|
const participantNames = this.config.participants.map((p) => p.name);
|
|
67
86
|
const signal = this.config.signal;
|
|
68
87
|
logger.info("arena.start", { mode: this.config.mode, participants: participantNames });
|
|
69
88
|
signal?.throwIfAborted();
|
|
70
89
|
// ─── Phase 0: Plan ────────────────────────────────────────
|
|
71
90
|
const llmConfig = this.config.participants[0].llm;
|
|
72
|
-
const plan = await planArena(topic, llmConfig, flags, signal);
|
|
91
|
+
const plan = await planArena(topic, llmConfig, flags, signal, this.recordUsage);
|
|
73
92
|
this.config.onProgress?.({ type: "plan_resolved", plan });
|
|
74
93
|
logger.info("arena.plan", {
|
|
75
94
|
mode: plan.mode,
|
|
@@ -129,6 +148,7 @@ export class Arena {
|
|
|
129
148
|
contextTools,
|
|
130
149
|
signal,
|
|
131
150
|
onProgress: this.config.onProgress,
|
|
151
|
+
onUsage: this.recordUsage,
|
|
132
152
|
});
|
|
133
153
|
const reports = researchResults.map((r) => r.report);
|
|
134
154
|
const dossiers = researchResults.map((r) => r.dossier);
|
|
@@ -197,6 +217,7 @@ export class Arena {
|
|
|
197
217
|
mode: "planning",
|
|
198
218
|
signal,
|
|
199
219
|
onProgress: this.config.onProgress,
|
|
220
|
+
onUsage: this.recordUsage,
|
|
200
221
|
});
|
|
201
222
|
signal?.throwIfAborted();
|
|
202
223
|
// ─── Roadmap Consensus ───────────────────────────────────
|
|
@@ -212,6 +233,7 @@ export class Arena {
|
|
|
212
233
|
claimSummary,
|
|
213
234
|
signal,
|
|
214
235
|
onProgress: this.config.onProgress,
|
|
236
|
+
onUsage: this.recordUsage,
|
|
215
237
|
});
|
|
216
238
|
signal?.throwIfAborted();
|
|
217
239
|
// ─── Detail Expansion ────────────────────────────────────
|
|
@@ -229,6 +251,7 @@ export class Arena {
|
|
|
229
251
|
contextTools,
|
|
230
252
|
signal,
|
|
231
253
|
onProgress: this.config.onProgress,
|
|
254
|
+
onUsage: this.recordUsage,
|
|
232
255
|
});
|
|
233
256
|
consensus.roadmapDetails = details;
|
|
234
257
|
}
|
|
@@ -251,6 +274,7 @@ export class Arena {
|
|
|
251
274
|
claims: allClaims,
|
|
252
275
|
reviews,
|
|
253
276
|
consensus,
|
|
277
|
+
usage: { ...this.usage },
|
|
254
278
|
};
|
|
255
279
|
}
|
|
256
280
|
/**
|
|
@@ -271,6 +295,7 @@ export class Arena {
|
|
|
271
295
|
limits: this.limits,
|
|
272
296
|
signal,
|
|
273
297
|
onProgress: this.config.onProgress,
|
|
298
|
+
onUsage: this.recordUsage,
|
|
274
299
|
});
|
|
275
300
|
signal?.throwIfAborted();
|
|
276
301
|
// ─── Debate Rounds ───────────────────────────────────────
|
|
@@ -284,6 +309,7 @@ export class Arena {
|
|
|
284
309
|
maxRounds: this.config.maxDiscussionRounds,
|
|
285
310
|
signal,
|
|
286
311
|
onProgress: this.config.onProgress,
|
|
312
|
+
onUsage: this.recordUsage,
|
|
287
313
|
});
|
|
288
314
|
signal?.throwIfAborted();
|
|
289
315
|
// ─── Adjudication ────────────────────────────────────────
|
|
@@ -295,6 +321,7 @@ export class Arena {
|
|
|
295
321
|
ledger,
|
|
296
322
|
signal,
|
|
297
323
|
onProgress: this.config.onProgress,
|
|
324
|
+
onUsage: this.recordUsage,
|
|
298
325
|
});
|
|
299
326
|
signal?.throwIfAborted();
|
|
300
327
|
// ─── Consensus (claim-aware) ─────────────────────────────
|
|
@@ -314,6 +341,7 @@ export class Arena {
|
|
|
314
341
|
claimSummary,
|
|
315
342
|
signal,
|
|
316
343
|
onProgress: this.config.onProgress,
|
|
344
|
+
onUsage: this.recordUsage,
|
|
317
345
|
});
|
|
318
346
|
return {
|
|
319
347
|
topic,
|
|
@@ -328,6 +356,7 @@ export class Arena {
|
|
|
328
356
|
debateRounds,
|
|
329
357
|
adjudications,
|
|
330
358
|
consensus,
|
|
359
|
+
usage: { ...this.usage },
|
|
331
360
|
};
|
|
332
361
|
}
|
|
333
362
|
}
|
|
@@ -6,7 +6,7 @@
|
|
|
6
6
|
*
|
|
7
7
|
* Claims that were verified without contest get synthetic adjudication records.
|
|
8
8
|
*/
|
|
9
|
-
import type { ArenaParticipant, ArenaStrategy, ClaimAdjudication, ArenaProgressEvent } from "../types.js";
|
|
9
|
+
import type { ArenaParticipant, ArenaStrategy, ClaimAdjudication, ArenaProgressEvent, ArenaUsageRecorder } from "../types.js";
|
|
10
10
|
import type { ArenaLedger } from "../ledger.js";
|
|
11
11
|
interface AdjudicationOptions {
|
|
12
12
|
concluder: ArenaParticipant;
|
|
@@ -15,6 +15,7 @@ interface AdjudicationOptions {
|
|
|
15
15
|
ledger: ArenaLedger;
|
|
16
16
|
signal?: AbortSignal;
|
|
17
17
|
onProgress?: (event: ArenaProgressEvent) => void;
|
|
18
|
+
onUsage?: ArenaUsageRecorder;
|
|
18
19
|
}
|
|
19
20
|
/**
|
|
20
21
|
* Run adjudication phase. The moderator rules on contested claims.
|
|
@@ -17,7 +17,7 @@ import { logger } from "../../logging/logger.js";
|
|
|
17
17
|
* Verified claims get synthetic adjudications.
|
|
18
18
|
*/
|
|
19
19
|
export async function runAdjudication(options) {
|
|
20
|
-
const { concluder, strategy, topic, ledger, signal, onProgress } = options;
|
|
20
|
+
const { concluder, strategy, topic, ledger, signal, onProgress, onUsage } = options;
|
|
21
21
|
const allAdjudications = [];
|
|
22
22
|
const v2 = isStrategyV2(strategy);
|
|
23
23
|
// Claims that need moderator adjudication: contested or those with debate rounds
|
|
@@ -54,6 +54,7 @@ export async function runAdjudication(options) {
|
|
|
54
54
|
messages: [{ role: "user", content: userContent }],
|
|
55
55
|
signal,
|
|
56
56
|
});
|
|
57
|
+
onUsage?.(response.usage);
|
|
57
58
|
logger.info("arena.adjudication_response", {
|
|
58
59
|
claimId: claim.claimId,
|
|
59
60
|
stopReason: response.stopReason,
|
|
@@ -8,7 +8,7 @@
|
|
|
8
8
|
* In both paths, the moderator must faithfully reflect aggregated results
|
|
9
9
|
* (no new unsourced conclusions).
|
|
10
10
|
*/
|
|
11
|
-
import type { ArenaParticipant, ArenaStrategy, ParticipantReport, FindingReview, ArenaConsensus, ClaimStatusSummary, ArenaProgressEvent } from "../types.js";
|
|
11
|
+
import type { ArenaParticipant, ArenaStrategy, ParticipantReport, FindingReview, ArenaConsensus, ClaimStatusSummary, ArenaProgressEvent, ArenaUsageRecorder } from "../types.js";
|
|
12
12
|
interface ConsensusOptions {
|
|
13
13
|
/** The participant that acts as moderator/concluder */
|
|
14
14
|
concluder: ArenaParticipant;
|
|
@@ -20,6 +20,7 @@ interface ConsensusOptions {
|
|
|
20
20
|
claimSummary?: ClaimStatusSummary;
|
|
21
21
|
signal?: AbortSignal;
|
|
22
22
|
onProgress?: (event: ArenaProgressEvent) => void;
|
|
23
|
+
onUsage?: ArenaUsageRecorder;
|
|
23
24
|
}
|
|
24
25
|
/**
|
|
25
26
|
* Build structured consensus from participant reports, cross-reviews,
|
|
@@ -16,7 +16,7 @@ import { isStrategyV2 } from "../types.js";
|
|
|
16
16
|
* and optionally adjudicated claim data.
|
|
17
17
|
*/
|
|
18
18
|
export async function buildConsensus(options) {
|
|
19
|
-
const { concluder, strategy, topic, reports, reviews, claimSummary, signal, onProgress } = options;
|
|
19
|
+
const { concluder, strategy, topic, reports, reviews, claimSummary, signal, onProgress, onUsage } = options;
|
|
20
20
|
onProgress?.({ type: "consensus_start" });
|
|
21
21
|
const client = await createLLMClient(concluder.llm, concluder.clientDefaults);
|
|
22
22
|
const systemPrompt = strategy.consensusSystemPrompt();
|
|
@@ -41,6 +41,7 @@ export async function buildConsensus(options) {
|
|
|
41
41
|
messages: [{ role: "user", content: userContent }],
|
|
42
42
|
signal,
|
|
43
43
|
});
|
|
44
|
+
onUsage?.(response.usage);
|
|
44
45
|
logger.info("arena.consensus_raw_response", {
|
|
45
46
|
text: response.text,
|
|
46
47
|
stopReason: response.stopReason,
|
|
@@ -64,6 +65,7 @@ export async function buildConsensus(options) {
|
|
|
64
65
|
],
|
|
65
66
|
signal,
|
|
66
67
|
});
|
|
68
|
+
onUsage?.(retryResponse.usage);
|
|
67
69
|
logger.info("arena.consensus_retry_response", {
|
|
68
70
|
textLen: retryResponse.text?.length ?? 0,
|
|
69
71
|
stopReason: retryResponse.stopReason,
|
|
@@ -7,7 +7,7 @@
|
|
|
7
7
|
* V2 (VerificationReview): Reviewers get claim + evidence packet + digest data,
|
|
8
8
|
* and produce ClaimChallenge records that feed into the claim state machine.
|
|
9
9
|
*/
|
|
10
|
-
import type { ArenaParticipant, ArenaStrategy, ParticipantReport, FindingReview, ClaimChallenge, ArenaProgressEvent, ArenaExecutionLimits } from "../types.js";
|
|
10
|
+
import type { ArenaParticipant, ArenaStrategy, ParticipantReport, FindingReview, ClaimChallenge, ArenaProgressEvent, ArenaExecutionLimits, ArenaUsageRecorder } from "../types.js";
|
|
11
11
|
import type { ArenaLedger } from "../ledger.js";
|
|
12
12
|
interface CrossReviewOptions {
|
|
13
13
|
participants: ArenaParticipant[];
|
|
@@ -16,6 +16,7 @@ interface CrossReviewOptions {
|
|
|
16
16
|
reports: ParticipantReport[];
|
|
17
17
|
signal?: AbortSignal;
|
|
18
18
|
onProgress?: (event: ArenaProgressEvent) => void;
|
|
19
|
+
onUsage?: ArenaUsageRecorder;
|
|
19
20
|
}
|
|
20
21
|
/**
|
|
21
22
|
* Run cross-review phase (V1). Each participant reviews the others' findings.
|
|
@@ -32,6 +33,7 @@ interface VerificationReviewOptions {
|
|
|
32
33
|
mode?: "review" | "discussion" | "planning";
|
|
33
34
|
signal?: AbortSignal;
|
|
34
35
|
onProgress?: (event: ArenaProgressEvent) => void;
|
|
36
|
+
onUsage?: ArenaUsageRecorder;
|
|
35
37
|
}
|
|
36
38
|
interface VerificationReviewResult {
|
|
37
39
|
reviews: FindingReview[];
|
|
@@ -17,7 +17,7 @@ import { logger } from "../../logging/logger.js";
|
|
|
17
17
|
* Run cross-review phase (V1). Each participant reviews the others' findings.
|
|
18
18
|
*/
|
|
19
19
|
export async function runCrossReview(options) {
|
|
20
|
-
const { participants, strategy, topic, reports, signal, onProgress } = options;
|
|
20
|
+
const { participants, strategy, topic, reports, signal, onProgress, onUsage } = options;
|
|
21
21
|
onProgress?.({ type: "cross_review_start", round: 1 });
|
|
22
22
|
const allReviews = [];
|
|
23
23
|
const tasks = participants.map(async (p) => {
|
|
@@ -36,6 +36,7 @@ export async function runCrossReview(options) {
|
|
|
36
36
|
messages: [{ role: "user", content: userContent }],
|
|
37
37
|
signal,
|
|
38
38
|
});
|
|
39
|
+
onUsage?.(response.usage);
|
|
39
40
|
logger.info("arena.cross_review_raw_response", {
|
|
40
41
|
participant: p.name,
|
|
41
42
|
text: response.text,
|
|
@@ -56,6 +57,7 @@ export async function runCrossReview(options) {
|
|
|
56
57
|
],
|
|
57
58
|
signal,
|
|
58
59
|
});
|
|
60
|
+
onUsage?.(retryResponse.usage);
|
|
59
61
|
logger.info("arena.cross_review_retry", {
|
|
60
62
|
participant: p.name,
|
|
61
63
|
stopReason: retryResponse.stopReason,
|
|
@@ -76,7 +78,7 @@ export async function runCrossReview(options) {
|
|
|
76
78
|
* Falls back to V1 cross-review if strategy doesn't implement V2.
|
|
77
79
|
*/
|
|
78
80
|
export async function runVerificationReview(options) {
|
|
79
|
-
const { participants, strategy, topic, reports, ledger, limits, mode, signal, onProgress } = options;
|
|
81
|
+
const { participants, strategy, topic, reports, ledger, limits, mode, signal, onProgress, onUsage } = options;
|
|
80
82
|
// Select claims to review, prioritized by severity + confidence
|
|
81
83
|
const allClaims = ledger.getAllClaims();
|
|
82
84
|
const claimsToReview = selectClaimsForReview(allClaims, limits.maxClaimsForReview);
|
|
@@ -120,6 +122,7 @@ export async function runVerificationReview(options) {
|
|
|
120
122
|
messages: [{ role: "user", content: userContent }],
|
|
121
123
|
signal,
|
|
122
124
|
});
|
|
125
|
+
onUsage?.(response.usage);
|
|
123
126
|
logger.info("arena.verification_review_raw", {
|
|
124
127
|
participant: p.name,
|
|
125
128
|
stopReason: response.stopReason,
|
|
@@ -134,6 +137,7 @@ export async function runVerificationReview(options) {
|
|
|
134
137
|
],
|
|
135
138
|
signal,
|
|
136
139
|
});
|
|
140
|
+
onUsage?.(retryResponse.usage);
|
|
137
141
|
response = retryResponse;
|
|
138
142
|
}
|
|
139
143
|
const challenges = isPlanningMerge
|
|
@@ -163,6 +167,7 @@ export async function runVerificationReview(options) {
|
|
|
163
167
|
messages: [{ role: "user", content: userContent }],
|
|
164
168
|
signal,
|
|
165
169
|
});
|
|
170
|
+
onUsage?.(response.usage);
|
|
166
171
|
if (response.stopReason === "length") {
|
|
167
172
|
const retryResponse = await client.createMessage({
|
|
168
173
|
systemPrompt,
|
|
@@ -173,6 +178,7 @@ export async function runVerificationReview(options) {
|
|
|
173
178
|
],
|
|
174
179
|
signal,
|
|
175
180
|
});
|
|
181
|
+
onUsage?.(retryResponse.usage);
|
|
176
182
|
response = retryResponse;
|
|
177
183
|
}
|
|
178
184
|
const reviews = strategy.parseCrossReviewResponse(p.name, response.text);
|
|
@@ -7,7 +7,7 @@
|
|
|
7
7
|
* 2. Convergence check: all stances are "support" or "narrow" → resolved
|
|
8
8
|
* 3. If max rounds exhausted → stays contested for adjudication
|
|
9
9
|
*/
|
|
10
|
-
import type { ArenaParticipant, ArenaStrategy, DebateRound, ArenaExecutionLimits, ArenaProgressEvent } from "../types.js";
|
|
10
|
+
import type { ArenaParticipant, ArenaStrategy, DebateRound, ArenaExecutionLimits, ArenaProgressEvent, ArenaUsageRecorder } from "../types.js";
|
|
11
11
|
import type { ArenaLedger } from "../ledger.js";
|
|
12
12
|
interface DebateOptions {
|
|
13
13
|
participants: ArenaParticipant[];
|
|
@@ -18,6 +18,7 @@ interface DebateOptions {
|
|
|
18
18
|
maxRounds: number;
|
|
19
19
|
signal?: AbortSignal;
|
|
20
20
|
onProgress?: (event: ArenaProgressEvent) => void;
|
|
21
|
+
onUsage?: ArenaUsageRecorder;
|
|
21
22
|
}
|
|
22
23
|
/**
|
|
23
24
|
* Run debate rounds for all contested claims.
|
|
@@ -17,7 +17,7 @@ import { logger } from "../../logging/logger.js";
|
|
|
17
17
|
* Returns empty array if no contested claims exist.
|
|
18
18
|
*/
|
|
19
19
|
export async function runDebateRounds(options) {
|
|
20
|
-
const { participants, strategy, topic, ledger, limits, maxRounds, signal, onProgress } = options;
|
|
20
|
+
const { participants, strategy, topic, ledger, limits, maxRounds, signal, onProgress, onUsage } = options;
|
|
21
21
|
// Select contested claims, capped
|
|
22
22
|
const contested = ledger.getClaimsByStatus("contested")
|
|
23
23
|
.slice(0, limits.maxContestedClaimsForDebate);
|
|
@@ -44,6 +44,7 @@ export async function runDebateRounds(options) {
|
|
|
44
44
|
maxRounds,
|
|
45
45
|
signal,
|
|
46
46
|
onProgress,
|
|
47
|
+
onUsage,
|
|
47
48
|
});
|
|
48
49
|
allDebateRounds.push(...claimDebateRounds);
|
|
49
50
|
// Attach debate rounds to claim record
|
|
@@ -52,7 +53,7 @@ export async function runDebateRounds(options) {
|
|
|
52
53
|
return allDebateRounds;
|
|
53
54
|
}
|
|
54
55
|
async function debateClaim(options) {
|
|
55
|
-
const { claim, participants, strategy, v2, topic, ledger, maxRounds, signal, onProgress } = options;
|
|
56
|
+
const { claim, participants, strategy, v2, topic, ledger, maxRounds, signal, onProgress, onUsage } = options;
|
|
56
57
|
// Identify debaters: claim owner + primary challenger
|
|
57
58
|
const owner = participants.find((p) => p.name === claim.owner);
|
|
58
59
|
const primaryChallenger = findPrimaryChallenger(claim, participants);
|
|
@@ -91,6 +92,7 @@ async function debateClaim(options) {
|
|
|
91
92
|
messages: [{ role: "user", content: userContent }],
|
|
92
93
|
signal,
|
|
93
94
|
});
|
|
95
|
+
onUsage?.(response.usage);
|
|
94
96
|
logger.info("arena.debate_turn", {
|
|
95
97
|
participant: p.name,
|
|
96
98
|
claimId: claim.claimId,
|
|
@@ -5,7 +5,7 @@
|
|
|
5
5
|
* Phase 3 upgrade: now captures ToolTrace and builds EvidencePackets,
|
|
6
6
|
* outputting a full ResearchDossier alongside the ParticipantReport.
|
|
7
7
|
*/
|
|
8
|
-
import type { ArenaBaseContext, ArenaParticipant, ArenaStrategy, ParticipantReport, ResearchDossier, ArenaProgressEvent } from "../types.js";
|
|
8
|
+
import type { ArenaBaseContext, ArenaParticipant, ArenaStrategy, ParticipantReport, ResearchDossier, ArenaProgressEvent, ArenaUsageRecorder } from "../types.js";
|
|
9
9
|
import type { ToolDefinition } from "../../types.js";
|
|
10
10
|
/** Result of a single participant's research — includes both report and dossier */
|
|
11
11
|
export interface ResearchResult {
|
|
@@ -23,6 +23,7 @@ interface ResearchOptions {
|
|
|
23
23
|
/** AbortSignal — cancels in-flight LLM calls */
|
|
24
24
|
signal?: AbortSignal;
|
|
25
25
|
onProgress?: (event: ArenaProgressEvent) => void;
|
|
26
|
+
onUsage?: ArenaUsageRecorder;
|
|
26
27
|
}
|
|
27
28
|
/**
|
|
28
29
|
* Run participant research phase in parallel.
|
|
@@ -23,7 +23,7 @@ export async function runParticipantResearch(options) {
|
|
|
23
23
|
* Returns both reports (backward compat) and dossiers (evidence trail).
|
|
24
24
|
*/
|
|
25
25
|
export async function runParticipantResearchWithDossiers(options) {
|
|
26
|
-
const { participants, strategy, topic, baseContext, enableContextTools, contextTools, signal, onProgress } = options;
|
|
26
|
+
const { participants, strategy, topic, baseContext, enableContextTools, contextTools, signal, onProgress, onUsage } = options;
|
|
27
27
|
const tools = enableContextTools ? (contextTools ?? CONTEXT_TOOLS) : undefined;
|
|
28
28
|
const tasks = participants.map(async (p) => {
|
|
29
29
|
onProgress?.({ type: "research_start", participant: p.name });
|
|
@@ -57,6 +57,7 @@ export async function runParticipantResearchWithDossiers(options) {
|
|
|
57
57
|
tools,
|
|
58
58
|
signal,
|
|
59
59
|
});
|
|
60
|
+
onUsage?.(response.usage);
|
|
60
61
|
const toolNames = (response.toolCalls ?? []).map((tc) => tc.toolName);
|
|
61
62
|
const hasTools = response.toolCalls && response.toolCalls.length > 0;
|
|
62
63
|
logger.info("arena.research_round", {
|
|
@@ -158,6 +159,7 @@ export async function runParticipantResearchWithDossiers(options) {
|
|
|
158
159
|
},
|
|
159
160
|
],
|
|
160
161
|
});
|
|
162
|
+
onUsage?.(forceResponse.usage);
|
|
161
163
|
logger.info("arena.research_force_conclude_response", {
|
|
162
164
|
participant: p.name,
|
|
163
165
|
textLen: forceResponse.text?.length ?? 0,
|
|
@@ -9,7 +9,7 @@
|
|
|
9
9
|
*
|
|
10
10
|
* Tool access is available so the LLM can verify file paths and interfaces.
|
|
11
11
|
*/
|
|
12
|
-
import type { ArenaParticipant, ArenaRoadmapPhase, ArenaRoadmapPhaseDetail, ArenaProgressEvent, ArenaExecutionLimits, ArenaStrategyPlanning } from "../types.js";
|
|
12
|
+
import type { ArenaParticipant, ArenaRoadmapPhase, ArenaRoadmapPhaseDetail, ArenaProgressEvent, ArenaExecutionLimits, ArenaStrategyPlanning, ArenaUsageRecorder } from "../types.js";
|
|
13
13
|
import type { ToolDefinition } from "../../types.js";
|
|
14
14
|
import type { ArenaLedger } from "../ledger.js";
|
|
15
15
|
interface DetailExpansionOptions {
|
|
@@ -27,6 +27,7 @@ interface DetailExpansionOptions {
|
|
|
27
27
|
contextTools?: ToolDefinition[];
|
|
28
28
|
signal?: AbortSignal;
|
|
29
29
|
onProgress?: (event: ArenaProgressEvent) => void;
|
|
30
|
+
onUsage?: ArenaUsageRecorder;
|
|
30
31
|
}
|
|
31
32
|
/**
|
|
32
33
|
* Expand each roadmap phase into a repo-level implementation plan.
|
|
@@ -22,7 +22,7 @@ const MAX_EXPANSION_TOOL_ROUNDS = 3;
|
|
|
22
22
|
* The number of phases expanded is capped by limits.maxExpandedPhasesPerRun.
|
|
23
23
|
*/
|
|
24
24
|
export async function runDetailExpansion(options) {
|
|
25
|
-
const { concluder, strategy, topic, phases, ledger, limits, signal, onProgress } = options;
|
|
25
|
+
const { concluder, strategy, topic, phases, ledger, limits, signal, onProgress, onUsage } = options;
|
|
26
26
|
const tools = options.enableContextTools !== false
|
|
27
27
|
? (options.contextTools ?? CONTEXT_TOOLS)
|
|
28
28
|
: undefined;
|
|
@@ -56,6 +56,7 @@ export async function runDetailExpansion(options) {
|
|
|
56
56
|
tools: offerTools,
|
|
57
57
|
signal,
|
|
58
58
|
});
|
|
59
|
+
onUsage?.(response.usage);
|
|
59
60
|
const hasTools = response.toolCalls && response.toolCalls.length > 0;
|
|
60
61
|
logger.info("arena.detail_expansion_round", {
|
|
61
62
|
phase: phase.title,
|
package/dist/arena/planner.d.ts
CHANGED
|
@@ -12,6 +12,7 @@
|
|
|
12
12
|
* LLM call that outputs a holistic execution plan.
|
|
13
13
|
*/
|
|
14
14
|
import type { LLMConfig } from "../types.js";
|
|
15
|
+
import type { ArenaUsageRecorder } from "./types.js";
|
|
15
16
|
import type { ArenaPlan, ArenaMode } from "./types.js";
|
|
16
17
|
/** Explicit flags the user may pass via CLI or tool args */
|
|
17
18
|
export interface PlannerFlags {
|
|
@@ -24,4 +25,4 @@ export interface PlannerFlags {
|
|
|
24
25
|
*
|
|
25
26
|
* Priority: explicit flags > LLM plan > safe defaults.
|
|
26
27
|
*/
|
|
27
|
-
export declare function planArena(topic: string, llmConfig: LLMConfig, flags?: PlannerFlags, signal?: AbortSignal): Promise<ArenaPlan>;
|
|
28
|
+
export declare function planArena(topic: string, llmConfig: LLMConfig, flags?: PlannerFlags, signal?: AbortSignal, onUsage?: ArenaUsageRecorder): Promise<ArenaPlan>;
|
package/dist/arena/planner.js
CHANGED
|
@@ -58,7 +58,7 @@ Respond ONLY with JSON, no markdown fences:
|
|
|
58
58
|
*
|
|
59
59
|
* Priority: explicit flags > LLM plan > safe defaults.
|
|
60
60
|
*/
|
|
61
|
-
export async function planArena(topic, llmConfig, flags, signal) {
|
|
61
|
+
export async function planArena(topic, llmConfig, flags, signal, onUsage) {
|
|
62
62
|
// If mode and base are both explicit, we can skip the LLM call
|
|
63
63
|
if (flags?.mode && flags?.base) {
|
|
64
64
|
return buildExplicitPlan(topic, flags);
|
|
@@ -75,6 +75,7 @@ export async function planArena(topic, llmConfig, flags, signal) {
|
|
|
75
75
|
maxTokens: 1024,
|
|
76
76
|
signal,
|
|
77
77
|
});
|
|
78
|
+
onUsage?.(response.usage);
|
|
78
79
|
const plan = parsePlanResponse(response.text, topic);
|
|
79
80
|
// Explicit flags override LLM output
|
|
80
81
|
if (flags?.mode)
|
package/dist/arena/types.d.ts
CHANGED
|
@@ -3,7 +3,9 @@
|
|
|
3
3
|
*
|
|
4
4
|
* V2 architecture: shared facts → independent research → findings → cross-review → consensus.
|
|
5
5
|
*/
|
|
6
|
-
import type { ClientDefaults, LLMConfig } from "../types.js";
|
|
6
|
+
import type { ClientDefaults, LLMConfig, TokenUsage } from "../types.js";
|
|
7
|
+
/** Receives usage for each completed Arena provider request. */
|
|
8
|
+
export type ArenaUsageRecorder = (usage: TokenUsage | undefined) => void;
|
|
7
9
|
/** Arena operating mode — determines prompts, output format, and default rounds */
|
|
8
10
|
export type ArenaMode = "review" | "discussion" | "planning";
|
|
9
11
|
/** Analysis lens — the perspective from which participants analyze */
|
|
@@ -337,6 +339,8 @@ export interface ArenaResultV2 {
|
|
|
337
339
|
/** Claim adjudications (Phase 3+) */
|
|
338
340
|
adjudications?: ClaimAdjudication[];
|
|
339
341
|
consensus: ArenaConsensus;
|
|
342
|
+
/** Aggregate of every provider request made by this Arena run. */
|
|
343
|
+
usage: TokenUsage;
|
|
340
344
|
}
|
|
341
345
|
/**
|
|
342
346
|
* ArenaStrategy — encapsulates mode-specific behavior for prompts and parsing.
|
|
@@ -2,6 +2,8 @@ export type PermissionMode = "default" | "acceptEdits" | "bypassPermissions";
|
|
|
2
2
|
export interface BuildArgsOpts {
|
|
3
3
|
prompt: string;
|
|
4
4
|
resumeSessionId?: string;
|
|
5
|
+
/** Optional caller-specified model override. Passed through without validation; the CLI reports unknown models. */
|
|
6
|
+
model?: string;
|
|
5
7
|
permissionMode: PermissionMode;
|
|
6
8
|
cwd: string;
|
|
7
9
|
imagePaths?: string[];
|
|
@@ -14,6 +14,8 @@ export const claudeAdapter = {
|
|
|
14
14
|
buildArgs(opts) {
|
|
15
15
|
// -p (print/headless) + stream-json REQUIRES --verbose (verified).
|
|
16
16
|
const args = ["-p", opts.prompt, "--output-format", "stream-json", "--verbose"];
|
|
17
|
+
if (opts.model)
|
|
18
|
+
args.push("--model", opts.model);
|
|
17
19
|
if (opts.resumeSessionId)
|
|
18
20
|
args.push("--resume", opts.resumeSessionId);
|
|
19
21
|
// Hard-disallow Workflow: driving CC unattended (esp. bypassPermissions),
|
|
@@ -82,6 +84,8 @@ export const codexAdapter = {
|
|
|
82
84
|
else {
|
|
83
85
|
args.push("--sandbox", opts.permissionMode === "acceptEdits" ? "workspace-write" : "read-only");
|
|
84
86
|
}
|
|
87
|
+
if (opts.model)
|
|
88
|
+
args.push("--model", opts.model);
|
|
85
89
|
if (opts.codexImageInputSupported) {
|
|
86
90
|
for (const imagePath of opts.imagePaths ?? [])
|
|
87
91
|
args.push("-i", imagePath);
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import type { HistoryMessage } from "./session-history.js";
|
|
1
|
+
import type { HistoryMessage, SessionTailEvent } from "./session-history.js";
|
|
2
2
|
/**
|
|
3
3
|
* Read the last `limit` user/assistant messages from a codex CLI session,
|
|
4
4
|
* returning the SAME shape as the claude-side `readRecentHistory` so the room
|
|
@@ -23,3 +23,16 @@ export declare function readCodexRecentHistory(cwd: string, threadId: string, li
|
|
|
23
23
|
hasMore: boolean;
|
|
24
24
|
totalCount: number;
|
|
25
25
|
};
|
|
26
|
+
/** Parse a bounded/raw Codex rollout snapshot. Shared with the desktop tail
|
|
27
|
+
* follower so its initial history and EOF cursor are atomic. */
|
|
28
|
+
export declare function parseCodexRecentHistory(raw: string, limit: number): {
|
|
29
|
+
messages: HistoryMessage[];
|
|
30
|
+
hasMore: boolean;
|
|
31
|
+
totalCount: number;
|
|
32
|
+
};
|
|
33
|
+
/** Parse one newly-appended Codex rollout JSONL line. `response_item` is the
|
|
34
|
+
* authoritative rendered stream; parallel `event_msg.agent_message` records
|
|
35
|
+
* are deliberately ignored to avoid duplicate assistant bubbles. */
|
|
36
|
+
export declare function parseCodexTranscriptLine(line: string): SessionTailEvent[];
|
|
37
|
+
/** Find the rollout file whose `session_meta` matches both `threadId` and `cwd`. */
|
|
38
|
+
export declare function findCodexRolloutFile(codexHome: string, cwd: string, threadId: string): string | undefined;
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { readdirSync, readFileSync, statSync, existsSync, openSync, readSync, closeSync } from "node:fs";
|
|
1
|
+
import { readdirSync, readFileSync, statSync, existsSync, openSync, readSync, closeSync, } from "node:fs";
|
|
2
2
|
import { join } from "node:path";
|
|
3
3
|
import { homedir } from "node:os";
|
|
4
4
|
/**
|
|
@@ -22,7 +22,7 @@ import { homedir } from "node:os";
|
|
|
22
22
|
*/
|
|
23
23
|
export function readCodexRecentHistory(cwd, threadId, limit, codexHome = join(homedir(), ".codex")) {
|
|
24
24
|
const empty = { messages: [], hasMore: false, totalCount: 0 };
|
|
25
|
-
const file =
|
|
25
|
+
const file = findCodexRolloutFile(codexHome, cwd, threadId);
|
|
26
26
|
if (!file)
|
|
27
27
|
return empty;
|
|
28
28
|
let raw;
|
|
@@ -32,6 +32,11 @@ export function readCodexRecentHistory(cwd, threadId, limit, codexHome = join(ho
|
|
|
32
32
|
catch {
|
|
33
33
|
return empty;
|
|
34
34
|
}
|
|
35
|
+
return parseCodexRecentHistory(raw, limit);
|
|
36
|
+
}
|
|
37
|
+
/** Parse a bounded/raw Codex rollout snapshot. Shared with the desktop tail
|
|
38
|
+
* follower so its initial history and EOF cursor are atomic. */
|
|
39
|
+
export function parseCodexRecentHistory(raw, limit) {
|
|
35
40
|
const all = [];
|
|
36
41
|
for (const line of raw.split("\n")) {
|
|
37
42
|
if (!line.trim())
|
|
@@ -55,7 +60,11 @@ export function readCodexRecentHistory(cwd, threadId, limit, codexHome = join(ho
|
|
|
55
60
|
all.push({ role: p.role, text: t });
|
|
56
61
|
}
|
|
57
62
|
else if (p.type === "function_call" || p.type === "custom_tool_call") {
|
|
58
|
-
const tool = {
|
|
63
|
+
const tool = {
|
|
64
|
+
name: typeof p.name === "string" ? p.name : "tool",
|
|
65
|
+
summary: summaryOf(p),
|
|
66
|
+
args: argsOf(p),
|
|
67
|
+
};
|
|
59
68
|
const last = all[all.length - 1];
|
|
60
69
|
// Attach the tool to the preceding assistant turn; otherwise start one.
|
|
61
70
|
if (last && last.role === "assistant") {
|
|
@@ -70,6 +79,57 @@ export function readCodexRecentHistory(cwd, threadId, limit, codexHome = join(ho
|
|
|
70
79
|
const start = Math.max(0, all.length - lim);
|
|
71
80
|
return { messages: all.slice(start), hasMore: start > 0, totalCount: all.length };
|
|
72
81
|
}
|
|
82
|
+
/** Parse one newly-appended Codex rollout JSONL line. `response_item` is the
|
|
83
|
+
* authoritative rendered stream; parallel `event_msg.agent_message` records
|
|
84
|
+
* are deliberately ignored to avoid duplicate assistant bubbles. */
|
|
85
|
+
export function parseCodexTranscriptLine(line) {
|
|
86
|
+
let d;
|
|
87
|
+
try {
|
|
88
|
+
d = JSON.parse(line);
|
|
89
|
+
}
|
|
90
|
+
catch {
|
|
91
|
+
return [];
|
|
92
|
+
}
|
|
93
|
+
if (d?.type === "event_msg" && d.payload?.type === "task_complete") {
|
|
94
|
+
return [{ type: "turn_end", reason: "completed" }];
|
|
95
|
+
}
|
|
96
|
+
if (d?.type !== "response_item" || !d.payload)
|
|
97
|
+
return [];
|
|
98
|
+
const p = d.payload;
|
|
99
|
+
if (p.type === "message" && (p.role === "user" || p.role === "assistant")) {
|
|
100
|
+
const text = textOf(p.content).trim();
|
|
101
|
+
if (!text || text.startsWith("<environment_context>"))
|
|
102
|
+
return [];
|
|
103
|
+
return [{ type: p.role === "user" ? "user" : "assistant", text }];
|
|
104
|
+
}
|
|
105
|
+
if (p.type === "function_call" || p.type === "custom_tool_call") {
|
|
106
|
+
return [
|
|
107
|
+
{
|
|
108
|
+
type: "tool",
|
|
109
|
+
id: typeof p.call_id === "string" ? p.call_id : undefined,
|
|
110
|
+
name: typeof p.name === "string" ? p.name : "tool",
|
|
111
|
+
summary: summaryOf(p),
|
|
112
|
+
args: argsOf(p),
|
|
113
|
+
},
|
|
114
|
+
];
|
|
115
|
+
}
|
|
116
|
+
if (p.type === "function_call_output" || p.type === "custom_tool_call_output") {
|
|
117
|
+
const result = typeof p.output === "string"
|
|
118
|
+
? p.output
|
|
119
|
+
: typeof p.content === "string"
|
|
120
|
+
? p.content
|
|
121
|
+
: JSON.stringify(p.output ?? p.content ?? "");
|
|
122
|
+
return [
|
|
123
|
+
{
|
|
124
|
+
type: "tool_result",
|
|
125
|
+
id: typeof p.call_id === "string" ? p.call_id : undefined,
|
|
126
|
+
result: result.slice(0, 4000),
|
|
127
|
+
isError: Boolean(p.is_error),
|
|
128
|
+
},
|
|
129
|
+
];
|
|
130
|
+
}
|
|
131
|
+
return [];
|
|
132
|
+
}
|
|
73
133
|
/** Join the text of codex content parts (`input_text`/`output_text`). */
|
|
74
134
|
function textOf(content) {
|
|
75
135
|
if (typeof content === "string")
|
|
@@ -121,7 +181,7 @@ function argsOf(payload) {
|
|
|
121
181
|
return undefined;
|
|
122
182
|
}
|
|
123
183
|
/** Find the rollout file whose `session_meta` matches both `threadId` and `cwd`. */
|
|
124
|
-
function
|
|
184
|
+
export function findCodexRolloutFile(codexHome, cwd, threadId) {
|
|
125
185
|
const root = join(codexHome, "sessions");
|
|
126
186
|
if (!existsSync(root))
|
|
127
187
|
return undefined;
|