@autohq/cli 0.1.417 → 0.1.419
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/agent-bridge.js +508 -58
- package/dist/index.js +660 -131
- package/package.json +1 -1
package/dist/agent-bridge.js
CHANGED
|
@@ -652,8 +652,8 @@ var require_common = __commonJS({
|
|
|
652
652
|
}
|
|
653
653
|
return debug12;
|
|
654
654
|
}
|
|
655
|
-
function extend2(namespace,
|
|
656
|
-
const newDebug = createDebug(this.namespace + (typeof
|
|
655
|
+
function extend2(namespace, delimiter2) {
|
|
656
|
+
const newDebug = createDebug(this.namespace + (typeof delimiter2 === "undefined" ? ":" : delimiter2) + namespace);
|
|
657
657
|
newDebug.log = this.log;
|
|
658
658
|
return newDebug;
|
|
659
659
|
}
|
|
@@ -13853,8 +13853,8 @@ function emoji() {
|
|
|
13853
13853
|
}
|
|
13854
13854
|
var ipv4 = /^(?:(?:25[0-5]|2[0-4][0-9]|1[0-9][0-9]|[1-9][0-9]|[0-9])\.){3}(?:25[0-5]|2[0-4][0-9]|1[0-9][0-9]|[1-9][0-9]|[0-9])$/;
|
|
13855
13855
|
var ipv6 = /^(([0-9a-fA-F]{1,4}:){7}[0-9a-fA-F]{1,4}|([0-9a-fA-F]{1,4}:){1,7}:|([0-9a-fA-F]{1,4}:){1,6}:[0-9a-fA-F]{1,4}|([0-9a-fA-F]{1,4}:){1,5}(:[0-9a-fA-F]{1,4}){1,2}|([0-9a-fA-F]{1,4}:){1,4}(:[0-9a-fA-F]{1,4}){1,3}|([0-9a-fA-F]{1,4}:){1,3}(:[0-9a-fA-F]{1,4}){1,4}|([0-9a-fA-F]{1,4}:){1,2}(:[0-9a-fA-F]{1,4}){1,5}|[0-9a-fA-F]{1,4}:((:[0-9a-fA-F]{1,4}){1,6})|:((:[0-9a-fA-F]{1,4}){1,7}|:))$/;
|
|
13856
|
-
var mac = (
|
|
13857
|
-
const escapedDelim = escapeRegex(
|
|
13856
|
+
var mac = (delimiter2) => {
|
|
13857
|
+
const escapedDelim = escapeRegex(delimiter2 ?? ":");
|
|
13858
13858
|
return new RegExp(`^(?:[0-9A-F]{2}${escapedDelim}){5}[0-9A-F]{2}$|^(?:[0-9a-f]{2}${escapedDelim}){5}[0-9a-f]{2}$`);
|
|
13859
13859
|
};
|
|
13860
13860
|
var cidrv4 = /^((25[0-5]|2[0-4][0-9]|1[0-9][0-9]|[1-9][0-9]|[0-9])\.){3}(25[0-5]|2[0-4][0-9]|1[0-9][0-9]|[1-9][0-9]|[0-9])\/([0-9]|[1-2][0-9]|3[0-2])$/;
|
|
@@ -30820,7 +30820,7 @@ Object.assign(lookup, {
|
|
|
30820
30820
|
// package.json
|
|
30821
30821
|
var package_default = {
|
|
30822
30822
|
name: "@autohq/cli",
|
|
30823
|
-
version: "0.1.
|
|
30823
|
+
version: "0.1.419",
|
|
30824
30824
|
license: "SEE LICENSE IN README.md",
|
|
30825
30825
|
publishConfig: {
|
|
30826
30826
|
access: "public"
|
|
@@ -36414,7 +36414,8 @@ var ProjectApplySourceLocationSchema = external_exports.object({
|
|
|
36414
36414
|
name: external_exports.string().min(1),
|
|
36415
36415
|
path: external_exports.string().min(1),
|
|
36416
36416
|
file: external_exports.string().min(1),
|
|
36417
|
-
line: external_exports.number().int().positive()
|
|
36417
|
+
line: external_exports.number().int().positive(),
|
|
36418
|
+
displayPath: external_exports.string().min(1).optional()
|
|
36418
36419
|
});
|
|
36419
36420
|
var ProjectApplyRequestSchema = external_exports.object({
|
|
36420
36421
|
delete: external_exports.array(ProjectDeleteResourceSchema).default([]),
|
|
@@ -61464,6 +61465,233 @@ function uiChunk(chunk) {
|
|
|
61464
61465
|
};
|
|
61465
61466
|
}
|
|
61466
61467
|
|
|
61468
|
+
// src/commands/agent-bridge/harness/claude-code/read-state.ts
|
|
61469
|
+
import {
|
|
61470
|
+
existsSync as existsSync2,
|
|
61471
|
+
mkdirSync as mkdirSync2,
|
|
61472
|
+
readFileSync as readFileSync2,
|
|
61473
|
+
statSync,
|
|
61474
|
+
writeFileSync as writeFileSync2
|
|
61475
|
+
} from "fs";
|
|
61476
|
+
import { dirname as dirname2 } from "path";
|
|
61477
|
+
|
|
61478
|
+
// src/commands/agent-bridge/harness/claude-code/resume-store.ts
|
|
61479
|
+
import { existsSync, mkdirSync, readFileSync, writeFileSync } from "fs";
|
|
61480
|
+
import { dirname } from "path";
|
|
61481
|
+
var AGENT_BRIDGE_RUNTIME_DIR = "/tmp/auto-bridge-runtime";
|
|
61482
|
+
var CLAUDE_SESSION_RESUME_PATH = `${AGENT_BRIDGE_RUNTIME_DIR}/claude-session-id`;
|
|
61483
|
+
function fileClaudeSessionResumeStore(path2 = CLAUDE_SESSION_RESUME_PATH) {
|
|
61484
|
+
return {
|
|
61485
|
+
read(sessionId) {
|
|
61486
|
+
if (!existsSync(path2)) {
|
|
61487
|
+
return null;
|
|
61488
|
+
}
|
|
61489
|
+
const record2 = parseResumeRecord(readFileSync(path2, "utf8"));
|
|
61490
|
+
if (!record2 || record2.sessionId !== sessionId) {
|
|
61491
|
+
return null;
|
|
61492
|
+
}
|
|
61493
|
+
return record2.agentId;
|
|
61494
|
+
},
|
|
61495
|
+
write(record2) {
|
|
61496
|
+
mkdirSync(dirname(path2), { recursive: true });
|
|
61497
|
+
writeFileSync(path2, `${JSON.stringify(record2)}
|
|
61498
|
+
`, "utf8");
|
|
61499
|
+
}
|
|
61500
|
+
};
|
|
61501
|
+
}
|
|
61502
|
+
function parseResumeRecord(raw) {
|
|
61503
|
+
try {
|
|
61504
|
+
const value2 = JSON.parse(raw);
|
|
61505
|
+
if (value2 !== null && typeof value2 === "object" && "sessionId" in value2 && "agentId" in value2 && typeof value2.sessionId === "string" && typeof value2.agentId === "string" && value2.agentId.length > 0) {
|
|
61506
|
+
return { sessionId: value2.sessionId, agentId: value2.agentId };
|
|
61507
|
+
}
|
|
61508
|
+
return null;
|
|
61509
|
+
} catch {
|
|
61510
|
+
return null;
|
|
61511
|
+
}
|
|
61512
|
+
}
|
|
61513
|
+
|
|
61514
|
+
// src/commands/agent-bridge/harness/claude-code/read-state.ts
|
|
61515
|
+
var CLAUDE_READ_STATE_PATH = `${AGENT_BRIDGE_RUNTIME_DIR}/claude-read-state`;
|
|
61516
|
+
var CLAUDE_READ_STATE_MAX_ENTRIES = 256;
|
|
61517
|
+
var ClaudeReadStateTracker = class {
|
|
61518
|
+
constructor(store) {
|
|
61519
|
+
this.store = store;
|
|
61520
|
+
}
|
|
61521
|
+
store;
|
|
61522
|
+
// Most-recently-observed entries last (Map preserves insertion order, and
|
|
61523
|
+
// touches re-insert), so eviction drops the stalest observation first.
|
|
61524
|
+
entriesByPath = /* @__PURE__ */ new Map();
|
|
61525
|
+
// tool_use ids of in-flight file-tool calls, mapped to the file they target.
|
|
61526
|
+
// Cleared at each turn's terminal result so interrupted calls cannot leak.
|
|
61527
|
+
pendingFileToolUses = /* @__PURE__ */ new Map();
|
|
61528
|
+
loadedForSessionId = null;
|
|
61529
|
+
// Feed every live SDK message through here. Successful Read/Write/Edit
|
|
61530
|
+
// results commit a path+mtime observation; everything else is ignored.
|
|
61531
|
+
observe(sessionId, message) {
|
|
61532
|
+
this.ensureLoaded(sessionId);
|
|
61533
|
+
if (message.type === "result") {
|
|
61534
|
+
this.pendingFileToolUses.clear();
|
|
61535
|
+
return;
|
|
61536
|
+
}
|
|
61537
|
+
if (message.type === "assistant" && message.parent_tool_use_id === null) {
|
|
61538
|
+
for (const block of contentBlocks(message.message.content)) {
|
|
61539
|
+
const use = fileToolUse(block);
|
|
61540
|
+
if (use) {
|
|
61541
|
+
this.pendingFileToolUses.set(use.toolUseId, use.path);
|
|
61542
|
+
}
|
|
61543
|
+
}
|
|
61544
|
+
return;
|
|
61545
|
+
}
|
|
61546
|
+
if (message.type !== "user" || message.parent_tool_use_id !== null) {
|
|
61547
|
+
return;
|
|
61548
|
+
}
|
|
61549
|
+
if ("isReplay" in message && message.isReplay === true) {
|
|
61550
|
+
return;
|
|
61551
|
+
}
|
|
61552
|
+
for (const block of contentBlocks(message.message.content)) {
|
|
61553
|
+
if (block.type !== "tool_result") {
|
|
61554
|
+
continue;
|
|
61555
|
+
}
|
|
61556
|
+
const toolUseId = typeof block.tool_use_id === "string" ? block.tool_use_id : null;
|
|
61557
|
+
if (toolUseId === null) {
|
|
61558
|
+
continue;
|
|
61559
|
+
}
|
|
61560
|
+
const path2 = this.pendingFileToolUses.get(toolUseId);
|
|
61561
|
+
this.pendingFileToolUses.delete(toolUseId);
|
|
61562
|
+
if (path2 !== void 0 && block.is_error !== true) {
|
|
61563
|
+
this.commit(sessionId, path2);
|
|
61564
|
+
}
|
|
61565
|
+
}
|
|
61566
|
+
}
|
|
61567
|
+
// The seeds to replay into a fresh CLI process, stalest observation first so
|
|
61568
|
+
// the most recent reads survive any CLI-side eviction.
|
|
61569
|
+
seeds(sessionId) {
|
|
61570
|
+
this.ensureLoaded(sessionId);
|
|
61571
|
+
return [...this.entriesByPath].map(([path2, mtime]) => ({ path: path2, mtime }));
|
|
61572
|
+
}
|
|
61573
|
+
// A conversation-lineage break: the next CLI session starts with no prior
|
|
61574
|
+
// context, so nothing the model "remembers reading" exists anymore.
|
|
61575
|
+
clear(sessionId) {
|
|
61576
|
+
this.ensureLoaded(sessionId);
|
|
61577
|
+
if (this.entriesByPath.size === 0) {
|
|
61578
|
+
return;
|
|
61579
|
+
}
|
|
61580
|
+
this.entriesByPath.clear();
|
|
61581
|
+
this.persist(sessionId);
|
|
61582
|
+
}
|
|
61583
|
+
ensureLoaded(sessionId) {
|
|
61584
|
+
if (this.loadedForSessionId === sessionId) {
|
|
61585
|
+
return;
|
|
61586
|
+
}
|
|
61587
|
+
this.loadedForSessionId = sessionId;
|
|
61588
|
+
this.entriesByPath.clear();
|
|
61589
|
+
this.pendingFileToolUses.clear();
|
|
61590
|
+
for (const entry of this.store.read(sessionId) ?? []) {
|
|
61591
|
+
this.entriesByPath.set(entry.path, entry.mtime);
|
|
61592
|
+
}
|
|
61593
|
+
}
|
|
61594
|
+
commit(sessionId, path2) {
|
|
61595
|
+
let mtime;
|
|
61596
|
+
try {
|
|
61597
|
+
mtime = Math.floor(statSync(path2).mtimeMs);
|
|
61598
|
+
} catch {
|
|
61599
|
+
if (this.entriesByPath.delete(path2)) {
|
|
61600
|
+
this.persist(sessionId);
|
|
61601
|
+
}
|
|
61602
|
+
return;
|
|
61603
|
+
}
|
|
61604
|
+
this.entriesByPath.delete(path2);
|
|
61605
|
+
this.entriesByPath.set(path2, mtime);
|
|
61606
|
+
while (this.entriesByPath.size > CLAUDE_READ_STATE_MAX_ENTRIES) {
|
|
61607
|
+
const oldest = this.entriesByPath.keys().next().value;
|
|
61608
|
+
if (oldest === void 0) {
|
|
61609
|
+
break;
|
|
61610
|
+
}
|
|
61611
|
+
this.entriesByPath.delete(oldest);
|
|
61612
|
+
}
|
|
61613
|
+
this.persist(sessionId);
|
|
61614
|
+
}
|
|
61615
|
+
persist(sessionId) {
|
|
61616
|
+
this.store.write({ sessionId, entries: this.seeds(sessionId) });
|
|
61617
|
+
}
|
|
61618
|
+
};
|
|
61619
|
+
function fileClaudeReadStateStore(path2 = CLAUDE_READ_STATE_PATH) {
|
|
61620
|
+
return {
|
|
61621
|
+
read(sessionId) {
|
|
61622
|
+
if (!existsSync2(path2)) {
|
|
61623
|
+
return null;
|
|
61624
|
+
}
|
|
61625
|
+
const record2 = parseReadStateRecord(readFileSync2(path2, "utf8"));
|
|
61626
|
+
if (!record2 || record2.sessionId !== sessionId) {
|
|
61627
|
+
return null;
|
|
61628
|
+
}
|
|
61629
|
+
return record2.entries;
|
|
61630
|
+
},
|
|
61631
|
+
write(record2) {
|
|
61632
|
+
mkdirSync2(dirname2(path2), { recursive: true });
|
|
61633
|
+
writeFileSync2(path2, `${JSON.stringify(record2)}
|
|
61634
|
+
`, "utf8");
|
|
61635
|
+
}
|
|
61636
|
+
};
|
|
61637
|
+
}
|
|
61638
|
+
function fileToolUse(block) {
|
|
61639
|
+
if (block.type !== "tool_use" || typeof block.id !== "string") {
|
|
61640
|
+
return null;
|
|
61641
|
+
}
|
|
61642
|
+
const input = block.input;
|
|
61643
|
+
if (typeof input !== "object" || input === null) {
|
|
61644
|
+
return null;
|
|
61645
|
+
}
|
|
61646
|
+
const filePath = input.file_path;
|
|
61647
|
+
if (typeof filePath !== "string" || filePath.length === 0) {
|
|
61648
|
+
return null;
|
|
61649
|
+
}
|
|
61650
|
+
switch (block.name) {
|
|
61651
|
+
case "Read": {
|
|
61652
|
+
const { offset, limit } = input;
|
|
61653
|
+
if (offset !== void 0 || limit !== void 0) {
|
|
61654
|
+
return null;
|
|
61655
|
+
}
|
|
61656
|
+
return { toolUseId: block.id, path: filePath };
|
|
61657
|
+
}
|
|
61658
|
+
case "Write":
|
|
61659
|
+
case "Edit":
|
|
61660
|
+
return { toolUseId: block.id, path: filePath };
|
|
61661
|
+
default:
|
|
61662
|
+
return null;
|
|
61663
|
+
}
|
|
61664
|
+
}
|
|
61665
|
+
function contentBlocks(content) {
|
|
61666
|
+
if (!Array.isArray(content)) {
|
|
61667
|
+
return [];
|
|
61668
|
+
}
|
|
61669
|
+
return content.filter(
|
|
61670
|
+
(block) => typeof block === "object" && block !== null
|
|
61671
|
+
);
|
|
61672
|
+
}
|
|
61673
|
+
function parseReadStateRecord(raw) {
|
|
61674
|
+
try {
|
|
61675
|
+
const value2 = JSON.parse(raw);
|
|
61676
|
+
if (value2 === null || typeof value2 !== "object" || !("sessionId" in value2) || !("entries" in value2) || typeof value2.sessionId !== "string" || !Array.isArray(value2.entries)) {
|
|
61677
|
+
return null;
|
|
61678
|
+
}
|
|
61679
|
+
const entries = [];
|
|
61680
|
+
for (const entry of value2.entries) {
|
|
61681
|
+
if (entry === null || typeof entry !== "object" || typeof entry.path !== "string" || typeof entry.mtime !== "number") {
|
|
61682
|
+
return null;
|
|
61683
|
+
}
|
|
61684
|
+
entries.push({
|
|
61685
|
+
path: entry.path,
|
|
61686
|
+
mtime: entry.mtime
|
|
61687
|
+
});
|
|
61688
|
+
}
|
|
61689
|
+
return { sessionId: value2.sessionId, entries };
|
|
61690
|
+
} catch {
|
|
61691
|
+
return null;
|
|
61692
|
+
}
|
|
61693
|
+
}
|
|
61694
|
+
|
|
61467
61695
|
// ../../node_modules/@anthropic-ai/claude-agent-sdk/sdk.mjs
|
|
61468
61696
|
import { createRequire as i_ } from "module";
|
|
61469
61697
|
import { execFile as v6$ } from "child_process";
|
|
@@ -81235,6 +81463,7 @@ var CLAUDE_INTERRUPT_SETTLE_TIMEOUT_MS = 1e4;
|
|
|
81235
81463
|
var CLAUDE_INTERRUPT_ACK_TIMEOUT_MS = 1e4;
|
|
81236
81464
|
var CLAUDE_MCP_REGISTRATION_TIMEOUT_MS = 3e3;
|
|
81237
81465
|
var CLAUDE_MCP_REGISTRATION_POLL_INTERVAL_MS = 100;
|
|
81466
|
+
var CLAUDE_READ_STATE_SEED_FAILURE_LIMIT = 3;
|
|
81238
81467
|
var CLAUDE_STARTUP_PROFILE_HOOK_EVENTS = [
|
|
81239
81468
|
"Setup",
|
|
81240
81469
|
"SessionStart",
|
|
@@ -81451,6 +81680,32 @@ var ClaudeAgentBridgeSessionImpl = class {
|
|
|
81451
81680
|
}
|
|
81452
81681
|
);
|
|
81453
81682
|
}
|
|
81683
|
+
async seedReadState(seeds) {
|
|
81684
|
+
if (seeds.length === 0 || this.state.kind !== "running") {
|
|
81685
|
+
return;
|
|
81686
|
+
}
|
|
81687
|
+
const query = this.state.query;
|
|
81688
|
+
const startedAt = Date.now();
|
|
81689
|
+
let seeded = 0;
|
|
81690
|
+
let failed = 0;
|
|
81691
|
+
for (const seed of seeds) {
|
|
81692
|
+
try {
|
|
81693
|
+
await query.seedReadState(seed.path, seed.mtime);
|
|
81694
|
+
seeded += 1;
|
|
81695
|
+
} catch (error51) {
|
|
81696
|
+
failed += 1;
|
|
81697
|
+
this.input.writeOutput?.(
|
|
81698
|
+
`agent_bridge_claude_read_state_seed_failed path=${seed.path} error=${error51 instanceof Error ? error51.message : String(error51)}`
|
|
81699
|
+
);
|
|
81700
|
+
if (failed >= CLAUDE_READ_STATE_SEED_FAILURE_LIMIT) {
|
|
81701
|
+
break;
|
|
81702
|
+
}
|
|
81703
|
+
}
|
|
81704
|
+
}
|
|
81705
|
+
this.input.writeOutput?.(
|
|
81706
|
+
`agent_bridge_claude_read_state_seeded seeded=${seeded} total=${seeds.length} duration_ms=${Date.now() - startedAt}`
|
|
81707
|
+
);
|
|
81708
|
+
}
|
|
81454
81709
|
close() {
|
|
81455
81710
|
const previousState = this.state;
|
|
81456
81711
|
if (previousState.kind === "closed") {
|
|
@@ -81512,6 +81767,7 @@ var ClaudeAgentBridgeSessionImpl = class {
|
|
|
81512
81767
|
this.input.writeOutput?.(
|
|
81513
81768
|
`agent_bridge_claude_resume_fallback session_id=${resume}`
|
|
81514
81769
|
);
|
|
81770
|
+
this.input.onResumeFallback?.();
|
|
81515
81771
|
this.state = { kind: "idle" };
|
|
81516
81772
|
return this.startSdkSession();
|
|
81517
81773
|
}
|
|
@@ -82116,7 +82372,7 @@ function isClaudeAgentTurnResult(message) {
|
|
|
82116
82372
|
}
|
|
82117
82373
|
function toolUseIds(message) {
|
|
82118
82374
|
if (message.type === "assistant") {
|
|
82119
|
-
return
|
|
82375
|
+
return contentBlocks2(message.message.content).flatMap(
|
|
82120
82376
|
(block2) => block2.type === "tool_use" && typeof block2.id === "string" ? [block2.id] : []
|
|
82121
82377
|
);
|
|
82122
82378
|
}
|
|
@@ -82134,11 +82390,11 @@ function toolResultIds(message) {
|
|
|
82134
82390
|
if (message.type !== "user") {
|
|
82135
82391
|
return [];
|
|
82136
82392
|
}
|
|
82137
|
-
return
|
|
82393
|
+
return contentBlocks2(message.message.content).flatMap(
|
|
82138
82394
|
(block) => block.type === "tool_result" && typeof block.tool_use_id === "string" ? [block.tool_use_id] : []
|
|
82139
82395
|
);
|
|
82140
82396
|
}
|
|
82141
|
-
function
|
|
82397
|
+
function contentBlocks2(content) {
|
|
82142
82398
|
if (!Array.isArray(content)) {
|
|
82143
82399
|
return [];
|
|
82144
82400
|
}
|
|
@@ -82147,42 +82403,6 @@ function contentBlocks(content) {
|
|
|
82147
82403
|
);
|
|
82148
82404
|
}
|
|
82149
82405
|
|
|
82150
|
-
// src/commands/agent-bridge/harness/claude-code/resume-store.ts
|
|
82151
|
-
import { existsSync as existsSync2, mkdirSync as mkdirSync2, readFileSync as readFileSync2, writeFileSync } from "fs";
|
|
82152
|
-
import { dirname } from "path";
|
|
82153
|
-
var AGENT_BRIDGE_RUNTIME_DIR = "/tmp/auto-bridge-runtime";
|
|
82154
|
-
var CLAUDE_SESSION_RESUME_PATH = `${AGENT_BRIDGE_RUNTIME_DIR}/claude-session-id`;
|
|
82155
|
-
function fileClaudeSessionResumeStore(path2 = CLAUDE_SESSION_RESUME_PATH) {
|
|
82156
|
-
return {
|
|
82157
|
-
read(sessionId) {
|
|
82158
|
-
if (!existsSync2(path2)) {
|
|
82159
|
-
return null;
|
|
82160
|
-
}
|
|
82161
|
-
const record2 = parseResumeRecord(readFileSync2(path2, "utf8"));
|
|
82162
|
-
if (!record2 || record2.sessionId !== sessionId) {
|
|
82163
|
-
return null;
|
|
82164
|
-
}
|
|
82165
|
-
return record2.agentId;
|
|
82166
|
-
},
|
|
82167
|
-
write(record2) {
|
|
82168
|
-
mkdirSync2(dirname(path2), { recursive: true });
|
|
82169
|
-
writeFileSync(path2, `${JSON.stringify(record2)}
|
|
82170
|
-
`, "utf8");
|
|
82171
|
-
}
|
|
82172
|
-
};
|
|
82173
|
-
}
|
|
82174
|
-
function parseResumeRecord(raw) {
|
|
82175
|
-
try {
|
|
82176
|
-
const value2 = JSON.parse(raw);
|
|
82177
|
-
if (value2 !== null && typeof value2 === "object" && "sessionId" in value2 && "agentId" in value2 && typeof value2.sessionId === "string" && typeof value2.agentId === "string" && value2.agentId.length > 0) {
|
|
82178
|
-
return { sessionId: value2.sessionId, agentId: value2.agentId };
|
|
82179
|
-
}
|
|
82180
|
-
return null;
|
|
82181
|
-
} catch {
|
|
82182
|
-
return null;
|
|
82183
|
-
}
|
|
82184
|
-
}
|
|
82185
|
-
|
|
82186
82406
|
// src/commands/agent-bridge/harness/claude-code/index.ts
|
|
82187
82407
|
function createClaudeCodeCommandHandler(input) {
|
|
82188
82408
|
return new ClaudeCodeCommandHandler(input);
|
|
@@ -82192,6 +82412,7 @@ var ClaudeCodeCommandHandler = class {
|
|
|
82192
82412
|
this.input = input;
|
|
82193
82413
|
this.claudeConfig = input.claude;
|
|
82194
82414
|
this.outputBuffer = new AgentBridgeOutputBuffer(input);
|
|
82415
|
+
this.readState = input.readState ? new ClaudeReadStateTracker(input.readState) : null;
|
|
82195
82416
|
}
|
|
82196
82417
|
input;
|
|
82197
82418
|
context = null;
|
|
@@ -82213,6 +82434,7 @@ var ClaudeCodeCommandHandler = class {
|
|
|
82213
82434
|
pendingQuestions = /* @__PURE__ */ new Map();
|
|
82214
82435
|
outputBuffer;
|
|
82215
82436
|
projector = new ClaudeCodeProjector();
|
|
82437
|
+
readState;
|
|
82216
82438
|
livenessTicker = null;
|
|
82217
82439
|
// -----------------------------------------------------------------------------
|
|
82218
82440
|
// Lifecycle (public API)
|
|
@@ -82589,6 +82811,7 @@ var ClaudeCodeCommandHandler = class {
|
|
|
82589
82811
|
return;
|
|
82590
82812
|
}
|
|
82591
82813
|
this.persistAgentId(activeContext, message);
|
|
82814
|
+
this.trackReadState(activeContext, message);
|
|
82592
82815
|
let projections;
|
|
82593
82816
|
try {
|
|
82594
82817
|
projections = this.projector.project(message);
|
|
@@ -82652,6 +82875,31 @@ var ClaudeCodeCommandHandler = class {
|
|
|
82652
82875
|
);
|
|
82653
82876
|
}
|
|
82654
82877
|
}
|
|
82878
|
+
// Observes file-tool results into the read-state tracker and replays the
|
|
82879
|
+
// tracked seeds whenever a fresh CLI cache appears: a new process's `init`
|
|
82880
|
+
// (runtime restart, selection change, CLI-internal fork — all resume the
|
|
82881
|
+
// conversation but start with an empty readFileState) and compaction
|
|
82882
|
+
// boundaries (which can evict prior reads). Seeding is fire-and-forget:
|
|
82883
|
+
// a failed seed degrades to today's behavior, a fresh Read before writing.
|
|
82884
|
+
trackReadState(activeContext, message) {
|
|
82885
|
+
const tracker = this.readState;
|
|
82886
|
+
if (!tracker) {
|
|
82887
|
+
return;
|
|
82888
|
+
}
|
|
82889
|
+
if (message.type === "system" && (message.subtype === "init" || message.subtype === "compact_boundary")) {
|
|
82890
|
+
const seeds = tracker.seeds(activeContext.sessionId);
|
|
82891
|
+
if (seeds.length === 0) {
|
|
82892
|
+
return;
|
|
82893
|
+
}
|
|
82894
|
+
this.agentSession?.seedReadState(seeds).catch((error51) => {
|
|
82895
|
+
this.input.writeOutput?.(
|
|
82896
|
+
`agent_bridge_claude_read_state_seed_failed error=${error51 instanceof Error ? error51.message : String(error51)}`
|
|
82897
|
+
);
|
|
82898
|
+
});
|
|
82899
|
+
return;
|
|
82900
|
+
}
|
|
82901
|
+
tracker.observe(activeContext.sessionId, message);
|
|
82902
|
+
}
|
|
82655
82903
|
storedResumeAgentId() {
|
|
82656
82904
|
const store = this.input.sessionResume;
|
|
82657
82905
|
const activeContext = this.context;
|
|
@@ -82681,10 +82929,18 @@ var ClaudeCodeCommandHandler = class {
|
|
|
82681
82929
|
"Cannot restart Claude Code for a model/effort selection change without a session id to resume"
|
|
82682
82930
|
);
|
|
82683
82931
|
}
|
|
82932
|
+
if (!resumeAgentId && this.context) {
|
|
82933
|
+
this.readState?.clear(this.context.sessionId);
|
|
82934
|
+
}
|
|
82684
82935
|
const session = claudeAgentBridgeRuntime.start({
|
|
82685
82936
|
claude: this.claudeConfig,
|
|
82686
82937
|
resumeAgentId,
|
|
82687
82938
|
...resumeRequired ? { allowResumeFallback: false } : {},
|
|
82939
|
+
onResumeFallback: () => {
|
|
82940
|
+
if (this.context) {
|
|
82941
|
+
this.readState?.clear(this.context.sessionId);
|
|
82942
|
+
}
|
|
82943
|
+
},
|
|
82688
82944
|
canUseTool: this.canUseTool,
|
|
82689
82945
|
onMessage: (message, meta3) => this.handleAgentMessage(message, meta3),
|
|
82690
82946
|
onError: (error51) => this.handleAgentError(error51),
|
|
@@ -83097,25 +83353,25 @@ function normalizeChunk(chunk) {
|
|
|
83097
83353
|
}
|
|
83098
83354
|
|
|
83099
83355
|
// src/commands/agent-bridge/harness/codex/resume-store.ts
|
|
83100
|
-
import { existsSync as
|
|
83101
|
-
import { dirname as
|
|
83356
|
+
import { existsSync as existsSync4, mkdirSync as mkdirSync4, readFileSync as readFileSync4, writeFileSync as writeFileSync3 } from "fs";
|
|
83357
|
+
import { dirname as dirname3 } from "path";
|
|
83102
83358
|
var AGENT_BRIDGE_RUNTIME_DIR2 = "/tmp/auto-bridge-runtime";
|
|
83103
83359
|
var CODEX_THREAD_RESUME_PATH = `${AGENT_BRIDGE_RUNTIME_DIR2}/codex-thread-id`;
|
|
83104
83360
|
function fileCodexThreadResumeStore(path2 = CODEX_THREAD_RESUME_PATH) {
|
|
83105
83361
|
return {
|
|
83106
83362
|
read(sessionId) {
|
|
83107
|
-
if (!
|
|
83363
|
+
if (!existsSync4(path2)) {
|
|
83108
83364
|
return null;
|
|
83109
83365
|
}
|
|
83110
|
-
const record2 = parseResumeRecord2(
|
|
83366
|
+
const record2 = parseResumeRecord2(readFileSync4(path2, "utf8"));
|
|
83111
83367
|
if (!record2 || record2.sessionId !== sessionId) {
|
|
83112
83368
|
return null;
|
|
83113
83369
|
}
|
|
83114
83370
|
return record2.threadId;
|
|
83115
83371
|
},
|
|
83116
83372
|
write(record2) {
|
|
83117
|
-
|
|
83118
|
-
|
|
83373
|
+
mkdirSync4(dirname3(path2), { recursive: true });
|
|
83374
|
+
writeFileSync3(path2, `${JSON.stringify(record2)}
|
|
83119
83375
|
`, "utf8");
|
|
83120
83376
|
}
|
|
83121
83377
|
};
|
|
@@ -83134,8 +83390,26 @@ function parseResumeRecord2(raw) {
|
|
|
83134
83390
|
|
|
83135
83391
|
// src/commands/agent-bridge/harness/codex/session.ts
|
|
83136
83392
|
import { spawn } from "child_process";
|
|
83137
|
-
import { mkdirSync as
|
|
83138
|
-
import { join as
|
|
83393
|
+
import { mkdirSync as mkdirSync5, writeFileSync as writeFileSync5 } from "fs";
|
|
83394
|
+
import { join as join3 } from "path";
|
|
83395
|
+
|
|
83396
|
+
// src/commands/agent-bridge/harness/codex/edit-capability.ts
|
|
83397
|
+
import { execFileSync } from "child_process";
|
|
83398
|
+
import {
|
|
83399
|
+
constants,
|
|
83400
|
+
accessSync,
|
|
83401
|
+
existsSync as existsSync5,
|
|
83402
|
+
lstatSync as lstatSync2,
|
|
83403
|
+
mkdtempSync,
|
|
83404
|
+
readFileSync as readFileSync5,
|
|
83405
|
+
realpathSync as realpathSync2,
|
|
83406
|
+
rmSync as rmSync2,
|
|
83407
|
+
symlinkSync as symlinkSync2,
|
|
83408
|
+
unlinkSync as unlinkSync2,
|
|
83409
|
+
writeFileSync as writeFileSync4
|
|
83410
|
+
} from "fs";
|
|
83411
|
+
import { tmpdir } from "os";
|
|
83412
|
+
import { delimiter, dirname as dirname4, join as join2 } from "path";
|
|
83139
83413
|
|
|
83140
83414
|
// src/commands/agent-bridge/harness/codex/options.ts
|
|
83141
83415
|
import { join } from "path";
|
|
@@ -83277,6 +83551,172 @@ function tomlString(value2) {
|
|
|
83277
83551
|
return `"${value2.replace(/\\/g, "\\\\").replace(/"/g, '\\"')}"`;
|
|
83278
83552
|
}
|
|
83279
83553
|
|
|
83554
|
+
// src/commands/agent-bridge/harness/codex/edit-capability.ts
|
|
83555
|
+
var CODEX_APPLY_PATCH_ALIAS = "apply_patch";
|
|
83556
|
+
var CODEX_EDIT_PROBE = {
|
|
83557
|
+
fileName: "probe.txt",
|
|
83558
|
+
before: "codex-edit-probe\n",
|
|
83559
|
+
after: "codex-edit-probe-ok\n",
|
|
83560
|
+
patch: [
|
|
83561
|
+
"*** Begin Patch",
|
|
83562
|
+
"*** Update File: probe.txt",
|
|
83563
|
+
"@@",
|
|
83564
|
+
"-codex-edit-probe",
|
|
83565
|
+
"+codex-edit-probe-ok",
|
|
83566
|
+
"*** End Patch"
|
|
83567
|
+
].join("\n")
|
|
83568
|
+
};
|
|
83569
|
+
var PROBE_TIMEOUT_MS = 15e3;
|
|
83570
|
+
var MAX_EVIDENCE_LENGTH = 300;
|
|
83571
|
+
var CODEX_PLATFORM_VENDOR_TARGETS = {
|
|
83572
|
+
linux: {
|
|
83573
|
+
x64: "x86_64-unknown-linux-musl",
|
|
83574
|
+
arm64: "aarch64-unknown-linux-musl"
|
|
83575
|
+
},
|
|
83576
|
+
darwin: {
|
|
83577
|
+
x64: "x86_64-apple-darwin",
|
|
83578
|
+
arm64: "aarch64-apple-darwin"
|
|
83579
|
+
}
|
|
83580
|
+
};
|
|
83581
|
+
function ensureCodexEditCapability(input) {
|
|
83582
|
+
if (input.command !== CODEX_EXECUTABLE_PATH) {
|
|
83583
|
+
input.writeOutput?.(
|
|
83584
|
+
"agent_bridge_codex_edit_capability status=skipped reason=command_override"
|
|
83585
|
+
);
|
|
83586
|
+
return;
|
|
83587
|
+
}
|
|
83588
|
+
const startedAt = Date.now();
|
|
83589
|
+
const layout = runStep(input, "resolve", () => resolveCodexVendorLayout());
|
|
83590
|
+
const status = runStep(
|
|
83591
|
+
input,
|
|
83592
|
+
"provision",
|
|
83593
|
+
() => provisionApplyPatchAlias(layout)
|
|
83594
|
+
);
|
|
83595
|
+
const alias = join2(layout.codexPathDir, CODEX_APPLY_PATCH_ALIAS);
|
|
83596
|
+
runStep(input, "verify", () => verifyApplyPatchAlias(alias));
|
|
83597
|
+
input.writeOutput?.(
|
|
83598
|
+
`agent_bridge_codex_edit_capability status=${status} alias=${alias} duration_ms=${Date.now() - startedAt}`
|
|
83599
|
+
);
|
|
83600
|
+
}
|
|
83601
|
+
function codexEditFallthroughMarker(item) {
|
|
83602
|
+
if (item.type !== "commandExecution" || item.exitCode !== 127) {
|
|
83603
|
+
return null;
|
|
83604
|
+
}
|
|
83605
|
+
const output = item.aggregatedOutput ?? "";
|
|
83606
|
+
if (!/apply_patch: (command )?not found/.test(output)) {
|
|
83607
|
+
return null;
|
|
83608
|
+
}
|
|
83609
|
+
return `agent_bridge_codex_edit_fallthrough item_id=${item.id} exit_code=127`;
|
|
83610
|
+
}
|
|
83611
|
+
function resolveCodexVendorLayout() {
|
|
83612
|
+
const wrapper = whichOnPath(CODEX_EXECUTABLE_PATH);
|
|
83613
|
+
if (!wrapper) {
|
|
83614
|
+
throw new Error("codex executable not found on PATH");
|
|
83615
|
+
}
|
|
83616
|
+
const target = CODEX_PLATFORM_VENDOR_TARGETS[process.platform]?.[process.arch];
|
|
83617
|
+
if (!target) {
|
|
83618
|
+
throw new Error(
|
|
83619
|
+
`unsupported platform for codex vendor layout: ${process.platform}/${process.arch}`
|
|
83620
|
+
);
|
|
83621
|
+
}
|
|
83622
|
+
const packageRoot = join2(dirname4(realpathSync2(wrapper)), "..");
|
|
83623
|
+
const platformPackage = `@openai/codex-${platformPackageSuffix()}`;
|
|
83624
|
+
const candidates = [
|
|
83625
|
+
join2(packageRoot, "node_modules", platformPackage, "vendor", target),
|
|
83626
|
+
join2(packageRoot, "vendor", target)
|
|
83627
|
+
];
|
|
83628
|
+
for (const vendorDir of candidates) {
|
|
83629
|
+
const binary = join2(vendorDir, "bin", "codex");
|
|
83630
|
+
const codexPathDir = join2(vendorDir, "codex-path");
|
|
83631
|
+
if (existsSync5(binary) && existsSync5(codexPathDir)) {
|
|
83632
|
+
return { binary, codexPathDir };
|
|
83633
|
+
}
|
|
83634
|
+
}
|
|
83635
|
+
throw new Error(
|
|
83636
|
+
`codex vendor layout not found (wrapper=${wrapper} candidates=${candidates.join(",")})`
|
|
83637
|
+
);
|
|
83638
|
+
}
|
|
83639
|
+
function platformPackageSuffix() {
|
|
83640
|
+
const os = process.platform === "darwin" ? "darwin" : "linux";
|
|
83641
|
+
return `${os}-${process.arch}`;
|
|
83642
|
+
}
|
|
83643
|
+
function whichOnPath(command) {
|
|
83644
|
+
for (const dir of (process.env.PATH ?? "").split(delimiter)) {
|
|
83645
|
+
if (!dir) {
|
|
83646
|
+
continue;
|
|
83647
|
+
}
|
|
83648
|
+
const candidate = join2(dir, command);
|
|
83649
|
+
try {
|
|
83650
|
+
accessSync(candidate, constants.X_OK);
|
|
83651
|
+
return candidate;
|
|
83652
|
+
} catch {
|
|
83653
|
+
}
|
|
83654
|
+
}
|
|
83655
|
+
return null;
|
|
83656
|
+
}
|
|
83657
|
+
function provisionApplyPatchAlias(layout) {
|
|
83658
|
+
const alias = join2(layout.codexPathDir, CODEX_APPLY_PATCH_ALIAS);
|
|
83659
|
+
if (aliasResolvesToBinary(alias, layout.binary)) {
|
|
83660
|
+
return "present";
|
|
83661
|
+
}
|
|
83662
|
+
if (lstatExists(alias)) {
|
|
83663
|
+
unlinkSync2(alias);
|
|
83664
|
+
}
|
|
83665
|
+
symlinkSync2(layout.binary, alias);
|
|
83666
|
+
return "provisioned";
|
|
83667
|
+
}
|
|
83668
|
+
function aliasResolvesToBinary(alias, binary) {
|
|
83669
|
+
try {
|
|
83670
|
+
return realpathSync2(alias) === realpathSync2(binary);
|
|
83671
|
+
} catch {
|
|
83672
|
+
return false;
|
|
83673
|
+
}
|
|
83674
|
+
}
|
|
83675
|
+
function lstatExists(path2) {
|
|
83676
|
+
try {
|
|
83677
|
+
lstatSync2(path2);
|
|
83678
|
+
return true;
|
|
83679
|
+
} catch {
|
|
83680
|
+
return false;
|
|
83681
|
+
}
|
|
83682
|
+
}
|
|
83683
|
+
function verifyApplyPatchAlias(alias) {
|
|
83684
|
+
const scratch = mkdtempSync(join2(tmpdir(), "codex-edit-probe-"));
|
|
83685
|
+
try {
|
|
83686
|
+
const probeFile = join2(scratch, CODEX_EDIT_PROBE.fileName);
|
|
83687
|
+
writeFileSync4(probeFile, CODEX_EDIT_PROBE.before);
|
|
83688
|
+
execFileSync(alias, [CODEX_EDIT_PROBE.patch], {
|
|
83689
|
+
cwd: scratch,
|
|
83690
|
+
stdio: ["ignore", "pipe", "pipe"],
|
|
83691
|
+
timeout: PROBE_TIMEOUT_MS
|
|
83692
|
+
});
|
|
83693
|
+
const applied = readFileSync5(probeFile, "utf8");
|
|
83694
|
+
if (applied !== CODEX_EDIT_PROBE.after) {
|
|
83695
|
+
throw new Error("probe patch did not apply the expected content");
|
|
83696
|
+
}
|
|
83697
|
+
} finally {
|
|
83698
|
+
rmSync2(scratch, { recursive: true, force: true });
|
|
83699
|
+
}
|
|
83700
|
+
}
|
|
83701
|
+
function runStep(input, step, action) {
|
|
83702
|
+
try {
|
|
83703
|
+
return action();
|
|
83704
|
+
} catch (error51) {
|
|
83705
|
+
const detail = boundedEvidence(error51);
|
|
83706
|
+
input.writeOutput?.(
|
|
83707
|
+
`agent_bridge_codex_edit_capability status=failed step=${step} error=${detail}`
|
|
83708
|
+
);
|
|
83709
|
+
throw new Error(
|
|
83710
|
+
`Codex edit capability unavailable at ${step}: ${detail}. Codex 0.141.0 declares no apply_patch tool; without the codex-path alias, exec invocations the interceptor does not recognize fail with command-not-found (codex-runtime-tool-loss-diagnostics).`
|
|
83711
|
+
);
|
|
83712
|
+
}
|
|
83713
|
+
}
|
|
83714
|
+
function boundedEvidence(error51) {
|
|
83715
|
+
const message = error51 instanceof Error ? error51.message : String(error51);
|
|
83716
|
+
const flattened = message.replace(/\s+/g, " ").trim();
|
|
83717
|
+
return flattened.length > MAX_EVIDENCE_LENGTH ? `${flattened.slice(0, MAX_EVIDENCE_LENGTH)}\u2026` : flattened;
|
|
83718
|
+
}
|
|
83719
|
+
|
|
83280
83720
|
// src/commands/agent-bridge/harness/codex/turn-retry.ts
|
|
83281
83721
|
var MAX_CODEX_TURN_RETRY_ATTEMPTS = 3;
|
|
83282
83722
|
var MAX_CODEX_TURN_RETRY_TOTAL_DELAY_MS = 3e4;
|
|
@@ -83510,12 +83950,16 @@ var CodexAgentBridgeSessionImpl = class {
|
|
|
83510
83950
|
}
|
|
83511
83951
|
async start() {
|
|
83512
83952
|
const options = codexLaunchOptions(this.input.codex);
|
|
83513
|
-
|
|
83514
|
-
|
|
83953
|
+
mkdirSync5(options.codexHome, { recursive: true });
|
|
83954
|
+
writeFileSync5(join3(options.codexHome, "config.toml"), options.configToml);
|
|
83515
83955
|
const startedAt = Date.now();
|
|
83516
83956
|
this.input.writeOutput?.(
|
|
83517
83957
|
`agent_bridge_codex_startup_started codex_home=${options.codexHome}`
|
|
83518
83958
|
);
|
|
83959
|
+
ensureCodexEditCapability({
|
|
83960
|
+
command: options.command,
|
|
83961
|
+
...this.input.writeOutput ? { writeOutput: this.input.writeOutput } : {}
|
|
83962
|
+
});
|
|
83519
83963
|
const proc = spawn(options.command, options.args, {
|
|
83520
83964
|
env: options.env,
|
|
83521
83965
|
stdio: ["pipe", "pipe", "pipe"]
|
|
@@ -83915,12 +84359,17 @@ var CodexAgentBridgeSessionImpl = class {
|
|
|
83915
84359
|
this.pendingToolItemIds.add(notification.item.id);
|
|
83916
84360
|
}
|
|
83917
84361
|
return;
|
|
83918
|
-
case "itemCompleted":
|
|
84362
|
+
case "itemCompleted": {
|
|
84363
|
+
const fallthrough = codexEditFallthroughMarker(notification.item);
|
|
84364
|
+
if (fallthrough) {
|
|
84365
|
+
this.input.writeOutput?.(fallthrough);
|
|
84366
|
+
}
|
|
83919
84367
|
this.pendingToolItemIds.delete(notification.item.id);
|
|
83920
84368
|
if (this.pendingToolItemIds.size === 0) {
|
|
83921
84369
|
this.resolveSettlement();
|
|
83922
84370
|
}
|
|
83923
84371
|
return;
|
|
84372
|
+
}
|
|
83924
84373
|
default:
|
|
83925
84374
|
return;
|
|
83926
84375
|
}
|
|
@@ -84405,6 +84854,7 @@ function createHarnessCommandHandler(input) {
|
|
|
84405
84854
|
return createClaudeCodeCommandHandler({
|
|
84406
84855
|
...base,
|
|
84407
84856
|
claude,
|
|
84857
|
+
readState: fileClaudeReadStateStore(),
|
|
84408
84858
|
sessionResume: fileClaudeSessionResumeStore()
|
|
84409
84859
|
});
|
|
84410
84860
|
}
|
|
@@ -84626,7 +85076,7 @@ function bridgeUrlHost(bridgeUrl) {
|
|
|
84626
85076
|
}
|
|
84627
85077
|
|
|
84628
85078
|
// src/lib/entrypoint.ts
|
|
84629
|
-
import { realpathSync as
|
|
85079
|
+
import { realpathSync as realpathSync3 } from "fs";
|
|
84630
85080
|
import { pathToFileURL } from "url";
|
|
84631
85081
|
function isCliEntrypoint(input) {
|
|
84632
85082
|
if (input.entrypoint.kind === "missing") {
|
|
@@ -84634,7 +85084,7 @@ function isCliEntrypoint(input) {
|
|
|
84634
85084
|
}
|
|
84635
85085
|
let resolvedEntrypoint;
|
|
84636
85086
|
try {
|
|
84637
|
-
resolvedEntrypoint =
|
|
85087
|
+
resolvedEntrypoint = realpathSync3(input.entrypoint.path);
|
|
84638
85088
|
} catch {
|
|
84639
85089
|
return false;
|
|
84640
85090
|
}
|