@autohq/cli 0.1.225 → 0.1.227
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 +1235 -5
- package/dist/index.js +1413 -164
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -15966,12 +15966,12 @@ function parseClaudeCodeStreamRecord(parsed) {
|
|
|
15966
15966
|
}
|
|
15967
15967
|
const isError = record2.is_error === true || record2.subtype === "error";
|
|
15968
15968
|
const sdkErrorMessage = record2.errors?.map((error51) => error51.trim()).filter(Boolean).join("\n");
|
|
15969
|
-
const
|
|
15969
|
+
const errorMessage6 = isError ? record2.error ?? record2.result ?? (sdkErrorMessage || void 0) ?? "claude-code reported an error" : void 0;
|
|
15970
15970
|
return {
|
|
15971
15971
|
projections: [],
|
|
15972
15972
|
result: {
|
|
15973
15973
|
isError,
|
|
15974
|
-
errorMessage:
|
|
15974
|
+
errorMessage: errorMessage6
|
|
15975
15975
|
}
|
|
15976
15976
|
};
|
|
15977
15977
|
}
|
|
@@ -16200,7 +16200,249 @@ var init_claude_code = __esm({
|
|
|
16200
16200
|
});
|
|
16201
16201
|
|
|
16202
16202
|
// ../../packages/schemas/src/codex.ts
|
|
16203
|
-
|
|
16203
|
+
function parseCodexServerFrame(raw) {
|
|
16204
|
+
const frame = CodexFrameSchema.parse(raw);
|
|
16205
|
+
if (frame.method === void 0 && frame.id !== void 0) {
|
|
16206
|
+
return {
|
|
16207
|
+
kind: "response",
|
|
16208
|
+
id: frame.id,
|
|
16209
|
+
...frame.result !== void 0 ? { result: toJsonValue(frame.result) } : {},
|
|
16210
|
+
...frame.error?.message ? { error: frame.error.message } : {}
|
|
16211
|
+
};
|
|
16212
|
+
}
|
|
16213
|
+
if (frame.method === void 0) {
|
|
16214
|
+
return { kind: "ignored" };
|
|
16215
|
+
}
|
|
16216
|
+
if (frame.id !== void 0) {
|
|
16217
|
+
return classifyServerRequest(frame.method, frame.id, frame.params);
|
|
16218
|
+
}
|
|
16219
|
+
const notification = parseNotification(frame.method, frame.params);
|
|
16220
|
+
return notification ? { kind: "notification", notification } : { kind: "ignored" };
|
|
16221
|
+
}
|
|
16222
|
+
function projectCodexItem(input) {
|
|
16223
|
+
const { item, phase } = input;
|
|
16224
|
+
switch (item.type) {
|
|
16225
|
+
case "agentMessage":
|
|
16226
|
+
return phase === "completed" && item.text.length > 0 ? [
|
|
16227
|
+
{
|
|
16228
|
+
role: "assistant",
|
|
16229
|
+
kind: "message",
|
|
16230
|
+
messageId: item.id,
|
|
16231
|
+
content: textContent2(item.text)
|
|
16232
|
+
}
|
|
16233
|
+
] : [];
|
|
16234
|
+
case "commandExecution":
|
|
16235
|
+
return toolProjection({
|
|
16236
|
+
phase,
|
|
16237
|
+
itemId: item.id,
|
|
16238
|
+
name: "shell",
|
|
16239
|
+
input: {
|
|
16240
|
+
command: item.command,
|
|
16241
|
+
...item.cwd ? { cwd: item.cwd } : {}
|
|
16242
|
+
},
|
|
16243
|
+
output: item.aggregatedOutput ?? "",
|
|
16244
|
+
isError: isFailedStatus(item.status) || (item.exitCode ?? 0) !== 0
|
|
16245
|
+
});
|
|
16246
|
+
case "fileChange":
|
|
16247
|
+
return toolProjection({
|
|
16248
|
+
phase,
|
|
16249
|
+
itemId: item.id,
|
|
16250
|
+
name: "apply_patch",
|
|
16251
|
+
input: { changes: toJsonValue(item.changes) },
|
|
16252
|
+
output: { status: item.status ?? "unknown" },
|
|
16253
|
+
isError: isFailedStatus(item.status)
|
|
16254
|
+
});
|
|
16255
|
+
case "mcpToolCall":
|
|
16256
|
+
return toolProjection({
|
|
16257
|
+
phase,
|
|
16258
|
+
itemId: item.id,
|
|
16259
|
+
name: `${item.server}.${item.tool}`,
|
|
16260
|
+
input: toJsonValue(item.arguments),
|
|
16261
|
+
output: item.error ? { error: item.error.message } : toJsonValue(item.result),
|
|
16262
|
+
isError: isFailedStatus(item.status) || item.error != null
|
|
16263
|
+
});
|
|
16264
|
+
default:
|
|
16265
|
+
return [];
|
|
16266
|
+
}
|
|
16267
|
+
}
|
|
16268
|
+
function projectCodexApproval(request) {
|
|
16269
|
+
const subject = request.type === "commandExecution" ? `run the command: ${request.command ?? "(unknown command)"}` : "apply file changes";
|
|
16270
|
+
const question = {
|
|
16271
|
+
question: request.reason ? `Codex requests approval to ${subject}. ${request.reason}` : `Codex requests approval to ${subject}.`,
|
|
16272
|
+
header: "Approval",
|
|
16273
|
+
options: [
|
|
16274
|
+
{ label: APPROVE_OPTION_LABEL, description: "Allow this action." },
|
|
16275
|
+
{ label: DECLINE_OPTION_LABEL, description: "Reject this action." }
|
|
16276
|
+
],
|
|
16277
|
+
multiSelect: false
|
|
16278
|
+
};
|
|
16279
|
+
return {
|
|
16280
|
+
role: "assistant",
|
|
16281
|
+
kind: "question",
|
|
16282
|
+
content: {
|
|
16283
|
+
parts: [
|
|
16284
|
+
{ type: "question", toolCallId: request.itemId, questions: [question] }
|
|
16285
|
+
]
|
|
16286
|
+
}
|
|
16287
|
+
};
|
|
16288
|
+
}
|
|
16289
|
+
function codexApprovalDecision(input) {
|
|
16290
|
+
const values = [...Object.values(input.answers), input.response ?? ""];
|
|
16291
|
+
const approved = values.some(
|
|
16292
|
+
(value) => value.trim().toLowerCase() === APPROVE_OPTION_LABEL.toLowerCase()
|
|
16293
|
+
);
|
|
16294
|
+
return approved ? "accept" : "decline";
|
|
16295
|
+
}
|
|
16296
|
+
function parseNotification(method, params) {
|
|
16297
|
+
switch (method) {
|
|
16298
|
+
case "thread/started": {
|
|
16299
|
+
const parsed = external_exports.object({ thread: external_exports.object({ id: external_exports.string() }).passthrough() }).passthrough().safeParse(params);
|
|
16300
|
+
return parsed.success ? { type: "threadStarted", threadId: parsed.data.thread.id } : null;
|
|
16301
|
+
}
|
|
16302
|
+
case "turn/started": {
|
|
16303
|
+
const parsed = CodexTurnEnvelopeSchema.safeParse(params);
|
|
16304
|
+
return parsed.success ? {
|
|
16305
|
+
type: "turnStarted",
|
|
16306
|
+
threadId: parsed.data.threadId,
|
|
16307
|
+
turnId: parsed.data.turn.id
|
|
16308
|
+
} : null;
|
|
16309
|
+
}
|
|
16310
|
+
case "turn/completed": {
|
|
16311
|
+
const parsed = CodexTurnEnvelopeSchema.safeParse(params);
|
|
16312
|
+
return parsed.success ? {
|
|
16313
|
+
type: "turnCompleted",
|
|
16314
|
+
threadId: parsed.data.threadId,
|
|
16315
|
+
turnId: parsed.data.turn.id,
|
|
16316
|
+
status: parsed.data.turn.status,
|
|
16317
|
+
...parsed.data.turn.error?.message ? { errorMessage: parsed.data.turn.error.message } : {}
|
|
16318
|
+
} : null;
|
|
16319
|
+
}
|
|
16320
|
+
case "item/started":
|
|
16321
|
+
case "item/completed": {
|
|
16322
|
+
const parsed = CodexItemEnvelopeSchema.safeParse(params);
|
|
16323
|
+
if (!parsed.success || parsed.data.item === null) {
|
|
16324
|
+
return null;
|
|
16325
|
+
}
|
|
16326
|
+
return {
|
|
16327
|
+
type: method === "item/started" ? "itemStarted" : "itemCompleted",
|
|
16328
|
+
threadId: parsed.data.threadId,
|
|
16329
|
+
turnId: parsed.data.turnId,
|
|
16330
|
+
item: parsed.data.item
|
|
16331
|
+
};
|
|
16332
|
+
}
|
|
16333
|
+
case "item/agentMessage/delta": {
|
|
16334
|
+
const parsed = external_exports.object({ itemId: external_exports.string(), delta: external_exports.string() }).passthrough().safeParse(params);
|
|
16335
|
+
return parsed.success ? {
|
|
16336
|
+
type: "agentMessageDelta",
|
|
16337
|
+
itemId: parsed.data.itemId,
|
|
16338
|
+
delta: parsed.data.delta
|
|
16339
|
+
} : null;
|
|
16340
|
+
}
|
|
16341
|
+
case "error": {
|
|
16342
|
+
const parsed = external_exports.object({
|
|
16343
|
+
error: external_exports.object({ message: external_exports.string() }).passthrough(),
|
|
16344
|
+
willRetry: external_exports.boolean().default(false),
|
|
16345
|
+
threadId: external_exports.string().default("")
|
|
16346
|
+
}).passthrough().safeParse(params);
|
|
16347
|
+
return parsed.success ? {
|
|
16348
|
+
type: "error",
|
|
16349
|
+
threadId: parsed.data.threadId,
|
|
16350
|
+
willRetry: parsed.data.willRetry,
|
|
16351
|
+
message: parsed.data.error.message
|
|
16352
|
+
} : null;
|
|
16353
|
+
}
|
|
16354
|
+
default:
|
|
16355
|
+
return null;
|
|
16356
|
+
}
|
|
16357
|
+
}
|
|
16358
|
+
function classifyServerRequest(method, requestId, params) {
|
|
16359
|
+
if (method === "mcpServer/elicitation/request") {
|
|
16360
|
+
const parsed = external_exports.object({ serverName: external_exports.string().default("") }).passthrough().safeParse(params);
|
|
16361
|
+
return {
|
|
16362
|
+
kind: "elicitation",
|
|
16363
|
+
requestId,
|
|
16364
|
+
serverName: parsed.success ? parsed.data.serverName : ""
|
|
16365
|
+
};
|
|
16366
|
+
}
|
|
16367
|
+
const approval = parseApprovalRequest(method, requestId, params);
|
|
16368
|
+
if (approval) {
|
|
16369
|
+
return { kind: "serverRequest", request: approval };
|
|
16370
|
+
}
|
|
16371
|
+
return { kind: "unsupportedRequest", requestId, method };
|
|
16372
|
+
}
|
|
16373
|
+
function parseApprovalRequest(method, requestId, params) {
|
|
16374
|
+
const base = external_exports.object({
|
|
16375
|
+
itemId: external_exports.string(),
|
|
16376
|
+
reason: external_exports.string().nullish(),
|
|
16377
|
+
command: external_exports.string().nullish()
|
|
16378
|
+
}).passthrough();
|
|
16379
|
+
switch (method) {
|
|
16380
|
+
case "item/commandExecution/requestApproval": {
|
|
16381
|
+
const parsed = base.safeParse(params);
|
|
16382
|
+
return parsed.success ? {
|
|
16383
|
+
type: "commandExecution",
|
|
16384
|
+
requestId,
|
|
16385
|
+
itemId: parsed.data.itemId,
|
|
16386
|
+
...parsed.data.reason ? { reason: parsed.data.reason } : {},
|
|
16387
|
+
...parsed.data.command ? { command: parsed.data.command } : {}
|
|
16388
|
+
} : null;
|
|
16389
|
+
}
|
|
16390
|
+
case "item/fileChange/requestApproval": {
|
|
16391
|
+
const parsed = base.safeParse(params);
|
|
16392
|
+
return parsed.success ? {
|
|
16393
|
+
type: "fileChange",
|
|
16394
|
+
requestId,
|
|
16395
|
+
itemId: parsed.data.itemId,
|
|
16396
|
+
...parsed.data.reason ? { reason: parsed.data.reason } : {}
|
|
16397
|
+
} : null;
|
|
16398
|
+
}
|
|
16399
|
+
default:
|
|
16400
|
+
return null;
|
|
16401
|
+
}
|
|
16402
|
+
}
|
|
16403
|
+
function toolProjection(input) {
|
|
16404
|
+
if (input.phase === "started") {
|
|
16405
|
+
return [
|
|
16406
|
+
{
|
|
16407
|
+
role: "assistant",
|
|
16408
|
+
kind: "tool_call",
|
|
16409
|
+
content: {
|
|
16410
|
+
parts: [
|
|
16411
|
+
{
|
|
16412
|
+
type: "tool_call",
|
|
16413
|
+
toolCallId: input.itemId,
|
|
16414
|
+
name: input.name,
|
|
16415
|
+
input: input.input
|
|
16416
|
+
}
|
|
16417
|
+
]
|
|
16418
|
+
}
|
|
16419
|
+
}
|
|
16420
|
+
];
|
|
16421
|
+
}
|
|
16422
|
+
return [
|
|
16423
|
+
{
|
|
16424
|
+
role: "tool",
|
|
16425
|
+
kind: "tool_result",
|
|
16426
|
+
content: {
|
|
16427
|
+
parts: [
|
|
16428
|
+
{
|
|
16429
|
+
type: "tool_result",
|
|
16430
|
+
toolUseId: input.itemId,
|
|
16431
|
+
output: input.output,
|
|
16432
|
+
isError: input.isError
|
|
16433
|
+
}
|
|
16434
|
+
]
|
|
16435
|
+
}
|
|
16436
|
+
}
|
|
16437
|
+
];
|
|
16438
|
+
}
|
|
16439
|
+
function textContent2(text) {
|
|
16440
|
+
return { parts: [{ type: "text", text }] };
|
|
16441
|
+
}
|
|
16442
|
+
function isFailedStatus(status) {
|
|
16443
|
+
return status === "failed" || status === "declined";
|
|
16444
|
+
}
|
|
16445
|
+
var CodexRequestIdSchema, CodexTurnStatusSchema, CodexUserMessageItemSchema, CodexAgentMessageItemSchema, CodexReasoningItemSchema, CodexCommandExecutionItemSchema, CodexFileChangeItemSchema, CodexMcpToolCallItemSchema, CodexItemSchema, OptionalCodexItemSchema, CodexItemEnvelopeSchema, CodexTurnEnvelopeSchema, CodexFrameSchema, APPROVE_OPTION_LABEL, DECLINE_OPTION_LABEL;
|
|
16204
16446
|
var init_codex = __esm({
|
|
16205
16447
|
"../../packages/schemas/src/codex.ts"() {
|
|
16206
16448
|
"use strict";
|
|
@@ -16281,6 +16523,8 @@ var init_codex = __esm({
|
|
|
16281
16523
|
result: external_exports.unknown().optional(),
|
|
16282
16524
|
error: external_exports.object({ message: external_exports.string().optional() }).passthrough().optional()
|
|
16283
16525
|
}).passthrough();
|
|
16526
|
+
APPROVE_OPTION_LABEL = "Approve";
|
|
16527
|
+
DECLINE_OPTION_LABEL = "Decline";
|
|
16284
16528
|
}
|
|
16285
16529
|
});
|
|
16286
16530
|
|
|
@@ -21994,7 +22238,7 @@ var init_package = __esm({
|
|
|
21994
22238
|
"package.json"() {
|
|
21995
22239
|
package_default = {
|
|
21996
22240
|
name: "@autohq/cli",
|
|
21997
|
-
version: "0.1.
|
|
22241
|
+
version: "0.1.227",
|
|
21998
22242
|
license: "SEE LICENSE IN README.md",
|
|
21999
22243
|
publishConfig: {
|
|
22000
22244
|
access: "public"
|
|
@@ -22058,13 +22302,13 @@ var init_version = __esm({
|
|
|
22058
22302
|
});
|
|
22059
22303
|
|
|
22060
22304
|
// src/commands/agents/authoring.ts
|
|
22061
|
-
import { readFileSync as
|
|
22305
|
+
import { readFileSync as readFileSync4, readdirSync as readdirSync2, statSync } from "fs";
|
|
22062
22306
|
import {
|
|
22063
22307
|
basename as basename2,
|
|
22064
|
-
dirname as
|
|
22308
|
+
dirname as dirname5,
|
|
22065
22309
|
extname,
|
|
22066
22310
|
isAbsolute,
|
|
22067
|
-
join as
|
|
22311
|
+
join as join5,
|
|
22068
22312
|
resolve
|
|
22069
22313
|
} from "path";
|
|
22070
22314
|
import { parseAllDocuments as parseYamlDocuments, stringify } from "yaml";
|
|
@@ -22116,8 +22360,8 @@ function renderAgentExplain(result) {
|
|
|
22116
22360
|
return lines.join("\n");
|
|
22117
22361
|
}
|
|
22118
22362
|
function readLocalAgentAuthoringStatuses(input) {
|
|
22119
|
-
const agentsDirectory =
|
|
22120
|
-
input?.directory ??
|
|
22363
|
+
const agentsDirectory = join5(
|
|
22364
|
+
input?.directory ?? join5(process.cwd(), ".auto"),
|
|
22121
22365
|
"agents"
|
|
22122
22366
|
);
|
|
22123
22367
|
const paths = agentAuthoringFiles(agentsDirectory);
|
|
@@ -22156,7 +22400,7 @@ function agentAuthoringFiles(directory) {
|
|
|
22156
22400
|
}
|
|
22157
22401
|
const files = [];
|
|
22158
22402
|
for (const entry of entries) {
|
|
22159
|
-
const path2 =
|
|
22403
|
+
const path2 = join5(directory, entry.name);
|
|
22160
22404
|
if (entry.isDirectory()) {
|
|
22161
22405
|
files.push(...agentAuthoringFiles(path2));
|
|
22162
22406
|
continue;
|
|
@@ -22176,12 +22420,12 @@ function resolveAgentAuthoringPath(input) {
|
|
|
22176
22420
|
if (isAgentFile(candidate)) {
|
|
22177
22421
|
return candidate;
|
|
22178
22422
|
}
|
|
22179
|
-
const agentsDirectory =
|
|
22180
|
-
input.directory ??
|
|
22423
|
+
const agentsDirectory = join5(
|
|
22424
|
+
input.directory ?? join5(process.cwd(), ".auto"),
|
|
22181
22425
|
"agents"
|
|
22182
22426
|
);
|
|
22183
22427
|
for (const extension of AGENT_FILE_EXTENSIONS) {
|
|
22184
|
-
const path2 =
|
|
22428
|
+
const path2 = join5(agentsDirectory, `${input.agent}${extension}`);
|
|
22185
22429
|
if (isAgentFile(path2)) {
|
|
22186
22430
|
return path2;
|
|
22187
22431
|
}
|
|
@@ -22239,7 +22483,7 @@ function readSingleDocument(path2) {
|
|
|
22239
22483
|
return documents[0];
|
|
22240
22484
|
}
|
|
22241
22485
|
function readDocuments(path2) {
|
|
22242
|
-
const source =
|
|
22486
|
+
const source = readFileSync4(path2, "utf8");
|
|
22243
22487
|
const documents = parseYamlDocuments(source);
|
|
22244
22488
|
const parseError = documents.flatMap((document) => document.errors).at(0);
|
|
22245
22489
|
if (parseError) {
|
|
@@ -22264,7 +22508,7 @@ function resolveImportPath(importPath, importerPath) {
|
|
|
22264
22508
|
if (isAbsolute(importPath) || /^[A-Za-z]+:\/\//.test(importPath)) {
|
|
22265
22509
|
throw new Error(`Agent import must be a relative path: ${importPath}`);
|
|
22266
22510
|
}
|
|
22267
|
-
const resolved = resolve(
|
|
22511
|
+
const resolved = resolve(dirname5(importerPath), importPath);
|
|
22268
22512
|
if (!isAgentFile(resolved)) {
|
|
22269
22513
|
throw new Error(
|
|
22270
22514
|
`Agent import not found: ${importPath} from ${importerPath}`
|
|
@@ -22439,7 +22683,7 @@ function resolveFileBackedString(value, input) {
|
|
|
22439
22683
|
`Invalid agent authoring file ${input.path}: ${input.field}.file must be a relative path`
|
|
22440
22684
|
);
|
|
22441
22685
|
}
|
|
22442
|
-
return
|
|
22686
|
+
return readFileSync4(resolve(dirname5(input.path), filePath), "utf8");
|
|
22443
22687
|
}
|
|
22444
22688
|
function removalDirectives(document, path2) {
|
|
22445
22689
|
const raw = isRecord(document.remove) ? document.remove : {};
|
|
@@ -24019,18 +24263,18 @@ var init_project_apply_files2 = __esm({
|
|
|
24019
24263
|
|
|
24020
24264
|
// src/commands/apply/files.ts
|
|
24021
24265
|
import {
|
|
24022
|
-
existsSync as
|
|
24023
|
-
readFileSync as
|
|
24266
|
+
existsSync as existsSync4,
|
|
24267
|
+
readFileSync as readFileSync5,
|
|
24024
24268
|
readdirSync as readdirSync3,
|
|
24025
24269
|
realpathSync,
|
|
24026
24270
|
statSync as statSync2
|
|
24027
24271
|
} from "fs";
|
|
24028
24272
|
import {
|
|
24029
24273
|
basename as basename3,
|
|
24030
|
-
dirname as
|
|
24274
|
+
dirname as dirname6,
|
|
24031
24275
|
extname as extname3,
|
|
24032
24276
|
isAbsolute as isAbsolute2,
|
|
24033
|
-
join as
|
|
24277
|
+
join as join7,
|
|
24034
24278
|
relative,
|
|
24035
24279
|
resolve as resolve2
|
|
24036
24280
|
} from "path";
|
|
@@ -24059,7 +24303,7 @@ function readProjectApplyBundleInput(options) {
|
|
|
24059
24303
|
}
|
|
24060
24304
|
};
|
|
24061
24305
|
}
|
|
24062
|
-
const directory = resolve2(options.directory ??
|
|
24306
|
+
const directory = resolve2(options.directory ?? join7(process.cwd(), ".auto"));
|
|
24063
24307
|
const projectRoot = applyProjectRoot(directory);
|
|
24064
24308
|
const files = sourceFiles(directory, projectRoot);
|
|
24065
24309
|
const resourceRoot = sourcePathRelative(projectRoot, directory);
|
|
@@ -24090,7 +24334,7 @@ function sourceFiles(root, projectRoot) {
|
|
|
24090
24334
|
return [];
|
|
24091
24335
|
}
|
|
24092
24336
|
return entries.flatMap((entry) => {
|
|
24093
|
-
const path2 =
|
|
24337
|
+
const path2 = join7(root, entry.name);
|
|
24094
24338
|
if (entry.isDirectory()) {
|
|
24095
24339
|
return sourceFiles(path2, projectRoot);
|
|
24096
24340
|
}
|
|
@@ -24103,7 +24347,7 @@ function sourceFiles(root, projectRoot) {
|
|
|
24103
24347
|
function sourceFile(path2, projectRoot) {
|
|
24104
24348
|
return {
|
|
24105
24349
|
path: sourcePathRelative(projectRoot, path2),
|
|
24106
|
-
contentBase64:
|
|
24350
|
+
contentBase64: readFileSync5(path2).toString("base64")
|
|
24107
24351
|
};
|
|
24108
24352
|
}
|
|
24109
24353
|
function applyBundle(files) {
|
|
@@ -24137,24 +24381,24 @@ function filesystemAssetReader(projectRoot) {
|
|
|
24137
24381
|
});
|
|
24138
24382
|
return {
|
|
24139
24383
|
path: path2,
|
|
24140
|
-
bytes:
|
|
24384
|
+
bytes: readFileSync5(path2)
|
|
24141
24385
|
};
|
|
24142
24386
|
};
|
|
24143
24387
|
}
|
|
24144
24388
|
function applyProjectRoot(directory) {
|
|
24145
24389
|
const resolved = resolve2(directory);
|
|
24146
|
-
return basename3(resolved) === ".auto" ?
|
|
24390
|
+
return basename3(resolved) === ".auto" ? dirname6(resolved) : resolved;
|
|
24147
24391
|
}
|
|
24148
24392
|
function applyFileProjectRoot(file2) {
|
|
24149
|
-
let dir =
|
|
24393
|
+
let dir = dirname6(resolve2(file2));
|
|
24150
24394
|
while (true) {
|
|
24151
24395
|
if (basename3(dir) === ".auto") {
|
|
24152
|
-
return
|
|
24396
|
+
return dirname6(dir);
|
|
24153
24397
|
}
|
|
24154
24398
|
if (directoryHasAutoRoot(dir)) {
|
|
24155
24399
|
return dir;
|
|
24156
24400
|
}
|
|
24157
|
-
const parent =
|
|
24401
|
+
const parent = dirname6(dir);
|
|
24158
24402
|
if (parent === dir) {
|
|
24159
24403
|
return process.cwd();
|
|
24160
24404
|
}
|
|
@@ -24163,11 +24407,11 @@ function applyFileProjectRoot(file2) {
|
|
|
24163
24407
|
}
|
|
24164
24408
|
function applyFileSourceRoot(file2, projectRoot) {
|
|
24165
24409
|
const autoRoot = resolve2(projectRoot, ".auto");
|
|
24166
|
-
return file2 === autoRoot || isInside(file2, autoRoot) ? autoRoot :
|
|
24410
|
+
return file2 === autoRoot || isInside(file2, autoRoot) ? autoRoot : dirname6(file2);
|
|
24167
24411
|
}
|
|
24168
24412
|
function directoryHasAutoRoot(directory) {
|
|
24169
24413
|
const autoRoot = resolve2(directory, ".auto");
|
|
24170
|
-
if (!
|
|
24414
|
+
if (!existsSync4(autoRoot)) {
|
|
24171
24415
|
return false;
|
|
24172
24416
|
}
|
|
24173
24417
|
return statSync2(autoRoot).isDirectory();
|
|
@@ -24758,16 +25002,16 @@ var init_resources3 = __esm({
|
|
|
24758
25002
|
});
|
|
24759
25003
|
|
|
24760
25004
|
// src/commands/edit/actions.ts
|
|
24761
|
-
import { spawn as
|
|
25005
|
+
import { spawn as spawn3 } from "child_process";
|
|
24762
25006
|
import {
|
|
24763
|
-
mkdirSync as
|
|
25007
|
+
mkdirSync as mkdirSync5,
|
|
24764
25008
|
mkdtempSync as mkdtempSync2,
|
|
24765
|
-
readFileSync as
|
|
25009
|
+
readFileSync as readFileSync6,
|
|
24766
25010
|
rmSync as rmSync2,
|
|
24767
|
-
writeFileSync as
|
|
25011
|
+
writeFileSync as writeFileSync6
|
|
24768
25012
|
} from "fs";
|
|
24769
25013
|
import { tmpdir as tmpdir2 } from "os";
|
|
24770
|
-
import { join as
|
|
25014
|
+
import { join as join8 } from "path";
|
|
24771
25015
|
import { parseAllDocuments as parseYamlDocuments3, stringify as stringify4 } from "yaml";
|
|
24772
25016
|
async function editResource(input) {
|
|
24773
25017
|
const reference = parseProjectResourceReference(input.resource);
|
|
@@ -24787,15 +25031,15 @@ async function editResource(input) {
|
|
|
24787
25031
|
const document = editableAgentFacade(current);
|
|
24788
25032
|
const source = `${stringify4(document).trimEnd()}
|
|
24789
25033
|
`;
|
|
24790
|
-
const tempRoot = mkdtempSync2(
|
|
24791
|
-
const agentsDir =
|
|
24792
|
-
|
|
24793
|
-
const filePath =
|
|
24794
|
-
|
|
25034
|
+
const tempRoot = mkdtempSync2(join8(tmpdir2(), "auto-edit-"));
|
|
25035
|
+
const agentsDir = join8(tempRoot, ".auto", "agents");
|
|
25036
|
+
mkdirSync5(agentsDir, { recursive: true });
|
|
25037
|
+
const filePath = join8(agentsDir, `${reference.name}.yaml`);
|
|
25038
|
+
writeFileSync6(filePath, source, "utf8");
|
|
24795
25039
|
let removeTempFile = false;
|
|
24796
25040
|
try {
|
|
24797
25041
|
await runEditor(editor, filePath);
|
|
24798
|
-
const editedSource =
|
|
25042
|
+
const editedSource = readFileSync6(filePath, "utf8");
|
|
24799
25043
|
if (editedSource === source) {
|
|
24800
25044
|
input.writeOutput("No changes; skipped apply.");
|
|
24801
25045
|
removeTempFile = true;
|
|
@@ -24838,7 +25082,7 @@ function resolveEditor(input) {
|
|
|
24838
25082
|
}
|
|
24839
25083
|
async function runEditor(editor, filePath) {
|
|
24840
25084
|
await new Promise((resolve4, reject) => {
|
|
24841
|
-
const child =
|
|
25085
|
+
const child = spawn3(editor, [filePath], {
|
|
24842
25086
|
shell: true,
|
|
24843
25087
|
stdio: "inherit"
|
|
24844
25088
|
});
|
|
@@ -24861,7 +25105,7 @@ async function runEditor(editor, filePath) {
|
|
|
24861
25105
|
});
|
|
24862
25106
|
}
|
|
24863
25107
|
function assertEditedResourceIdentity(filePath, expected) {
|
|
24864
|
-
const source =
|
|
25108
|
+
const source = readFileSync6(filePath, "utf8");
|
|
24865
25109
|
let parsedDocuments;
|
|
24866
25110
|
try {
|
|
24867
25111
|
parsedDocuments = parseYamlDocuments3(source);
|
|
@@ -26127,7 +26371,8 @@ function ConversationView({
|
|
|
26127
26371
|
word: pickActivityWord(sessionId)
|
|
26128
26372
|
});
|
|
26129
26373
|
const sawLiveTurnActivity = useRef(false);
|
|
26130
|
-
const pendingLocalCommand = useRef(
|
|
26374
|
+
const pendingLocalCommand = useRef(null);
|
|
26375
|
+
const lastSessionUpdatedAt = useRef(null);
|
|
26131
26376
|
const awaitingReplyRef = useRef(true);
|
|
26132
26377
|
const updateAwaitingReply = useCallback((value) => {
|
|
26133
26378
|
awaitingReplyRef.current = value;
|
|
@@ -26153,10 +26398,13 @@ function ConversationView({
|
|
|
26153
26398
|
status: session.status,
|
|
26154
26399
|
runInput: session.input,
|
|
26155
26400
|
hasConversationActivity: hasConversationActivity.current,
|
|
26156
|
-
|
|
26401
|
+
pendingLocalCommand: pendingLocalCommand.current,
|
|
26402
|
+
sessionUpdatedAt: session.updatedAt
|
|
26157
26403
|
})) {
|
|
26404
|
+
pendingLocalCommand.current = null;
|
|
26158
26405
|
updateAwaitingReply(false);
|
|
26159
26406
|
}
|
|
26407
|
+
lastSessionUpdatedAt.current = session.updatedAt;
|
|
26160
26408
|
},
|
|
26161
26409
|
[updateAwaitingReply]
|
|
26162
26410
|
);
|
|
@@ -26169,12 +26417,12 @@ function ConversationView({
|
|
|
26169
26417
|
return;
|
|
26170
26418
|
}
|
|
26171
26419
|
if (event.kind === "question") {
|
|
26172
|
-
pendingLocalCommand.current =
|
|
26420
|
+
pendingLocalCommand.current = null;
|
|
26173
26421
|
updateAwaitingReply(false);
|
|
26174
26422
|
return;
|
|
26175
26423
|
}
|
|
26176
26424
|
if (isTurnLifecycleStartEntry(event)) {
|
|
26177
|
-
pendingLocalCommand.current =
|
|
26425
|
+
pendingLocalCommand.current = null;
|
|
26178
26426
|
if (!awaitingReplyRef.current) {
|
|
26179
26427
|
turnRef.current = {
|
|
26180
26428
|
startedAt: Date.now(),
|
|
@@ -26191,7 +26439,7 @@ function ConversationView({
|
|
|
26191
26439
|
if (!turnEnd) {
|
|
26192
26440
|
return;
|
|
26193
26441
|
}
|
|
26194
|
-
pendingLocalCommand.current =
|
|
26442
|
+
pendingLocalCommand.current = null;
|
|
26195
26443
|
updateAwaitingReply(false);
|
|
26196
26444
|
if (turnEnd === "completed" && sawLiveTurnActivity.current) {
|
|
26197
26445
|
setCompletedTurn({
|
|
@@ -26344,7 +26592,9 @@ function ConversationView({
|
|
|
26344
26592
|
setInput("");
|
|
26345
26593
|
hasConversationActivity.current = true;
|
|
26346
26594
|
updateAwaitingReply(true);
|
|
26347
|
-
pendingLocalCommand.current =
|
|
26595
|
+
pendingLocalCommand.current = {
|
|
26596
|
+
previousSessionUpdatedAt: lastSessionUpdatedAt.current
|
|
26597
|
+
};
|
|
26348
26598
|
turnRef.current = { startedAt: Date.now(), word: pickActivityWord(text) };
|
|
26349
26599
|
sawLiveTurnActivity.current = false;
|
|
26350
26600
|
setTurnTokenChars(0);
|
|
@@ -26392,7 +26642,7 @@ function ConversationView({
|
|
|
26392
26642
|
return next;
|
|
26393
26643
|
});
|
|
26394
26644
|
}
|
|
26395
|
-
pendingLocalCommand.current =
|
|
26645
|
+
pendingLocalCommand.current = null;
|
|
26396
26646
|
updateAwaitingReply(false);
|
|
26397
26647
|
throw err;
|
|
26398
26648
|
} finally {
|
|
@@ -26417,7 +26667,9 @@ function ConversationView({
|
|
|
26417
26667
|
}
|
|
26418
26668
|
hasConversationActivity.current = true;
|
|
26419
26669
|
updateAwaitingReply(true);
|
|
26420
|
-
pendingLocalCommand.current =
|
|
26670
|
+
pendingLocalCommand.current = {
|
|
26671
|
+
previousSessionUpdatedAt: lastSessionUpdatedAt.current
|
|
26672
|
+
};
|
|
26421
26673
|
turnRef.current = {
|
|
26422
26674
|
startedAt: Date.now(),
|
|
26423
26675
|
word: pickActivityWord(toolCallId)
|
|
@@ -26439,7 +26691,7 @@ function ConversationView({
|
|
|
26439
26691
|
next.delete(toolCallId);
|
|
26440
26692
|
return next;
|
|
26441
26693
|
});
|
|
26442
|
-
pendingLocalCommand.current =
|
|
26694
|
+
pendingLocalCommand.current = null;
|
|
26443
26695
|
updateAwaitingReply(false);
|
|
26444
26696
|
throw err;
|
|
26445
26697
|
} finally {
|
|
@@ -26592,7 +26844,7 @@ function ConversationView({
|
|
|
26592
26844
|
/* @__PURE__ */ jsx4(Text4, { dimColor: true, children: "esc to go back" }),
|
|
26593
26845
|
/* @__PURE__ */ jsx4(Text4, { dimColor: true, children: "\xB7" }),
|
|
26594
26846
|
/* @__PURE__ */ jsxs4(Text4, { dimColor: true, children: [
|
|
26595
|
-
|
|
26847
|
+
footerSessionStatusLabel({ status, awaitingReply }),
|
|
26596
26848
|
debugActive ? " \xB7 debug" : ""
|
|
26597
26849
|
] })
|
|
26598
26850
|
] })
|
|
@@ -26689,14 +26941,20 @@ function elapsedSeconds(startedAt) {
|
|
|
26689
26941
|
return Math.max(0, Math.floor((Date.now() - startedAt) / 1e3));
|
|
26690
26942
|
}
|
|
26691
26943
|
function shouldAcceptUserInputFromRunSnapshot(input) {
|
|
26692
|
-
if (input.hasPendingLocalCommand) {
|
|
26693
|
-
return false;
|
|
26694
|
-
}
|
|
26695
26944
|
if (input.status === "awaiting") {
|
|
26696
|
-
return
|
|
26945
|
+
return input.pendingLocalCommand === null || input.pendingLocalCommand.previousSessionUpdatedAt === null || input.sessionUpdatedAt !== input.pendingLocalCommand.previousSessionUpdatedAt;
|
|
26946
|
+
}
|
|
26947
|
+
if (input.pendingLocalCommand !== null) {
|
|
26948
|
+
return false;
|
|
26697
26949
|
}
|
|
26698
26950
|
return input.status === "running" && !input.hasConversationActivity && isInteractiveRunInputWithoutMessage(input.runInput);
|
|
26699
26951
|
}
|
|
26952
|
+
function footerSessionStatusLabel(input) {
|
|
26953
|
+
if (input.status === "running" && input.awaitingReply) {
|
|
26954
|
+
return "working";
|
|
26955
|
+
}
|
|
26956
|
+
return input.status;
|
|
26957
|
+
}
|
|
26700
26958
|
function isInteractiveRunInputWithoutMessage(input) {
|
|
26701
26959
|
return typeof input === "object" && input !== null && !Array.isArray(input) && "interactive" in input && input.interactive === true && !("message" in input && typeof input.message === "string" && input.message.trim().length > 0);
|
|
26702
26960
|
}
|
|
@@ -27983,7 +28241,7 @@ function SessionsView({
|
|
|
27983
28241
|
visibleSessions.map((session, vi) => {
|
|
27984
28242
|
const i = scrollOffset + vi;
|
|
27985
28243
|
const title = sessionDisplayTitle(session);
|
|
27986
|
-
const err = session.status === "failed" ?
|
|
28244
|
+
const err = session.status === "failed" ? errorMessage4(session) : null;
|
|
27987
28245
|
const isSelected = i === safeIndex;
|
|
27988
28246
|
const isMarked = selectedSessionIds.has(session.id);
|
|
27989
28247
|
return /* @__PURE__ */ jsxs10(Box11, { flexDirection: "column", children: [
|
|
@@ -28121,7 +28379,7 @@ function truncateToWidth(value, width) {
|
|
|
28121
28379
|
function agentNameForRun(session) {
|
|
28122
28380
|
return session.snapshot.metadata.name;
|
|
28123
28381
|
}
|
|
28124
|
-
function
|
|
28382
|
+
function errorMessage4(session) {
|
|
28125
28383
|
if (session.error == null) return null;
|
|
28126
28384
|
if (typeof session.error === "string") return session.error;
|
|
28127
28385
|
const msg = readField(session.error, "message");
|
|
@@ -29543,7 +29801,7 @@ function HomeView({ apiUrl, notice, returnToAgent }) {
|
|
|
29543
29801
|
if (inspectedResource) {
|
|
29544
29802
|
sectionTitle = `Inspect ${inspectedResource.kind}/${inspectedResource.name}`;
|
|
29545
29803
|
}
|
|
29546
|
-
const runError =
|
|
29804
|
+
const runError = errorMessage5(triggerSession.error) ?? errorMessage5(archiveSessions.error) ?? errorMessage5(unarchiveSessions.error) ?? errorMessage5(stopSessions.error);
|
|
29547
29805
|
const isRunMutationPending = triggerSession.isPending || archiveSessions.isPending || unarchiveSessions.isPending || stopSessions.isPending;
|
|
29548
29806
|
const isConnectionMutationPending = startConnection.isPending || allowConnection.isPending || removeConnection.isPending || createGithubSyncBinding.isPending;
|
|
29549
29807
|
const serviceAccountStatus = createServiceAccount2.error instanceof Error ? createServiceAccount2.error.message : rotateServiceAccount2.error instanceof Error ? rotateServiceAccount2.error.message : removeServiceAccount2.error instanceof Error ? removeServiceAccount2.error.message : serviceAccountNotice;
|
|
@@ -29956,7 +30214,7 @@ function runActionTargetLabel(sessionIds, markedRunCount) {
|
|
|
29956
30214
|
function pluralizeRunCount(count) {
|
|
29957
30215
|
return `${count} ${count === 1 ? "session" : "sessions"}`;
|
|
29958
30216
|
}
|
|
29959
|
-
function
|
|
30217
|
+
function errorMessage5(error51) {
|
|
29960
30218
|
if (error51 instanceof Error) return error51.message;
|
|
29961
30219
|
return error51 ? String(error51) : null;
|
|
29962
30220
|
}
|
|
@@ -30277,8 +30535,8 @@ __export(launcher_exports, {
|
|
|
30277
30535
|
launch: () => launch
|
|
30278
30536
|
});
|
|
30279
30537
|
import { spawnSync } from "child_process";
|
|
30280
|
-
import { existsSync as
|
|
30281
|
-
import { dirname as
|
|
30538
|
+
import { existsSync as existsSync6 } from "fs";
|
|
30539
|
+
import { dirname as dirname7, resolve as resolve3 } from "path";
|
|
30282
30540
|
import { fileURLToPath } from "url";
|
|
30283
30541
|
import {
|
|
30284
30542
|
QueryClient,
|
|
@@ -30455,7 +30713,7 @@ function resolveSplashVersion() {
|
|
|
30455
30713
|
return resolveLatestReleaseVersionFromCheckout() ?? cliVersion;
|
|
30456
30714
|
}
|
|
30457
30715
|
function resolveLatestReleaseVersionFromCheckout() {
|
|
30458
|
-
const repoRoot = findRepoRoot(
|
|
30716
|
+
const repoRoot = findRepoRoot(dirname7(fileURLToPath(import.meta.url)));
|
|
30459
30717
|
if (!repoRoot) {
|
|
30460
30718
|
return null;
|
|
30461
30719
|
}
|
|
@@ -30472,10 +30730,10 @@ function resolveLatestReleaseVersionFromCheckout() {
|
|
|
30472
30730
|
function findRepoRoot(startDirectory) {
|
|
30473
30731
|
let directory = startDirectory;
|
|
30474
30732
|
while (true) {
|
|
30475
|
-
if (
|
|
30733
|
+
if (existsSync6(resolve3(directory, ".git")) && existsSync6(resolve3(directory, "apps/cli/package.json"))) {
|
|
30476
30734
|
return directory;
|
|
30477
30735
|
}
|
|
30478
|
-
const parent =
|
|
30736
|
+
const parent = dirname7(directory);
|
|
30479
30737
|
if (parent === directory) {
|
|
30480
30738
|
return null;
|
|
30481
30739
|
}
|
|
@@ -31476,6 +31734,9 @@ var AgentBridgeClaudeConfigSchema = AgentBridgeHarnessBaseConfigSchema;
|
|
|
31476
31734
|
var AgentBridgeHarnessConfigSchema = external_exports.discriminatedUnion("kind", [
|
|
31477
31735
|
AgentBridgeHarnessBaseConfigSchema.extend({
|
|
31478
31736
|
kind: external_exports.literal("claude-code")
|
|
31737
|
+
}),
|
|
31738
|
+
AgentBridgeHarnessBaseConfigSchema.extend({
|
|
31739
|
+
kind: external_exports.literal("codex")
|
|
31479
31740
|
})
|
|
31480
31741
|
]);
|
|
31481
31742
|
var RuntimeBridgeBootstrapPlaintextSchema = external_exports.object({
|
|
@@ -33597,110 +33858,1098 @@ function commandLogContext(delivery, fields = {}) {
|
|
|
33597
33858
|
};
|
|
33598
33859
|
}
|
|
33599
33860
|
|
|
33600
|
-
// src/commands/agent-bridge/harness/index.ts
|
|
33601
|
-
|
|
33602
|
-
|
|
33603
|
-
|
|
33604
|
-
|
|
33861
|
+
// src/commands/agent-bridge/harness/codex/index.ts
|
|
33862
|
+
init_src();
|
|
33863
|
+
|
|
33864
|
+
// src/commands/agent-bridge/harness/codex/projector.ts
|
|
33865
|
+
init_src();
|
|
33866
|
+
var CodexProjector = class {
|
|
33867
|
+
project(notification) {
|
|
33868
|
+
switch (notification.type) {
|
|
33869
|
+
case "agentMessageDelta":
|
|
33870
|
+
return [
|
|
33871
|
+
{
|
|
33872
|
+
type: "delta",
|
|
33873
|
+
delta: {
|
|
33874
|
+
messageId: notification.itemId,
|
|
33875
|
+
partId: "0",
|
|
33876
|
+
role: "assistant",
|
|
33877
|
+
kind: "message",
|
|
33878
|
+
delta: { type: "text", text: notification.delta }
|
|
33879
|
+
}
|
|
33880
|
+
}
|
|
33881
|
+
];
|
|
33882
|
+
case "itemStarted":
|
|
33883
|
+
return entryProjections(
|
|
33884
|
+
projectCodexItem({ item: notification.item, phase: "started" })
|
|
33885
|
+
);
|
|
33886
|
+
case "itemCompleted":
|
|
33887
|
+
return entryProjections(
|
|
33888
|
+
projectCodexItem({ item: notification.item, phase: "completed" })
|
|
33889
|
+
);
|
|
33890
|
+
case "turnCompleted":
|
|
33891
|
+
return [turnCompletionEntry(notification)];
|
|
33892
|
+
case "error":
|
|
33893
|
+
return [errorEntry(notification)];
|
|
33894
|
+
default:
|
|
33895
|
+
return [];
|
|
33896
|
+
}
|
|
33897
|
+
}
|
|
33898
|
+
// An approval parks the turn on operator input, so the question entry also
|
|
33899
|
+
// marks the delivered turn as waiting for input.
|
|
33900
|
+
projectApproval(request) {
|
|
33901
|
+
return {
|
|
33902
|
+
type: "entry",
|
|
33903
|
+
entry: {
|
|
33904
|
+
...projectCodexApproval(request),
|
|
33905
|
+
turnStatus: "waiting_for_input"
|
|
33906
|
+
}
|
|
33907
|
+
};
|
|
33908
|
+
}
|
|
33909
|
+
// Surfaces a session-level failure (e.g. the app-server process dying) as a
|
|
33910
|
+
// durable failed status entry rather than only a diagnostic log line.
|
|
33911
|
+
projectSessionFailure(message) {
|
|
33912
|
+
return {
|
|
33913
|
+
type: "entry",
|
|
33914
|
+
entry: {
|
|
33915
|
+
role: "system",
|
|
33916
|
+
kind: "status",
|
|
33917
|
+
status: "failed",
|
|
33918
|
+
turnStatus: "failed",
|
|
33919
|
+
content: {
|
|
33920
|
+
parts: [{ type: "text", text: `codex failed: ${message}` }]
|
|
33921
|
+
}
|
|
33922
|
+
}
|
|
33923
|
+
};
|
|
33924
|
+
}
|
|
33925
|
+
};
|
|
33926
|
+
function entryProjections(projections) {
|
|
33927
|
+
return projections.map((projection) => ({
|
|
33928
|
+
type: "entry",
|
|
33929
|
+
entry: projection
|
|
33930
|
+
}));
|
|
33931
|
+
}
|
|
33932
|
+
function turnCompletionEntry(notification) {
|
|
33933
|
+
if (notification.status === "failed") {
|
|
33934
|
+
const detail = notification.errorMessage ?? "unknown error";
|
|
33935
|
+
return statusEntry({
|
|
33936
|
+
text: `codex turn failed: ${detail}`,
|
|
33937
|
+
status: "failed",
|
|
33938
|
+
turnStatus: "failed"
|
|
33939
|
+
});
|
|
33940
|
+
}
|
|
33941
|
+
const text = notification.status === "interrupted" ? "codex turn interrupted" : "codex turn completed";
|
|
33942
|
+
return statusEntry({
|
|
33943
|
+
text,
|
|
33944
|
+
status: "completed",
|
|
33945
|
+
turnStatus: "completed"
|
|
33605
33946
|
});
|
|
33606
33947
|
}
|
|
33607
|
-
function
|
|
33608
|
-
|
|
33609
|
-
|
|
33610
|
-
|
|
33611
|
-
|
|
33612
|
-
|
|
33613
|
-
socketId: input.socketId,
|
|
33614
|
-
...input.writeOutput ? { writeOutput: input.writeOutput } : {}
|
|
33615
|
-
};
|
|
33616
|
-
switch (config2.kind) {
|
|
33617
|
-
case "claude-code": {
|
|
33618
|
-
const { kind, ...claude } = config2;
|
|
33619
|
-
return createClaudeCodeCommandHandler({
|
|
33620
|
-
...base,
|
|
33621
|
-
claude,
|
|
33622
|
-
sessionResume: fileClaudeSessionResumeStore()
|
|
33623
|
-
});
|
|
33624
|
-
}
|
|
33948
|
+
function errorEntry(notification) {
|
|
33949
|
+
if (notification.willRetry) {
|
|
33950
|
+
return statusEntry({
|
|
33951
|
+
text: `codex retrying after error: ${notification.message}`,
|
|
33952
|
+
status: "completed"
|
|
33953
|
+
});
|
|
33625
33954
|
}
|
|
33955
|
+
return statusEntry({
|
|
33956
|
+
text: `codex error: ${notification.message}`,
|
|
33957
|
+
status: "failed",
|
|
33958
|
+
turnStatus: "failed"
|
|
33959
|
+
});
|
|
33626
33960
|
}
|
|
33627
|
-
function
|
|
33628
|
-
return
|
|
33961
|
+
function statusEntry(input) {
|
|
33962
|
+
return {
|
|
33963
|
+
type: "entry",
|
|
33964
|
+
entry: {
|
|
33965
|
+
role: "system",
|
|
33966
|
+
kind: "status",
|
|
33967
|
+
status: input.status,
|
|
33968
|
+
...input.turnStatus ? { turnStatus: input.turnStatus } : {},
|
|
33969
|
+
content: { parts: [{ type: "text", text: input.text }] }
|
|
33970
|
+
}
|
|
33971
|
+
};
|
|
33629
33972
|
}
|
|
33630
33973
|
|
|
33631
|
-
// src/commands/agent-bridge/
|
|
33632
|
-
|
|
33633
|
-
|
|
33634
|
-
var
|
|
33635
|
-
var
|
|
33636
|
-
|
|
33637
|
-
|
|
33638
|
-
|
|
33639
|
-
|
|
33640
|
-
|
|
33641
|
-
const emit = (lineLevel) => {
|
|
33642
|
-
return (message, context) => {
|
|
33643
|
-
if (!runtimeLogLevelEnabled(level, lineLevel)) {
|
|
33644
|
-
return;
|
|
33974
|
+
// src/commands/agent-bridge/harness/codex/resume-store.ts
|
|
33975
|
+
import { existsSync as existsSync2, mkdirSync as mkdirSync3, readFileSync as readFileSync3, writeFileSync as writeFileSync3 } from "fs";
|
|
33976
|
+
import { dirname as dirname4 } from "path";
|
|
33977
|
+
var AGENT_BRIDGE_RUNTIME_DIR2 = "/tmp/auto-bridge-runtime";
|
|
33978
|
+
var CODEX_THREAD_RESUME_PATH = `${AGENT_BRIDGE_RUNTIME_DIR2}/codex-thread-id`;
|
|
33979
|
+
function fileCodexThreadResumeStore(path2 = CODEX_THREAD_RESUME_PATH) {
|
|
33980
|
+
return {
|
|
33981
|
+
read(sessionId) {
|
|
33982
|
+
if (!existsSync2(path2)) {
|
|
33983
|
+
return null;
|
|
33645
33984
|
}
|
|
33646
|
-
const
|
|
33647
|
-
|
|
33648
|
-
|
|
33649
|
-
|
|
33650
|
-
|
|
33651
|
-
|
|
33652
|
-
|
|
33653
|
-
|
|
33654
|
-
|
|
33655
|
-
|
|
33985
|
+
const record2 = parseResumeRecord2(readFileSync3(path2, "utf8"));
|
|
33986
|
+
if (!record2 || record2.sessionId !== sessionId) {
|
|
33987
|
+
return null;
|
|
33988
|
+
}
|
|
33989
|
+
return record2.threadId;
|
|
33990
|
+
},
|
|
33991
|
+
write(record2) {
|
|
33992
|
+
mkdirSync3(dirname4(path2), { recursive: true });
|
|
33993
|
+
writeFileSync3(path2, `${JSON.stringify(record2)}
|
|
33994
|
+
`, "utf8");
|
|
33995
|
+
}
|
|
33656
33996
|
};
|
|
33997
|
+
}
|
|
33998
|
+
function parseResumeRecord2(raw) {
|
|
33999
|
+
try {
|
|
34000
|
+
const value = JSON.parse(raw);
|
|
34001
|
+
if (value !== null && typeof value === "object" && "sessionId" in value && "threadId" in value && typeof value.sessionId === "string" && typeof value.threadId === "string" && value.threadId.length > 0) {
|
|
34002
|
+
return { sessionId: value.sessionId, threadId: value.threadId };
|
|
34003
|
+
}
|
|
34004
|
+
return null;
|
|
34005
|
+
} catch {
|
|
34006
|
+
return null;
|
|
34007
|
+
}
|
|
34008
|
+
}
|
|
34009
|
+
|
|
34010
|
+
// src/commands/agent-bridge/harness/codex/session.ts
|
|
34011
|
+
init_src();
|
|
34012
|
+
import { spawn as spawn2 } from "child_process";
|
|
34013
|
+
import { mkdirSync as mkdirSync4, writeFileSync as writeFileSync4 } from "fs";
|
|
34014
|
+
import { join as join4 } from "path";
|
|
34015
|
+
|
|
34016
|
+
// src/commands/agent-bridge/harness/codex/options.ts
|
|
34017
|
+
import { join as join3 } from "path";
|
|
34018
|
+
var CODEX_EXECUTABLE_PATH = "codex";
|
|
34019
|
+
var CODEX_DEFAULT_MODEL = "gpt-5.3-codex";
|
|
34020
|
+
var CODEX_HTTP_PROVIDER_ID = "openai-responses-http";
|
|
34021
|
+
var CODEX_OPENAI_BASE_URL = "https://api.openai.com/v1";
|
|
34022
|
+
var CODEX_API_KEY_ENV = "OPENAI_API_KEY";
|
|
34023
|
+
var CODEX_RUNTIME_PROCESS_ENV_KEYS = ["PATH", "HOME"];
|
|
34024
|
+
function codexLaunchOptions(config2) {
|
|
33657
34025
|
return {
|
|
33658
|
-
|
|
33659
|
-
|
|
33660
|
-
|
|
33661
|
-
|
|
33662
|
-
|
|
34026
|
+
command: codexExecutablePath(),
|
|
34027
|
+
// `--listen stdio://` is the default, but pin it so a config/feature change
|
|
34028
|
+
// cannot silently move the transport off the stdin/stdout the client drives.
|
|
34029
|
+
args: ["app-server", "--listen", "stdio://"],
|
|
34030
|
+
env: codexProcessEnv(config2.env),
|
|
34031
|
+
// Codex reads config/auth/rollout state from its standard home; the caller
|
|
34032
|
+
// writes the rendered config.toml there.
|
|
34033
|
+
codexHome: codexHomeDir(),
|
|
34034
|
+
configToml: renderCodexConfigToml(config2)
|
|
33663
34035
|
};
|
|
33664
34036
|
}
|
|
33665
|
-
function
|
|
34037
|
+
function codexThreadParams(config2) {
|
|
33666
34038
|
return {
|
|
33667
|
-
...
|
|
33668
|
-
|
|
33669
|
-
timestamp: (/* @__PURE__ */ new Date()).toISOString(),
|
|
33670
|
-
level: input.level,
|
|
33671
|
-
component: RUNTIME_LOG_COMPONENT,
|
|
33672
|
-
message: input.message
|
|
34039
|
+
...config2.cwd ? { cwd: config2.cwd } : {},
|
|
34040
|
+
...config2.systemPromptAppend ? { developerInstructions: config2.systemPromptAppend } : {}
|
|
33673
34041
|
};
|
|
33674
34042
|
}
|
|
33675
|
-
function
|
|
33676
|
-
|
|
33677
|
-
`);
|
|
34043
|
+
function renderCodexConfigToml(config2) {
|
|
34044
|
+
const lines = [];
|
|
34045
|
+
lines.push(`model = ${tomlString(CODEX_DEFAULT_MODEL)}`);
|
|
34046
|
+
lines.push(`model_provider = ${tomlString(CODEX_HTTP_PROVIDER_ID)}`);
|
|
34047
|
+
lines.push("");
|
|
34048
|
+
lines.push(`[model_providers.${CODEX_HTTP_PROVIDER_ID}]`);
|
|
34049
|
+
lines.push('name = "OpenAI"');
|
|
34050
|
+
lines.push(`base_url = ${tomlString(CODEX_OPENAI_BASE_URL)}`);
|
|
34051
|
+
lines.push('wire_api = "responses"');
|
|
34052
|
+
lines.push(`env_key = ${tomlString(CODEX_API_KEY_ENV)}`);
|
|
34053
|
+
lines.push("supports_websockets = false");
|
|
34054
|
+
for (const [name, server] of Object.entries(config2.mcpServers ?? {})) {
|
|
34055
|
+
lines.push("");
|
|
34056
|
+
lines.push(`[mcp_servers.${tomlKey(name)}]`);
|
|
34057
|
+
lines.push(`url = ${tomlString(server.url)}`);
|
|
34058
|
+
if (server.headers && Object.keys(server.headers).length > 0) {
|
|
34059
|
+
lines.push(`http_headers = ${tomlInlineTable(server.headers)}`);
|
|
34060
|
+
}
|
|
34061
|
+
}
|
|
34062
|
+
return `${lines.join("\n")}
|
|
34063
|
+
`;
|
|
33678
34064
|
}
|
|
33679
|
-
function
|
|
33680
|
-
const
|
|
33681
|
-
const
|
|
33682
|
-
|
|
33683
|
-
|
|
33684
|
-
|
|
33685
|
-
const queue = [];
|
|
33686
|
-
let flushTimer;
|
|
33687
|
-
let inFlight = false;
|
|
33688
|
-
const scheduleFlush = () => {
|
|
33689
|
-
if (flushTimer || inFlight) {
|
|
33690
|
-
return;
|
|
34065
|
+
function codexProcessEnv(env) {
|
|
34066
|
+
const selected = {};
|
|
34067
|
+
for (const key of CODEX_RUNTIME_PROCESS_ENV_KEYS) {
|
|
34068
|
+
const value = process.env[key];
|
|
34069
|
+
if (value !== void 0) {
|
|
34070
|
+
selected[key] = value;
|
|
33691
34071
|
}
|
|
33692
|
-
|
|
33693
|
-
|
|
33694
|
-
|
|
33695
|
-
|
|
33696
|
-
flushTimer.unref?.();
|
|
34072
|
+
}
|
|
34073
|
+
return {
|
|
34074
|
+
...selected,
|
|
34075
|
+
...env
|
|
33697
34076
|
};
|
|
33698
|
-
|
|
33699
|
-
|
|
33700
|
-
|
|
33701
|
-
|
|
33702
|
-
|
|
33703
|
-
|
|
34077
|
+
}
|
|
34078
|
+
function codexHomeDir() {
|
|
34079
|
+
const home = process.env.HOME;
|
|
34080
|
+
if (!home) {
|
|
34081
|
+
throw new Error("codex launch requires HOME to locate the ~/.codex home");
|
|
34082
|
+
}
|
|
34083
|
+
return join3(home, ".codex");
|
|
34084
|
+
}
|
|
34085
|
+
function codexExecutablePath() {
|
|
34086
|
+
if (process.env.AUTO_AGENT_BRIDGE_TEST_CODEX_COMMAND === "1" && process.env.AUTO_CODEX_COMMAND?.trim()) {
|
|
34087
|
+
return process.env.AUTO_CODEX_COMMAND.trim();
|
|
34088
|
+
}
|
|
34089
|
+
return CODEX_EXECUTABLE_PATH;
|
|
34090
|
+
}
|
|
34091
|
+
function tomlInlineTable(values) {
|
|
34092
|
+
const entries = Object.entries(values).map(
|
|
34093
|
+
([key, value]) => `${tomlKey(key)} = ${tomlString(value)}`
|
|
34094
|
+
);
|
|
34095
|
+
return `{ ${entries.join(", ")} }`;
|
|
34096
|
+
}
|
|
34097
|
+
function tomlKey(key) {
|
|
34098
|
+
return /^[A-Za-z0-9_-]+$/.test(key) ? key : tomlString(key);
|
|
34099
|
+
}
|
|
34100
|
+
function tomlString(value) {
|
|
34101
|
+
return `"${value.replace(/\\/g, "\\\\").replace(/"/g, '\\"')}"`;
|
|
34102
|
+
}
|
|
34103
|
+
|
|
34104
|
+
// src/commands/agent-bridge/harness/codex/session.ts
|
|
34105
|
+
var CODEX_REQUEST_TIMEOUT_MS = 3e4;
|
|
34106
|
+
var CODEX_ITEM_SETTLE_TIMEOUT_MS = 1e4;
|
|
34107
|
+
var CODEX_TOOL_ITEM_TYPES = /* @__PURE__ */ new Set([
|
|
34108
|
+
"commandExecution",
|
|
34109
|
+
"fileChange",
|
|
34110
|
+
"mcpToolCall"
|
|
34111
|
+
]);
|
|
34112
|
+
function startCodexAgentBridgeSession(input) {
|
|
34113
|
+
return new CodexAgentBridgeSessionImpl(input);
|
|
34114
|
+
}
|
|
34115
|
+
var codexAgentBridgeRuntime = {
|
|
34116
|
+
start: startCodexAgentBridgeSession
|
|
34117
|
+
};
|
|
34118
|
+
var CodexAgentBridgeSessionImpl = class {
|
|
34119
|
+
input;
|
|
34120
|
+
proc = null;
|
|
34121
|
+
startup = null;
|
|
34122
|
+
closed = false;
|
|
34123
|
+
nextRequestId = 1;
|
|
34124
|
+
pending = /* @__PURE__ */ new Map();
|
|
34125
|
+
stdoutBuffer = "";
|
|
34126
|
+
threadId = null;
|
|
34127
|
+
activeTurnId = null;
|
|
34128
|
+
// Tool-like items started but not yet completed in the active turn. A non-empty
|
|
34129
|
+
// set means an interrupt/steer would race an unsettled item (FRA-3049 analog).
|
|
34130
|
+
pendingToolItemIds = /* @__PURE__ */ new Set();
|
|
34131
|
+
settlementWaiters = /* @__PURE__ */ new Set();
|
|
34132
|
+
// Messages held in "deferred" mode while a turn is in flight; flushed as a
|
|
34133
|
+
// fresh turn once the active turn completes.
|
|
34134
|
+
deferredMessages = [];
|
|
34135
|
+
constructor(input) {
|
|
34136
|
+
this.input = input;
|
|
34137
|
+
}
|
|
34138
|
+
async prepare() {
|
|
34139
|
+
await this.ensureStarted();
|
|
34140
|
+
}
|
|
34141
|
+
async sendMessage(message, options) {
|
|
34142
|
+
await this.ensureStarted();
|
|
34143
|
+
const threadId = this.requireThreadId();
|
|
34144
|
+
const mode = options?.mode ?? "interrupt";
|
|
34145
|
+
if (this.activeTurnId === null) {
|
|
34146
|
+
await this.startTurn(threadId, message);
|
|
34147
|
+
return;
|
|
34148
|
+
}
|
|
34149
|
+
if (mode === "deferred") {
|
|
34150
|
+
this.deferredMessages.push(message);
|
|
34151
|
+
this.input.writeOutput?.("agent_bridge_codex_message_deferred");
|
|
34152
|
+
return;
|
|
34153
|
+
}
|
|
34154
|
+
await this.injectIntoActiveTurn(threadId, message);
|
|
34155
|
+
}
|
|
34156
|
+
resolveApproval(resolution) {
|
|
34157
|
+
this.writeFrame({
|
|
34158
|
+
jsonrpc: "2.0",
|
|
34159
|
+
id: resolution.requestId,
|
|
34160
|
+
result: { decision: resolution.decision }
|
|
34161
|
+
});
|
|
34162
|
+
this.input.writeOutput?.(
|
|
34163
|
+
`agent_bridge_codex_approval_resolved decision=${resolution.decision}`
|
|
34164
|
+
);
|
|
34165
|
+
}
|
|
34166
|
+
close() {
|
|
34167
|
+
if (this.closed) {
|
|
34168
|
+
return;
|
|
34169
|
+
}
|
|
34170
|
+
this.closed = true;
|
|
34171
|
+
if (this.threadId && this.activeTurnId) {
|
|
34172
|
+
this.writeFrame({
|
|
34173
|
+
jsonrpc: "2.0",
|
|
34174
|
+
id: this.allocRequestId(),
|
|
34175
|
+
method: "turn/interrupt",
|
|
34176
|
+
params: { threadId: this.threadId, turnId: this.activeTurnId }
|
|
34177
|
+
});
|
|
34178
|
+
}
|
|
34179
|
+
this.activeTurnId = null;
|
|
34180
|
+
this.pendingToolItemIds.clear();
|
|
34181
|
+
this.resolveSettlement();
|
|
34182
|
+
this.rejectAllPending(new Error("Codex session is closed"));
|
|
34183
|
+
if (this.deferredMessages.length > 0) {
|
|
34184
|
+
this.input.writeOutput?.(
|
|
34185
|
+
`agent_bridge_codex_deferred_dropped count=${this.deferredMessages.length} reason=session_closed`
|
|
34186
|
+
);
|
|
34187
|
+
this.deferredMessages.length = 0;
|
|
34188
|
+
}
|
|
34189
|
+
this.proc?.kill("SIGTERM");
|
|
34190
|
+
this.proc = null;
|
|
34191
|
+
}
|
|
34192
|
+
// ---------------------------------------------------------------------------
|
|
34193
|
+
// Startup
|
|
34194
|
+
// ---------------------------------------------------------------------------
|
|
34195
|
+
ensureStarted() {
|
|
34196
|
+
if (this.startup) {
|
|
34197
|
+
return this.startup;
|
|
34198
|
+
}
|
|
34199
|
+
this.startup = this.start().catch((error51) => {
|
|
34200
|
+
this.startup = null;
|
|
34201
|
+
this.close();
|
|
34202
|
+
throw error51;
|
|
34203
|
+
});
|
|
34204
|
+
return this.startup;
|
|
34205
|
+
}
|
|
34206
|
+
async start() {
|
|
34207
|
+
const options = codexLaunchOptions(this.input.codex);
|
|
34208
|
+
mkdirSync4(options.codexHome, { recursive: true });
|
|
34209
|
+
writeFileSync4(join4(options.codexHome, "config.toml"), options.configToml);
|
|
34210
|
+
const startedAt = Date.now();
|
|
34211
|
+
this.input.writeOutput?.(
|
|
34212
|
+
`agent_bridge_codex_startup_started codex_home=${options.codexHome}`
|
|
34213
|
+
);
|
|
34214
|
+
const proc = spawn2(options.command, options.args, {
|
|
34215
|
+
env: options.env,
|
|
34216
|
+
stdio: ["pipe", "pipe", "pipe"]
|
|
34217
|
+
});
|
|
34218
|
+
this.proc = proc;
|
|
34219
|
+
proc.stdout.setEncoding("utf8");
|
|
34220
|
+
proc.stdout.on("data", (chunk) => this.onStdout(chunk));
|
|
34221
|
+
proc.stderr.setEncoding("utf8");
|
|
34222
|
+
proc.stderr.on(
|
|
34223
|
+
"data",
|
|
34224
|
+
(chunk) => this.input.writeOutput?.(`agent_bridge_codex_stderr ${chunk.trimEnd()}`)
|
|
34225
|
+
);
|
|
34226
|
+
proc.on("exit", (code) => this.onProcessExit(code));
|
|
34227
|
+
proc.on("error", (error51) => void this.input.onError(error51));
|
|
34228
|
+
await this.request("initialize", {
|
|
34229
|
+
clientInfo: {
|
|
34230
|
+
name: "auto-agent-bridge",
|
|
34231
|
+
title: "Auto",
|
|
34232
|
+
version: "1"
|
|
34233
|
+
},
|
|
34234
|
+
capabilities: null
|
|
34235
|
+
});
|
|
34236
|
+
this.notify("initialized");
|
|
34237
|
+
await this.openThread();
|
|
34238
|
+
this.input.writeOutput?.(
|
|
34239
|
+
`agent_bridge_codex_startup_ready duration_ms=${Date.now() - startedAt} thread_id=${this.threadId ?? ""}`
|
|
34240
|
+
);
|
|
34241
|
+
}
|
|
34242
|
+
// Resume the stored thread when present, falling back to a fresh thread if the
|
|
34243
|
+
// resume is rejected (e.g. the rollout was pruned). A fresh thread carries the
|
|
34244
|
+
// neutral thread params (cwd + the agent identity as developerInstructions).
|
|
34245
|
+
async openThread() {
|
|
34246
|
+
if (this.input.resumeThreadId) {
|
|
34247
|
+
try {
|
|
34248
|
+
const resumed = await this.request("thread/resume", {
|
|
34249
|
+
threadId: this.input.resumeThreadId
|
|
34250
|
+
});
|
|
34251
|
+
this.adoptThreadId(resumed);
|
|
34252
|
+
return;
|
|
34253
|
+
} catch (error51) {
|
|
34254
|
+
this.input.writeOutput?.(
|
|
34255
|
+
`agent_bridge_codex_resume_fallback thread_id=${this.input.resumeThreadId} error=${errorMessage2(error51)}`
|
|
34256
|
+
);
|
|
34257
|
+
}
|
|
34258
|
+
}
|
|
34259
|
+
const started = await this.request(
|
|
34260
|
+
"thread/start",
|
|
34261
|
+
codexThreadParams(this.input.codex)
|
|
34262
|
+
);
|
|
34263
|
+
this.adoptThreadId(started);
|
|
34264
|
+
}
|
|
34265
|
+
adoptThreadId(result) {
|
|
34266
|
+
const threadId = threadIdFromResult(result);
|
|
34267
|
+
if (!threadId) {
|
|
34268
|
+
throw new Error("Codex thread response did not include a thread id");
|
|
34269
|
+
}
|
|
34270
|
+
this.threadId = threadId;
|
|
34271
|
+
this.input.onThreadId(threadId);
|
|
34272
|
+
}
|
|
34273
|
+
// ---------------------------------------------------------------------------
|
|
34274
|
+
// Turn delivery
|
|
34275
|
+
// ---------------------------------------------------------------------------
|
|
34276
|
+
async startTurn(threadId, message) {
|
|
34277
|
+
await this.request("turn/start", {
|
|
34278
|
+
threadId,
|
|
34279
|
+
input: [userTextInput(message)]
|
|
34280
|
+
});
|
|
34281
|
+
}
|
|
34282
|
+
// Inject a message into the active turn. Prefers `turn/steer` (codex folds the
|
|
34283
|
+
// input into the running turn and owns transcript consistency); falls back to a
|
|
34284
|
+
// hard `turn/interrupt` + fresh `turn/start` when the turn cannot be steered.
|
|
34285
|
+
async injectIntoActiveTurn(threadId, message) {
|
|
34286
|
+
await this.awaitItemSettlement();
|
|
34287
|
+
const expectedTurnId = this.activeTurnId;
|
|
34288
|
+
if (expectedTurnId === null) {
|
|
34289
|
+
await this.startTurn(threadId, message);
|
|
34290
|
+
return;
|
|
34291
|
+
}
|
|
34292
|
+
try {
|
|
34293
|
+
await this.request("turn/steer", {
|
|
34294
|
+
threadId,
|
|
34295
|
+
input: [userTextInput(message)],
|
|
34296
|
+
expectedTurnId
|
|
34297
|
+
});
|
|
34298
|
+
this.input.writeOutput?.("agent_bridge_codex_steered");
|
|
34299
|
+
return;
|
|
34300
|
+
} catch (error51) {
|
|
34301
|
+
this.input.writeOutput?.(
|
|
34302
|
+
`agent_bridge_codex_steer_failed error=${errorMessage2(error51)}`
|
|
34303
|
+
);
|
|
34304
|
+
}
|
|
34305
|
+
if (this.activeTurnId) {
|
|
34306
|
+
await this.interruptActiveTurn(threadId, this.activeTurnId);
|
|
34307
|
+
}
|
|
34308
|
+
await this.startTurn(threadId, message);
|
|
34309
|
+
}
|
|
34310
|
+
async interruptActiveTurn(threadId, turnId) {
|
|
34311
|
+
try {
|
|
34312
|
+
await this.request("turn/interrupt", { threadId, turnId });
|
|
34313
|
+
this.input.writeOutput?.("agent_bridge_codex_interrupted");
|
|
34314
|
+
} catch (error51) {
|
|
34315
|
+
this.input.writeOutput?.(
|
|
34316
|
+
`agent_bridge_codex_interrupt_failed error=${errorMessage2(error51)}`
|
|
34317
|
+
);
|
|
34318
|
+
}
|
|
34319
|
+
}
|
|
34320
|
+
flushDeferredMessages() {
|
|
34321
|
+
if (this.deferredMessages.length === 0 || this.threadId === null) {
|
|
34322
|
+
return;
|
|
34323
|
+
}
|
|
34324
|
+
const pending = this.deferredMessages.splice(0);
|
|
34325
|
+
this.input.writeOutput?.(
|
|
34326
|
+
`agent_bridge_codex_deferred_flush count=${pending.length}`
|
|
34327
|
+
);
|
|
34328
|
+
void (async () => {
|
|
34329
|
+
for (const message of pending) {
|
|
34330
|
+
try {
|
|
34331
|
+
await this.sendMessage(message, { mode: "interrupt" });
|
|
34332
|
+
} catch (error51) {
|
|
34333
|
+
void this.input.onError(error51);
|
|
34334
|
+
}
|
|
34335
|
+
}
|
|
34336
|
+
})();
|
|
34337
|
+
}
|
|
34338
|
+
// ---------------------------------------------------------------------------
|
|
34339
|
+
// Item settlement
|
|
34340
|
+
// ---------------------------------------------------------------------------
|
|
34341
|
+
awaitItemSettlement() {
|
|
34342
|
+
if (this.pendingToolItemIds.size === 0) {
|
|
34343
|
+
return Promise.resolve();
|
|
34344
|
+
}
|
|
34345
|
+
return new Promise((resolve4) => {
|
|
34346
|
+
let done = false;
|
|
34347
|
+
const finish = () => {
|
|
34348
|
+
if (done) {
|
|
34349
|
+
return;
|
|
34350
|
+
}
|
|
34351
|
+
done = true;
|
|
34352
|
+
clearTimeout(timer);
|
|
34353
|
+
this.settlementWaiters.delete(waiter);
|
|
34354
|
+
resolve4();
|
|
34355
|
+
};
|
|
34356
|
+
const waiter = () => finish();
|
|
34357
|
+
const timer = setTimeout(finish, CODEX_ITEM_SETTLE_TIMEOUT_MS);
|
|
34358
|
+
timer.unref?.();
|
|
34359
|
+
this.settlementWaiters.add(waiter);
|
|
34360
|
+
});
|
|
34361
|
+
}
|
|
34362
|
+
resolveSettlement() {
|
|
34363
|
+
if (this.settlementWaiters.size === 0) {
|
|
34364
|
+
return;
|
|
34365
|
+
}
|
|
34366
|
+
const waiters = [...this.settlementWaiters];
|
|
34367
|
+
this.settlementWaiters.clear();
|
|
34368
|
+
for (const waiter of waiters) {
|
|
34369
|
+
waiter();
|
|
34370
|
+
}
|
|
34371
|
+
}
|
|
34372
|
+
// ---------------------------------------------------------------------------
|
|
34373
|
+
// Incoming frame handling
|
|
34374
|
+
// ---------------------------------------------------------------------------
|
|
34375
|
+
onStdout(chunk) {
|
|
34376
|
+
this.stdoutBuffer += chunk;
|
|
34377
|
+
let newline = this.stdoutBuffer.indexOf("\n");
|
|
34378
|
+
while (newline >= 0) {
|
|
34379
|
+
const line = this.stdoutBuffer.slice(0, newline).trim();
|
|
34380
|
+
this.stdoutBuffer = this.stdoutBuffer.slice(newline + 1);
|
|
34381
|
+
if (line) {
|
|
34382
|
+
this.handleFrame(line);
|
|
34383
|
+
}
|
|
34384
|
+
newline = this.stdoutBuffer.indexOf("\n");
|
|
34385
|
+
}
|
|
34386
|
+
}
|
|
34387
|
+
handleFrame(line) {
|
|
34388
|
+
let message;
|
|
34389
|
+
try {
|
|
34390
|
+
message = parseCodexServerFrame(JSON.parse(line));
|
|
34391
|
+
} catch (error51) {
|
|
34392
|
+
this.input.writeOutput?.(
|
|
34393
|
+
`agent_bridge_codex_parse_failed error=${errorMessage2(error51)}`
|
|
34394
|
+
);
|
|
34395
|
+
return;
|
|
34396
|
+
}
|
|
34397
|
+
switch (message.kind) {
|
|
34398
|
+
case "response":
|
|
34399
|
+
this.settleResponse(message.id, message.result, message.error);
|
|
34400
|
+
return;
|
|
34401
|
+
case "notification":
|
|
34402
|
+
this.trackNotification(message.notification);
|
|
34403
|
+
void this.input.onNotification(message.notification);
|
|
34404
|
+
return;
|
|
34405
|
+
case "serverRequest":
|
|
34406
|
+
void this.input.onServerRequest(message.request);
|
|
34407
|
+
return;
|
|
34408
|
+
case "elicitation":
|
|
34409
|
+
this.writeFrame({
|
|
34410
|
+
jsonrpc: "2.0",
|
|
34411
|
+
id: message.requestId,
|
|
34412
|
+
result: { action: "accept", content: {}, _meta: null }
|
|
34413
|
+
});
|
|
34414
|
+
this.input.writeOutput?.(
|
|
34415
|
+
`agent_bridge_codex_elicitation_accepted server=${message.serverName}`
|
|
34416
|
+
);
|
|
34417
|
+
return;
|
|
34418
|
+
case "unsupportedRequest":
|
|
34419
|
+
this.writeFrame({
|
|
34420
|
+
jsonrpc: "2.0",
|
|
34421
|
+
id: message.requestId,
|
|
34422
|
+
error: { code: -32601, message: "Unsupported by Auto bridge" }
|
|
34423
|
+
});
|
|
34424
|
+
this.input.writeOutput?.(
|
|
34425
|
+
`agent_bridge_codex_unsupported_request method=${message.method}`
|
|
34426
|
+
);
|
|
34427
|
+
return;
|
|
34428
|
+
case "ignored":
|
|
34429
|
+
return;
|
|
34430
|
+
}
|
|
34431
|
+
}
|
|
34432
|
+
// Track turn/item lifecycle so steer/interrupt target the live turn and gate on
|
|
34433
|
+
// tool-item settlement.
|
|
34434
|
+
trackNotification(notification) {
|
|
34435
|
+
switch (notification.type) {
|
|
34436
|
+
case "turnStarted":
|
|
34437
|
+
this.activeTurnId = notification.turnId;
|
|
34438
|
+
return;
|
|
34439
|
+
case "turnCompleted":
|
|
34440
|
+
if (notification.turnId === this.activeTurnId) {
|
|
34441
|
+
this.activeTurnId = null;
|
|
34442
|
+
}
|
|
34443
|
+
this.pendingToolItemIds.clear();
|
|
34444
|
+
this.resolveSettlement();
|
|
34445
|
+
this.flushDeferredMessages();
|
|
34446
|
+
return;
|
|
34447
|
+
case "itemStarted":
|
|
34448
|
+
if (CODEX_TOOL_ITEM_TYPES.has(notification.item.type)) {
|
|
34449
|
+
this.pendingToolItemIds.add(notification.item.id);
|
|
34450
|
+
}
|
|
34451
|
+
return;
|
|
34452
|
+
case "itemCompleted":
|
|
34453
|
+
this.pendingToolItemIds.delete(notification.item.id);
|
|
34454
|
+
if (this.pendingToolItemIds.size === 0) {
|
|
34455
|
+
this.resolveSettlement();
|
|
34456
|
+
}
|
|
34457
|
+
return;
|
|
34458
|
+
default:
|
|
34459
|
+
return;
|
|
34460
|
+
}
|
|
34461
|
+
}
|
|
34462
|
+
onProcessExit(code) {
|
|
34463
|
+
this.rejectAllPending(
|
|
34464
|
+
new Error(`Codex app-server exited (code ${code ?? "unknown"})`)
|
|
34465
|
+
);
|
|
34466
|
+
this.activeTurnId = null;
|
|
34467
|
+
this.pendingToolItemIds.clear();
|
|
34468
|
+
this.resolveSettlement();
|
|
34469
|
+
this.input.writeOutput?.(`agent_bridge_codex_exited code=${code ?? ""}`);
|
|
34470
|
+
if (!this.closed) {
|
|
34471
|
+
this.closed = true;
|
|
34472
|
+
this.input.onExit();
|
|
34473
|
+
}
|
|
34474
|
+
}
|
|
34475
|
+
// ---------------------------------------------------------------------------
|
|
34476
|
+
// JSON-RPC transport
|
|
34477
|
+
// ---------------------------------------------------------------------------
|
|
34478
|
+
request(method, params) {
|
|
34479
|
+
const id = this.allocRequestId();
|
|
34480
|
+
const frame = { jsonrpc: "2.0", id, method, params };
|
|
34481
|
+
return new Promise((resolve4, reject) => {
|
|
34482
|
+
this.pending.set(id, { resolve: resolve4, reject });
|
|
34483
|
+
const timer = setTimeout(() => {
|
|
34484
|
+
if (this.pending.delete(id)) {
|
|
34485
|
+
reject(new Error(`Codex request timed out: ${method}`));
|
|
34486
|
+
}
|
|
34487
|
+
}, CODEX_REQUEST_TIMEOUT_MS);
|
|
34488
|
+
timer.unref?.();
|
|
34489
|
+
this.writeFrame(frame);
|
|
34490
|
+
});
|
|
34491
|
+
}
|
|
34492
|
+
settleResponse(id, result, error51) {
|
|
34493
|
+
if (typeof id !== "number") {
|
|
34494
|
+
return;
|
|
34495
|
+
}
|
|
34496
|
+
const pending = this.pending.get(id);
|
|
34497
|
+
if (!pending) {
|
|
34498
|
+
return;
|
|
34499
|
+
}
|
|
34500
|
+
this.pending.delete(id);
|
|
34501
|
+
if (error51 !== void 0) {
|
|
34502
|
+
pending.reject(new Error(error51));
|
|
34503
|
+
return;
|
|
34504
|
+
}
|
|
34505
|
+
pending.resolve(result);
|
|
34506
|
+
}
|
|
34507
|
+
rejectAllPending(error51) {
|
|
34508
|
+
const pending = [...this.pending.values()];
|
|
34509
|
+
this.pending.clear();
|
|
34510
|
+
for (const request of pending) {
|
|
34511
|
+
request.reject(error51);
|
|
34512
|
+
}
|
|
34513
|
+
}
|
|
34514
|
+
notify(method, params) {
|
|
34515
|
+
this.writeFrame({
|
|
34516
|
+
jsonrpc: "2.0",
|
|
34517
|
+
method,
|
|
34518
|
+
...params !== void 0 ? { params } : {}
|
|
34519
|
+
});
|
|
34520
|
+
}
|
|
34521
|
+
writeFrame(frame) {
|
|
34522
|
+
const proc = this.proc;
|
|
34523
|
+
if (!proc || proc.stdin.destroyed) {
|
|
34524
|
+
return;
|
|
34525
|
+
}
|
|
34526
|
+
proc.stdin.write(`${JSON.stringify(frame)}
|
|
34527
|
+
`);
|
|
34528
|
+
}
|
|
34529
|
+
allocRequestId() {
|
|
34530
|
+
const id = this.nextRequestId;
|
|
34531
|
+
this.nextRequestId += 1;
|
|
34532
|
+
return id;
|
|
34533
|
+
}
|
|
34534
|
+
requireThreadId() {
|
|
34535
|
+
if (this.threadId === null) {
|
|
34536
|
+
throw new Error("Codex session has no active thread");
|
|
34537
|
+
}
|
|
34538
|
+
return this.threadId;
|
|
34539
|
+
}
|
|
34540
|
+
};
|
|
34541
|
+
function userTextInput(text) {
|
|
34542
|
+
return { type: "text", text, text_elements: [] };
|
|
34543
|
+
}
|
|
34544
|
+
function threadIdFromResult(result) {
|
|
34545
|
+
if (result === null || typeof result !== "object") {
|
|
34546
|
+
return null;
|
|
34547
|
+
}
|
|
34548
|
+
const thread = result.thread;
|
|
34549
|
+
if (thread === null || typeof thread !== "object") {
|
|
34550
|
+
return null;
|
|
34551
|
+
}
|
|
34552
|
+
const id = thread.id;
|
|
34553
|
+
return typeof id === "string" && id.length > 0 ? id : null;
|
|
34554
|
+
}
|
|
34555
|
+
function errorMessage2(error51) {
|
|
34556
|
+
return error51 instanceof Error ? error51.message : String(error51);
|
|
34557
|
+
}
|
|
34558
|
+
|
|
34559
|
+
// src/commands/agent-bridge/harness/codex/index.ts
|
|
34560
|
+
function createCodexCommandHandler(input) {
|
|
34561
|
+
return new CodexCommandHandler({
|
|
34562
|
+
...input,
|
|
34563
|
+
sessionResume: input.sessionResume ?? fileCodexThreadResumeStore()
|
|
34564
|
+
});
|
|
34565
|
+
}
|
|
34566
|
+
var CodexCommandHandler = class {
|
|
34567
|
+
constructor(input) {
|
|
34568
|
+
this.input = input;
|
|
34569
|
+
this.outputBuffer = new AgentBridgeOutputBuffer(input);
|
|
34570
|
+
}
|
|
34571
|
+
input;
|
|
34572
|
+
context = null;
|
|
34573
|
+
session = null;
|
|
34574
|
+
injectedCommands = /* @__PURE__ */ new Set();
|
|
34575
|
+
// itemId -> JSON-RPC request id of the parked approval request, so an `answer`
|
|
34576
|
+
// command keyed by toolCallId (= itemId) can resolve the right server request.
|
|
34577
|
+
pendingApprovals = /* @__PURE__ */ new Map();
|
|
34578
|
+
outputBuffer;
|
|
34579
|
+
projector = new CodexProjector();
|
|
34580
|
+
// ---------------------------------------------------------------------------
|
|
34581
|
+
// Lifecycle (public API)
|
|
34582
|
+
// ---------------------------------------------------------------------------
|
|
34583
|
+
setContext(nextContext) {
|
|
34584
|
+
this.context = RuntimeBridgeConnectedPayloadSchema.parse(nextContext);
|
|
34585
|
+
}
|
|
34586
|
+
async replayPendingOutputs() {
|
|
34587
|
+
await this.outputBuffer.replayPendingOutputs();
|
|
34588
|
+
}
|
|
34589
|
+
async prepare() {
|
|
34590
|
+
await this.ensureSession().prepare();
|
|
34591
|
+
}
|
|
34592
|
+
shutdown() {
|
|
34593
|
+
this.session?.close();
|
|
34594
|
+
this.session = null;
|
|
34595
|
+
this.pendingApprovals.clear();
|
|
34596
|
+
}
|
|
34597
|
+
async handleCommand(rawDelivery) {
|
|
34598
|
+
const delivery = RuntimeBridgeCommandDeliverySchema.parse(rawDelivery);
|
|
34599
|
+
const socketId = this.input.socketId?.();
|
|
34600
|
+
const activeContext = this.context;
|
|
34601
|
+
if (!activeContext || delivery.sessionId !== activeContext.sessionId || delivery.runtimeId !== activeContext.runtimeId || delivery.bridgeLeaseId !== activeContext.bridgeLeaseId) {
|
|
34602
|
+
return commandAck({ delivery, socketId, status: "stale_lease" });
|
|
34603
|
+
}
|
|
34604
|
+
if (this.injectedCommands.has(delivery.commandId)) {
|
|
34605
|
+
return commandAck({ delivery, socketId, status: "duplicate" });
|
|
34606
|
+
}
|
|
34607
|
+
if (delivery.kind === "answer") {
|
|
34608
|
+
return this.handleAnswerCommand(delivery, activeContext, socketId);
|
|
34609
|
+
}
|
|
34610
|
+
if (delivery.kind === "stop") {
|
|
34611
|
+
this.injectedCommands.add(delivery.commandId);
|
|
34612
|
+
this.shutdown();
|
|
34613
|
+
return commandAck({ delivery, socketId, status: "injected" });
|
|
34614
|
+
}
|
|
34615
|
+
if (delivery.kind !== "message") {
|
|
34616
|
+
return commandAck({
|
|
34617
|
+
delivery,
|
|
34618
|
+
socketId,
|
|
34619
|
+
status: "failed",
|
|
34620
|
+
error: `Unsupported command kind: ${delivery.kind}`
|
|
34621
|
+
});
|
|
34622
|
+
}
|
|
34623
|
+
const message = deliveryMessage2(delivery);
|
|
34624
|
+
if (message === null) {
|
|
34625
|
+
return commandAck({
|
|
34626
|
+
delivery,
|
|
34627
|
+
socketId,
|
|
34628
|
+
status: "failed",
|
|
34629
|
+
error: "Message command payload must include a string message"
|
|
34630
|
+
});
|
|
34631
|
+
}
|
|
34632
|
+
this.injectedCommands.add(delivery.commandId);
|
|
34633
|
+
try {
|
|
34634
|
+
await this.emitUserMessageEntry(
|
|
34635
|
+
activeContext,
|
|
34636
|
+
delivery.commandId,
|
|
34637
|
+
message
|
|
34638
|
+
);
|
|
34639
|
+
await this.ensureSession().sendMessage(message, {
|
|
34640
|
+
mode: deliveryMode2(delivery)
|
|
34641
|
+
});
|
|
34642
|
+
} catch (error51) {
|
|
34643
|
+
this.injectedCommands.delete(delivery.commandId);
|
|
34644
|
+
return commandAck({
|
|
34645
|
+
delivery,
|
|
34646
|
+
socketId,
|
|
34647
|
+
status: "failed",
|
|
34648
|
+
error: errorMessage3(error51)
|
|
34649
|
+
});
|
|
34650
|
+
}
|
|
34651
|
+
return commandAck({ delivery, socketId, status: "injected" });
|
|
34652
|
+
}
|
|
34653
|
+
// ---------------------------------------------------------------------------
|
|
34654
|
+
// Answering parked approvals
|
|
34655
|
+
// ---------------------------------------------------------------------------
|
|
34656
|
+
async handleAnswerCommand(delivery, activeContext, socketId) {
|
|
34657
|
+
const payload = RuntimeBridgeAnswerCommandPayloadSchema.safeParse(
|
|
34658
|
+
delivery.payload
|
|
34659
|
+
);
|
|
34660
|
+
if (!payload.success) {
|
|
34661
|
+
return commandAck({
|
|
34662
|
+
delivery,
|
|
34663
|
+
socketId,
|
|
34664
|
+
status: "failed",
|
|
34665
|
+
error: "Answer command payload must include toolCallId and answers"
|
|
34666
|
+
});
|
|
34667
|
+
}
|
|
34668
|
+
this.injectedCommands.add(delivery.commandId);
|
|
34669
|
+
const requestId = this.pendingApprovals.get(payload.data.toolCallId);
|
|
34670
|
+
try {
|
|
34671
|
+
if (requestId !== void 0) {
|
|
34672
|
+
this.pendingApprovals.delete(payload.data.toolCallId);
|
|
34673
|
+
const decision = codexApprovalDecision({
|
|
34674
|
+
answers: payload.data.answers,
|
|
34675
|
+
...payload.data.response ? { response: payload.data.response } : {}
|
|
34676
|
+
});
|
|
34677
|
+
this.ensureSession().resolveApproval({ requestId, decision });
|
|
34678
|
+
this.input.writeOutput?.(
|
|
34679
|
+
`agent_bridge_codex_question_answered tool_use_id=${payload.data.toolCallId} decision=${decision}`
|
|
34680
|
+
);
|
|
34681
|
+
} else {
|
|
34682
|
+
const message = answerFallbackMessage2(payload.data);
|
|
34683
|
+
await this.emitUserMessageEntry(
|
|
34684
|
+
activeContext,
|
|
34685
|
+
delivery.commandId,
|
|
34686
|
+
message
|
|
34687
|
+
);
|
|
34688
|
+
await this.ensureSession().sendMessage(message);
|
|
34689
|
+
}
|
|
34690
|
+
} catch (error51) {
|
|
34691
|
+
this.injectedCommands.delete(delivery.commandId);
|
|
34692
|
+
return commandAck({
|
|
34693
|
+
delivery,
|
|
34694
|
+
socketId,
|
|
34695
|
+
status: "failed",
|
|
34696
|
+
error: errorMessage3(error51)
|
|
34697
|
+
});
|
|
34698
|
+
}
|
|
34699
|
+
return commandAck({ delivery, socketId, status: "injected" });
|
|
34700
|
+
}
|
|
34701
|
+
// ---------------------------------------------------------------------------
|
|
34702
|
+
// Session callbacks
|
|
34703
|
+
// ---------------------------------------------------------------------------
|
|
34704
|
+
async emitUserMessageEntry(activeContext, commandId, message) {
|
|
34705
|
+
await this.emit(activeContext, {
|
|
34706
|
+
type: "entry",
|
|
34707
|
+
entry: {
|
|
34708
|
+
messageId: commandId,
|
|
34709
|
+
role: "user",
|
|
34710
|
+
kind: "message",
|
|
34711
|
+
status: "completed",
|
|
34712
|
+
content: { parts: [{ type: "text", text: message }] }
|
|
34713
|
+
}
|
|
34714
|
+
});
|
|
34715
|
+
}
|
|
34716
|
+
async handleNotification(notification) {
|
|
34717
|
+
const activeContext = this.context;
|
|
34718
|
+
if (!activeContext) {
|
|
34719
|
+
return;
|
|
34720
|
+
}
|
|
34721
|
+
for (const projection of this.projector.project(notification)) {
|
|
34722
|
+
await this.emit(activeContext, projection);
|
|
34723
|
+
}
|
|
34724
|
+
}
|
|
34725
|
+
async handleServerRequest(request) {
|
|
34726
|
+
const activeContext = this.context;
|
|
34727
|
+
if (!activeContext) {
|
|
34728
|
+
return;
|
|
34729
|
+
}
|
|
34730
|
+
this.pendingApprovals.set(request.itemId, request.requestId);
|
|
34731
|
+
this.input.writeOutput?.(
|
|
34732
|
+
`agent_bridge_codex_question_pending tool_use_id=${request.itemId}`
|
|
34733
|
+
);
|
|
34734
|
+
await this.emit(activeContext, this.projector.projectApproval(request));
|
|
34735
|
+
}
|
|
34736
|
+
async handleSessionError(error51) {
|
|
34737
|
+
this.input.writeOutput?.(
|
|
34738
|
+
`agent_bridge_codex_session_failed error=${errorMessage3(error51)}`
|
|
34739
|
+
);
|
|
34740
|
+
const activeContext = this.context;
|
|
34741
|
+
if (!activeContext) {
|
|
34742
|
+
return;
|
|
34743
|
+
}
|
|
34744
|
+
await this.emit(
|
|
34745
|
+
activeContext,
|
|
34746
|
+
this.projector.projectSessionFailure(errorMessage3(error51))
|
|
34747
|
+
);
|
|
34748
|
+
}
|
|
34749
|
+
async emit(activeContext, projection) {
|
|
34750
|
+
try {
|
|
34751
|
+
await this.outputBuffer.emitProjection(activeContext, projection);
|
|
34752
|
+
} catch (error51) {
|
|
34753
|
+
this.input.writeOutput?.(
|
|
34754
|
+
`agent_bridge_output_emit_failed error=${errorMessage3(error51)}`
|
|
34755
|
+
);
|
|
34756
|
+
}
|
|
34757
|
+
}
|
|
34758
|
+
ensureSession() {
|
|
34759
|
+
if (this.session) {
|
|
34760
|
+
return this.session;
|
|
34761
|
+
}
|
|
34762
|
+
const resumeThreadId = this.storedResumeThreadId();
|
|
34763
|
+
const session = codexAgentBridgeRuntime.start({
|
|
34764
|
+
codex: this.input.codex,
|
|
34765
|
+
...resumeThreadId ? { resumeThreadId } : {},
|
|
34766
|
+
onNotification: (notification) => this.handleNotification(notification),
|
|
34767
|
+
onServerRequest: (request) => this.handleServerRequest(request),
|
|
34768
|
+
onThreadId: (threadId) => this.persistThreadId(threadId),
|
|
34769
|
+
onError: (error51) => this.handleSessionError(error51),
|
|
34770
|
+
onExit: () => {
|
|
34771
|
+
if (this.session === session) {
|
|
34772
|
+
this.session = null;
|
|
34773
|
+
}
|
|
34774
|
+
this.input.writeOutput?.("agent_bridge_codex_session_exited");
|
|
34775
|
+
},
|
|
34776
|
+
...this.input.writeOutput ? { writeOutput: this.input.writeOutput } : {}
|
|
34777
|
+
});
|
|
34778
|
+
this.session = session;
|
|
34779
|
+
return session;
|
|
34780
|
+
}
|
|
34781
|
+
storedResumeThreadId() {
|
|
34782
|
+
const store = this.input.sessionResume;
|
|
34783
|
+
const activeContext = this.context;
|
|
34784
|
+
if (!store || !activeContext) {
|
|
34785
|
+
return void 0;
|
|
34786
|
+
}
|
|
34787
|
+
try {
|
|
34788
|
+
return store.read(activeContext.sessionId) ?? void 0;
|
|
34789
|
+
} catch (error51) {
|
|
34790
|
+
this.input.writeOutput?.(
|
|
34791
|
+
`agent_bridge_codex_thread_read_failed error=${errorMessage3(error51)}`
|
|
34792
|
+
);
|
|
34793
|
+
return void 0;
|
|
34794
|
+
}
|
|
34795
|
+
}
|
|
34796
|
+
persistThreadId(threadId) {
|
|
34797
|
+
const store = this.input.sessionResume;
|
|
34798
|
+
const activeContext = this.context;
|
|
34799
|
+
if (!store || !activeContext) {
|
|
34800
|
+
return;
|
|
34801
|
+
}
|
|
34802
|
+
try {
|
|
34803
|
+
store.write({ sessionId: activeContext.sessionId, threadId });
|
|
34804
|
+
} catch (error51) {
|
|
34805
|
+
this.input.writeOutput?.(
|
|
34806
|
+
`agent_bridge_codex_thread_persist_failed error=${errorMessage3(error51)}`
|
|
34807
|
+
);
|
|
34808
|
+
}
|
|
34809
|
+
}
|
|
34810
|
+
};
|
|
34811
|
+
function answerFallbackMessage2(answer) {
|
|
34812
|
+
const lines = Object.entries(answer.answers).map(
|
|
34813
|
+
([question, value]) => `- ${question}: ${value}`
|
|
34814
|
+
);
|
|
34815
|
+
if (answer.response) {
|
|
34816
|
+
lines.push(`The user also responded: ${answer.response}`);
|
|
34817
|
+
}
|
|
34818
|
+
return ["The user answered your questions:", ...lines].join("\n");
|
|
34819
|
+
}
|
|
34820
|
+
function deliveryMessage2(delivery) {
|
|
34821
|
+
const payload = delivery.payload;
|
|
34822
|
+
if (payload && typeof payload === "object" && "message" in payload && typeof payload.message === "string") {
|
|
34823
|
+
return payload.message;
|
|
34824
|
+
}
|
|
34825
|
+
return null;
|
|
34826
|
+
}
|
|
34827
|
+
function deliveryMode2(delivery) {
|
|
34828
|
+
const payload = delivery.payload;
|
|
34829
|
+
if (payload && typeof payload === "object" && "deliveryMode" in payload) {
|
|
34830
|
+
const parsed = MessageDeliveryModeSchema.safeParse(payload.deliveryMode);
|
|
34831
|
+
if (parsed.success) {
|
|
34832
|
+
return parsed.data;
|
|
34833
|
+
}
|
|
34834
|
+
}
|
|
34835
|
+
return "interrupt";
|
|
34836
|
+
}
|
|
34837
|
+
function errorMessage3(error51) {
|
|
34838
|
+
return error51 instanceof Error ? error51.message : String(error51);
|
|
34839
|
+
}
|
|
34840
|
+
|
|
34841
|
+
// src/commands/agent-bridge/harness/index.ts
|
|
34842
|
+
async function runAgentBridgeHarness(options) {
|
|
34843
|
+
await runAgentBridgeSocket({
|
|
34844
|
+
...options,
|
|
34845
|
+
createHandler: createHarnessCommandHandler
|
|
34846
|
+
});
|
|
34847
|
+
}
|
|
34848
|
+
function createHarnessCommandHandler(input) {
|
|
34849
|
+
const config2 = resolveHarnessConfig(input.bootstrap);
|
|
34850
|
+
const base = {
|
|
34851
|
+
emitOutput: input.emitOutput,
|
|
34852
|
+
...input.outputSeqStart !== void 0 ? { outputSeqStart: input.outputSeqStart } : {},
|
|
34853
|
+
...input.runtimeLogger ? { runtimeLogger: input.runtimeLogger } : {},
|
|
34854
|
+
socketId: input.socketId,
|
|
34855
|
+
...input.writeOutput ? { writeOutput: input.writeOutput } : {}
|
|
34856
|
+
};
|
|
34857
|
+
switch (config2.kind) {
|
|
34858
|
+
case "claude-code": {
|
|
34859
|
+
const { kind, ...claude } = config2;
|
|
34860
|
+
return createClaudeCodeCommandHandler({
|
|
34861
|
+
...base,
|
|
34862
|
+
claude,
|
|
34863
|
+
sessionResume: fileClaudeSessionResumeStore()
|
|
34864
|
+
});
|
|
34865
|
+
}
|
|
34866
|
+
case "codex": {
|
|
34867
|
+
const { kind, ...codex } = config2;
|
|
34868
|
+
return createCodexCommandHandler({
|
|
34869
|
+
...base,
|
|
34870
|
+
codex,
|
|
34871
|
+
sessionResume: fileCodexThreadResumeStore()
|
|
34872
|
+
});
|
|
34873
|
+
}
|
|
34874
|
+
}
|
|
34875
|
+
}
|
|
34876
|
+
function resolveHarnessConfig(bootstrap) {
|
|
34877
|
+
return bootstrap.harness ?? { kind: "claude-code", ...bootstrap.claude };
|
|
34878
|
+
}
|
|
34879
|
+
|
|
34880
|
+
// src/commands/agent-bridge/runtime-log.ts
|
|
34881
|
+
init_src();
|
|
34882
|
+
var RUNTIME_LOG_COMPONENT = "runtime-cli";
|
|
34883
|
+
var INGEST_BATCH_SIZE = 50;
|
|
34884
|
+
var INGEST_FLUSH_DELAY_MS = 1e3;
|
|
34885
|
+
var INGEST_MAX_QUEUED_LINES = 1e3;
|
|
34886
|
+
function createRuntimeLogger(env = process.env) {
|
|
34887
|
+
const level = parseRuntimeLogLevel(env.AUTO_RUNTIME_LOG_LEVEL);
|
|
34888
|
+
const ingest = createRuntimeLogIngest(env);
|
|
34889
|
+
let nextLogSeq = 1;
|
|
34890
|
+
const emit = (lineLevel) => {
|
|
34891
|
+
return (message, context) => {
|
|
34892
|
+
if (!runtimeLogLevelEnabled(level, lineLevel)) {
|
|
34893
|
+
return;
|
|
34894
|
+
}
|
|
34895
|
+
const line = runtimeLogLine({
|
|
34896
|
+
context,
|
|
34897
|
+
level: lineLevel,
|
|
34898
|
+
logSeq: nextLogSeq,
|
|
34899
|
+
message
|
|
34900
|
+
});
|
|
34901
|
+
nextLogSeq += 1;
|
|
34902
|
+
writeRuntimeLogLine(line);
|
|
34903
|
+
ingest?.enqueue(line);
|
|
34904
|
+
};
|
|
34905
|
+
};
|
|
34906
|
+
return {
|
|
34907
|
+
level,
|
|
34908
|
+
debug: emit("debug"),
|
|
34909
|
+
info: emit("info"),
|
|
34910
|
+
warn: emit("warn"),
|
|
34911
|
+
error: emit("error")
|
|
34912
|
+
};
|
|
34913
|
+
}
|
|
34914
|
+
function runtimeLogLine(input) {
|
|
34915
|
+
return {
|
|
34916
|
+
...input.context ?? {},
|
|
34917
|
+
logSeq: input.logSeq,
|
|
34918
|
+
timestamp: (/* @__PURE__ */ new Date()).toISOString(),
|
|
34919
|
+
level: input.level,
|
|
34920
|
+
component: RUNTIME_LOG_COMPONENT,
|
|
34921
|
+
message: input.message
|
|
34922
|
+
};
|
|
34923
|
+
}
|
|
34924
|
+
function writeRuntimeLogLine(payload) {
|
|
34925
|
+
process.stderr.write(`${JSON.stringify(payload, replaceErrors)}
|
|
34926
|
+
`);
|
|
34927
|
+
}
|
|
34928
|
+
function createRuntimeLogIngest(env) {
|
|
34929
|
+
const url2 = env[RUNTIME_LOG_INGEST_URL_ENV]?.trim();
|
|
34930
|
+
const token2 = env[RUNTIME_LOG_INGEST_TOKEN_ENV]?.trim();
|
|
34931
|
+
if (!url2 || !token2) {
|
|
34932
|
+
return void 0;
|
|
34933
|
+
}
|
|
34934
|
+
const queue = [];
|
|
34935
|
+
let flushTimer;
|
|
34936
|
+
let inFlight = false;
|
|
34937
|
+
const scheduleFlush = () => {
|
|
34938
|
+
if (flushTimer || inFlight) {
|
|
34939
|
+
return;
|
|
34940
|
+
}
|
|
34941
|
+
flushTimer = setTimeout(() => {
|
|
34942
|
+
flushTimer = void 0;
|
|
34943
|
+
void flush();
|
|
34944
|
+
}, INGEST_FLUSH_DELAY_MS);
|
|
34945
|
+
flushTimer.unref?.();
|
|
34946
|
+
};
|
|
34947
|
+
const flush = async () => {
|
|
34948
|
+
if (inFlight || queue.length === 0) {
|
|
34949
|
+
return;
|
|
34950
|
+
}
|
|
34951
|
+
inFlight = true;
|
|
34952
|
+
const batch = queue.splice(0, INGEST_BATCH_SIZE);
|
|
33704
34953
|
try {
|
|
33705
34954
|
const response = await fetch(url2, {
|
|
33706
34955
|
method: "POST",
|
|
@@ -33906,9 +35155,9 @@ function statusAgents(input) {
|
|
|
33906
35155
|
// src/commands/agents/connect.ts
|
|
33907
35156
|
init_resources2();
|
|
33908
35157
|
init_browser();
|
|
33909
|
-
import { existsSync as
|
|
35158
|
+
import { existsSync as existsSync3, mkdtempSync, writeFileSync as writeFileSync5 } from "fs";
|
|
33910
35159
|
import { homedir as homedir3, tmpdir } from "os";
|
|
33911
|
-
import { join as
|
|
35160
|
+
import { join as join6 } from "path";
|
|
33912
35161
|
|
|
33913
35162
|
// src/lib/stdio/secret.ts
|
|
33914
35163
|
async function questionSecret(context, prompt) {
|
|
@@ -34099,7 +35348,7 @@ async function promptForIconUploads(input, options) {
|
|
|
34099
35348
|
}
|
|
34100
35349
|
}
|
|
34101
35350
|
function stagedLocationLabel(stagedPath) {
|
|
34102
|
-
return stagedPath.startsWith(`${
|
|
35351
|
+
return stagedPath.startsWith(`${join6(homedir3(), "Downloads")}/`) ? "Downloads" : "the printed path";
|
|
34103
35352
|
}
|
|
34104
35353
|
async function stageAvatarImage(input) {
|
|
34105
35354
|
try {
|
|
@@ -34111,10 +35360,10 @@ async function stageAvatarImage(input) {
|
|
|
34111
35360
|
}
|
|
34112
35361
|
const contentType = response.headers.get("content-type") ?? "";
|
|
34113
35362
|
const extension = contentType.includes("jpeg") ? ".jpg" : ".png";
|
|
34114
|
-
const downloads =
|
|
34115
|
-
const directory =
|
|
34116
|
-
const path2 =
|
|
34117
|
-
|
|
35363
|
+
const downloads = join6(homedir3(), "Downloads");
|
|
35364
|
+
const directory = existsSync3(downloads) ? downloads : mkdtempSync(join6(tmpdir(), "auto-avatar-"));
|
|
35365
|
+
const path2 = join6(directory, `${input.agent}-avatar${extension}`);
|
|
35366
|
+
writeFileSync5(path2, Buffer.from(await response.arrayBuffer()));
|
|
34118
35367
|
return path2;
|
|
34119
35368
|
} catch {
|
|
34120
35369
|
return void 0;
|
|
@@ -35578,19 +36827,19 @@ init_src();
|
|
|
35578
36827
|
// src/commands/logs/actions.ts
|
|
35579
36828
|
import {
|
|
35580
36829
|
closeSync,
|
|
35581
|
-
existsSync as
|
|
36830
|
+
existsSync as existsSync5,
|
|
35582
36831
|
openSync,
|
|
35583
|
-
readFileSync as
|
|
36832
|
+
readFileSync as readFileSync7,
|
|
35584
36833
|
readSync,
|
|
35585
36834
|
statSync as statSync3
|
|
35586
36835
|
} from "fs";
|
|
35587
36836
|
var DEFAULT_POLL_INTERVAL_MS = 1e3;
|
|
35588
36837
|
async function tailRuntimeLog(input) {
|
|
35589
|
-
if (!
|
|
36838
|
+
if (!existsSync5(input.path)) {
|
|
35590
36839
|
input.writeError(`No runtime log at ${input.path}`);
|
|
35591
36840
|
return;
|
|
35592
36841
|
}
|
|
35593
|
-
const content =
|
|
36842
|
+
const content = readFileSync7(input.path, "utf8");
|
|
35594
36843
|
for (const line of selectLastLines(content, input.lines)) {
|
|
35595
36844
|
input.writeOutput(line);
|
|
35596
36845
|
}
|