@autohq/cli 0.1.224 → 0.1.226
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 +1338 -19
- package/dist/index.js +1483 -167
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -15261,6 +15261,7 @@ var init_auth = __esm({
|
|
|
15261
15261
|
"github:mcp",
|
|
15262
15262
|
"github:credentials",
|
|
15263
15263
|
"mcp:connection",
|
|
15264
|
+
"runtime-logs:write",
|
|
15264
15265
|
"projects:admin",
|
|
15265
15266
|
"org:admin"
|
|
15266
15267
|
]);
|
|
@@ -15965,12 +15966,12 @@ function parseClaudeCodeStreamRecord(parsed) {
|
|
|
15965
15966
|
}
|
|
15966
15967
|
const isError = record2.is_error === true || record2.subtype === "error";
|
|
15967
15968
|
const sdkErrorMessage = record2.errors?.map((error51) => error51.trim()).filter(Boolean).join("\n");
|
|
15968
|
-
const
|
|
15969
|
+
const errorMessage6 = isError ? record2.error ?? record2.result ?? (sdkErrorMessage || void 0) ?? "claude-code reported an error" : void 0;
|
|
15969
15970
|
return {
|
|
15970
15971
|
projections: [],
|
|
15971
15972
|
result: {
|
|
15972
15973
|
isError,
|
|
15973
|
-
errorMessage:
|
|
15974
|
+
errorMessage: errorMessage6
|
|
15974
15975
|
}
|
|
15975
15976
|
};
|
|
15976
15977
|
}
|
|
@@ -16199,7 +16200,249 @@ var init_claude_code = __esm({
|
|
|
16199
16200
|
});
|
|
16200
16201
|
|
|
16201
16202
|
// ../../packages/schemas/src/codex.ts
|
|
16202
|
-
|
|
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;
|
|
16203
16446
|
var init_codex = __esm({
|
|
16204
16447
|
"../../packages/schemas/src/codex.ts"() {
|
|
16205
16448
|
"use strict";
|
|
@@ -16280,6 +16523,8 @@ var init_codex = __esm({
|
|
|
16280
16523
|
result: external_exports.unknown().optional(),
|
|
16281
16524
|
error: external_exports.object({ message: external_exports.string().optional() }).passthrough().optional()
|
|
16282
16525
|
}).passthrough();
|
|
16526
|
+
APPROVE_OPTION_LABEL = "Approve";
|
|
16527
|
+
DECLINE_OPTION_LABEL = "Decline";
|
|
16283
16528
|
}
|
|
16284
16529
|
});
|
|
16285
16530
|
|
|
@@ -19112,21 +19357,6 @@ var init_setup = __esm({
|
|
|
19112
19357
|
}
|
|
19113
19358
|
});
|
|
19114
19359
|
|
|
19115
|
-
// ../../packages/schemas/src/e2b-webhook.ts
|
|
19116
|
-
var E2bLifecycleWebhookEventSchema;
|
|
19117
|
-
var init_e2b_webhook = __esm({
|
|
19118
|
-
"../../packages/schemas/src/e2b-webhook.ts"() {
|
|
19119
|
-
"use strict";
|
|
19120
|
-
init_zod();
|
|
19121
|
-
E2bLifecycleWebhookEventSchema = external_exports.object({
|
|
19122
|
-
type: external_exports.string().min(1),
|
|
19123
|
-
sandbox_id: external_exports.string().min(1),
|
|
19124
|
-
sandbox_execution_id: external_exports.string().optional(),
|
|
19125
|
-
timestamp: external_exports.string().optional()
|
|
19126
|
-
}).passthrough();
|
|
19127
|
-
}
|
|
19128
|
-
});
|
|
19129
|
-
|
|
19130
19360
|
// ../../packages/schemas/src/runtime-log.ts
|
|
19131
19361
|
function parseRuntimeLogLevel(value) {
|
|
19132
19362
|
const parsed = RuntimeLogLevelSchema.safeParse(value?.trim());
|
|
@@ -19135,16 +19365,28 @@ function parseRuntimeLogLevel(value) {
|
|
|
19135
19365
|
function runtimeLogLevelEnabled(configured, lineLevel) {
|
|
19136
19366
|
return LEVEL_SEVERITY[lineLevel] >= LEVEL_SEVERITY[configured];
|
|
19137
19367
|
}
|
|
19138
|
-
var RUNTIME_LOG_LEVELS, RuntimeLogLevelSchema, DEFAULT_RUNTIME_LOG_LEVEL, SANDBOX_RUNTIME_LOG_DIR, SANDBOX_RUNTIME_LOG_PATH, LEVEL_SEVERITY;
|
|
19368
|
+
var RUNTIME_LOG_LEVELS, RuntimeLogLevelSchema, RUNTIME_LOG_INGEST_URL_ENV, RUNTIME_LOG_INGEST_TOKEN_ENV, DEFAULT_RUNTIME_LOG_LEVEL, SANDBOX_RUNTIME_LOG_DIR, SANDBOX_RUNTIME_LOG_PATH, RuntimeLogIngestLineSchema, RuntimeLogIngestRequestSchema, LEVEL_SEVERITY;
|
|
19139
19369
|
var init_runtime_log = __esm({
|
|
19140
19370
|
"../../packages/schemas/src/runtime-log.ts"() {
|
|
19141
19371
|
"use strict";
|
|
19142
19372
|
init_zod();
|
|
19143
19373
|
RUNTIME_LOG_LEVELS = ["debug", "info", "warn", "error"];
|
|
19144
19374
|
RuntimeLogLevelSchema = external_exports.enum(RUNTIME_LOG_LEVELS);
|
|
19375
|
+
RUNTIME_LOG_INGEST_URL_ENV = "AUTO_RUNTIME_LOG_INGEST_URL";
|
|
19376
|
+
RUNTIME_LOG_INGEST_TOKEN_ENV = "AUTO_RUNTIME_LOG_INGEST_TOKEN";
|
|
19145
19377
|
DEFAULT_RUNTIME_LOG_LEVEL = "info";
|
|
19146
19378
|
SANDBOX_RUNTIME_LOG_DIR = "/home/user/.auto-runtime";
|
|
19147
19379
|
SANDBOX_RUNTIME_LOG_PATH = `${SANDBOX_RUNTIME_LOG_DIR}/agent-bridge.log`;
|
|
19380
|
+
RuntimeLogIngestLineSchema = external_exports.object({
|
|
19381
|
+
logSeq: external_exports.number().int().positive(),
|
|
19382
|
+
timestamp: external_exports.string().datetime(),
|
|
19383
|
+
level: RuntimeLogLevelSchema,
|
|
19384
|
+
component: external_exports.string().trim().min(1),
|
|
19385
|
+
message: external_exports.string()
|
|
19386
|
+
}).passthrough();
|
|
19387
|
+
RuntimeLogIngestRequestSchema = external_exports.object({
|
|
19388
|
+
lines: external_exports.array(RuntimeLogIngestLineSchema).min(1).max(100)
|
|
19389
|
+
}).strict();
|
|
19148
19390
|
LEVEL_SEVERITY = {
|
|
19149
19391
|
debug: 10,
|
|
19150
19392
|
info: 20,
|
|
@@ -19303,7 +19545,6 @@ var init_src = __esm({
|
|
|
19303
19545
|
init_secrets();
|
|
19304
19546
|
init_session_commands();
|
|
19305
19547
|
init_setup();
|
|
19306
|
-
init_e2b_webhook();
|
|
19307
19548
|
init_runtime_log();
|
|
19308
19549
|
init_runtime_log_tailer();
|
|
19309
19550
|
init_runtimes();
|
|
@@ -21997,7 +22238,7 @@ var init_package = __esm({
|
|
|
21997
22238
|
"package.json"() {
|
|
21998
22239
|
package_default = {
|
|
21999
22240
|
name: "@autohq/cli",
|
|
22000
|
-
version: "0.1.
|
|
22241
|
+
version: "0.1.226",
|
|
22001
22242
|
license: "SEE LICENSE IN README.md",
|
|
22002
22243
|
publishConfig: {
|
|
22003
22244
|
access: "public"
|
|
@@ -22061,13 +22302,13 @@ var init_version = __esm({
|
|
|
22061
22302
|
});
|
|
22062
22303
|
|
|
22063
22304
|
// src/commands/agents/authoring.ts
|
|
22064
|
-
import { readFileSync as
|
|
22305
|
+
import { readFileSync as readFileSync4, readdirSync as readdirSync2, statSync } from "fs";
|
|
22065
22306
|
import {
|
|
22066
22307
|
basename as basename2,
|
|
22067
|
-
dirname as
|
|
22308
|
+
dirname as dirname5,
|
|
22068
22309
|
extname,
|
|
22069
22310
|
isAbsolute,
|
|
22070
|
-
join as
|
|
22311
|
+
join as join5,
|
|
22071
22312
|
resolve
|
|
22072
22313
|
} from "path";
|
|
22073
22314
|
import { parseAllDocuments as parseYamlDocuments, stringify } from "yaml";
|
|
@@ -22119,8 +22360,8 @@ function renderAgentExplain(result) {
|
|
|
22119
22360
|
return lines.join("\n");
|
|
22120
22361
|
}
|
|
22121
22362
|
function readLocalAgentAuthoringStatuses(input) {
|
|
22122
|
-
const agentsDirectory =
|
|
22123
|
-
input?.directory ??
|
|
22363
|
+
const agentsDirectory = join5(
|
|
22364
|
+
input?.directory ?? join5(process.cwd(), ".auto"),
|
|
22124
22365
|
"agents"
|
|
22125
22366
|
);
|
|
22126
22367
|
const paths = agentAuthoringFiles(agentsDirectory);
|
|
@@ -22159,7 +22400,7 @@ function agentAuthoringFiles(directory) {
|
|
|
22159
22400
|
}
|
|
22160
22401
|
const files = [];
|
|
22161
22402
|
for (const entry of entries) {
|
|
22162
|
-
const path2 =
|
|
22403
|
+
const path2 = join5(directory, entry.name);
|
|
22163
22404
|
if (entry.isDirectory()) {
|
|
22164
22405
|
files.push(...agentAuthoringFiles(path2));
|
|
22165
22406
|
continue;
|
|
@@ -22179,12 +22420,12 @@ function resolveAgentAuthoringPath(input) {
|
|
|
22179
22420
|
if (isAgentFile(candidate)) {
|
|
22180
22421
|
return candidate;
|
|
22181
22422
|
}
|
|
22182
|
-
const agentsDirectory =
|
|
22183
|
-
input.directory ??
|
|
22423
|
+
const agentsDirectory = join5(
|
|
22424
|
+
input.directory ?? join5(process.cwd(), ".auto"),
|
|
22184
22425
|
"agents"
|
|
22185
22426
|
);
|
|
22186
22427
|
for (const extension of AGENT_FILE_EXTENSIONS) {
|
|
22187
|
-
const path2 =
|
|
22428
|
+
const path2 = join5(agentsDirectory, `${input.agent}${extension}`);
|
|
22188
22429
|
if (isAgentFile(path2)) {
|
|
22189
22430
|
return path2;
|
|
22190
22431
|
}
|
|
@@ -22242,7 +22483,7 @@ function readSingleDocument(path2) {
|
|
|
22242
22483
|
return documents[0];
|
|
22243
22484
|
}
|
|
22244
22485
|
function readDocuments(path2) {
|
|
22245
|
-
const source =
|
|
22486
|
+
const source = readFileSync4(path2, "utf8");
|
|
22246
22487
|
const documents = parseYamlDocuments(source);
|
|
22247
22488
|
const parseError = documents.flatMap((document) => document.errors).at(0);
|
|
22248
22489
|
if (parseError) {
|
|
@@ -22267,7 +22508,7 @@ function resolveImportPath(importPath, importerPath) {
|
|
|
22267
22508
|
if (isAbsolute(importPath) || /^[A-Za-z]+:\/\//.test(importPath)) {
|
|
22268
22509
|
throw new Error(`Agent import must be a relative path: ${importPath}`);
|
|
22269
22510
|
}
|
|
22270
|
-
const resolved = resolve(
|
|
22511
|
+
const resolved = resolve(dirname5(importerPath), importPath);
|
|
22271
22512
|
if (!isAgentFile(resolved)) {
|
|
22272
22513
|
throw new Error(
|
|
22273
22514
|
`Agent import not found: ${importPath} from ${importerPath}`
|
|
@@ -22442,7 +22683,7 @@ function resolveFileBackedString(value, input) {
|
|
|
22442
22683
|
`Invalid agent authoring file ${input.path}: ${input.field}.file must be a relative path`
|
|
22443
22684
|
);
|
|
22444
22685
|
}
|
|
22445
|
-
return
|
|
22686
|
+
return readFileSync4(resolve(dirname5(input.path), filePath), "utf8");
|
|
22446
22687
|
}
|
|
22447
22688
|
function removalDirectives(document, path2) {
|
|
22448
22689
|
const raw = isRecord(document.remove) ? document.remove : {};
|
|
@@ -24022,18 +24263,18 @@ var init_project_apply_files2 = __esm({
|
|
|
24022
24263
|
|
|
24023
24264
|
// src/commands/apply/files.ts
|
|
24024
24265
|
import {
|
|
24025
|
-
existsSync as
|
|
24026
|
-
readFileSync as
|
|
24266
|
+
existsSync as existsSync4,
|
|
24267
|
+
readFileSync as readFileSync5,
|
|
24027
24268
|
readdirSync as readdirSync3,
|
|
24028
24269
|
realpathSync,
|
|
24029
24270
|
statSync as statSync2
|
|
24030
24271
|
} from "fs";
|
|
24031
24272
|
import {
|
|
24032
24273
|
basename as basename3,
|
|
24033
|
-
dirname as
|
|
24274
|
+
dirname as dirname6,
|
|
24034
24275
|
extname as extname3,
|
|
24035
24276
|
isAbsolute as isAbsolute2,
|
|
24036
|
-
join as
|
|
24277
|
+
join as join7,
|
|
24037
24278
|
relative,
|
|
24038
24279
|
resolve as resolve2
|
|
24039
24280
|
} from "path";
|
|
@@ -24062,7 +24303,7 @@ function readProjectApplyBundleInput(options) {
|
|
|
24062
24303
|
}
|
|
24063
24304
|
};
|
|
24064
24305
|
}
|
|
24065
|
-
const directory = resolve2(options.directory ??
|
|
24306
|
+
const directory = resolve2(options.directory ?? join7(process.cwd(), ".auto"));
|
|
24066
24307
|
const projectRoot = applyProjectRoot(directory);
|
|
24067
24308
|
const files = sourceFiles(directory, projectRoot);
|
|
24068
24309
|
const resourceRoot = sourcePathRelative(projectRoot, directory);
|
|
@@ -24093,7 +24334,7 @@ function sourceFiles(root, projectRoot) {
|
|
|
24093
24334
|
return [];
|
|
24094
24335
|
}
|
|
24095
24336
|
return entries.flatMap((entry) => {
|
|
24096
|
-
const path2 =
|
|
24337
|
+
const path2 = join7(root, entry.name);
|
|
24097
24338
|
if (entry.isDirectory()) {
|
|
24098
24339
|
return sourceFiles(path2, projectRoot);
|
|
24099
24340
|
}
|
|
@@ -24106,7 +24347,7 @@ function sourceFiles(root, projectRoot) {
|
|
|
24106
24347
|
function sourceFile(path2, projectRoot) {
|
|
24107
24348
|
return {
|
|
24108
24349
|
path: sourcePathRelative(projectRoot, path2),
|
|
24109
|
-
contentBase64:
|
|
24350
|
+
contentBase64: readFileSync5(path2).toString("base64")
|
|
24110
24351
|
};
|
|
24111
24352
|
}
|
|
24112
24353
|
function applyBundle(files) {
|
|
@@ -24140,24 +24381,24 @@ function filesystemAssetReader(projectRoot) {
|
|
|
24140
24381
|
});
|
|
24141
24382
|
return {
|
|
24142
24383
|
path: path2,
|
|
24143
|
-
bytes:
|
|
24384
|
+
bytes: readFileSync5(path2)
|
|
24144
24385
|
};
|
|
24145
24386
|
};
|
|
24146
24387
|
}
|
|
24147
24388
|
function applyProjectRoot(directory) {
|
|
24148
24389
|
const resolved = resolve2(directory);
|
|
24149
|
-
return basename3(resolved) === ".auto" ?
|
|
24390
|
+
return basename3(resolved) === ".auto" ? dirname6(resolved) : resolved;
|
|
24150
24391
|
}
|
|
24151
24392
|
function applyFileProjectRoot(file2) {
|
|
24152
|
-
let dir =
|
|
24393
|
+
let dir = dirname6(resolve2(file2));
|
|
24153
24394
|
while (true) {
|
|
24154
24395
|
if (basename3(dir) === ".auto") {
|
|
24155
|
-
return
|
|
24396
|
+
return dirname6(dir);
|
|
24156
24397
|
}
|
|
24157
24398
|
if (directoryHasAutoRoot(dir)) {
|
|
24158
24399
|
return dir;
|
|
24159
24400
|
}
|
|
24160
|
-
const parent =
|
|
24401
|
+
const parent = dirname6(dir);
|
|
24161
24402
|
if (parent === dir) {
|
|
24162
24403
|
return process.cwd();
|
|
24163
24404
|
}
|
|
@@ -24166,11 +24407,11 @@ function applyFileProjectRoot(file2) {
|
|
|
24166
24407
|
}
|
|
24167
24408
|
function applyFileSourceRoot(file2, projectRoot) {
|
|
24168
24409
|
const autoRoot = resolve2(projectRoot, ".auto");
|
|
24169
|
-
return file2 === autoRoot || isInside(file2, autoRoot) ? autoRoot :
|
|
24410
|
+
return file2 === autoRoot || isInside(file2, autoRoot) ? autoRoot : dirname6(file2);
|
|
24170
24411
|
}
|
|
24171
24412
|
function directoryHasAutoRoot(directory) {
|
|
24172
24413
|
const autoRoot = resolve2(directory, ".auto");
|
|
24173
|
-
if (!
|
|
24414
|
+
if (!existsSync4(autoRoot)) {
|
|
24174
24415
|
return false;
|
|
24175
24416
|
}
|
|
24176
24417
|
return statSync2(autoRoot).isDirectory();
|
|
@@ -24761,16 +25002,16 @@ var init_resources3 = __esm({
|
|
|
24761
25002
|
});
|
|
24762
25003
|
|
|
24763
25004
|
// src/commands/edit/actions.ts
|
|
24764
|
-
import { spawn as
|
|
25005
|
+
import { spawn as spawn3 } from "child_process";
|
|
24765
25006
|
import {
|
|
24766
|
-
mkdirSync as
|
|
25007
|
+
mkdirSync as mkdirSync5,
|
|
24767
25008
|
mkdtempSync as mkdtempSync2,
|
|
24768
|
-
readFileSync as
|
|
25009
|
+
readFileSync as readFileSync6,
|
|
24769
25010
|
rmSync as rmSync2,
|
|
24770
|
-
writeFileSync as
|
|
25011
|
+
writeFileSync as writeFileSync6
|
|
24771
25012
|
} from "fs";
|
|
24772
25013
|
import { tmpdir as tmpdir2 } from "os";
|
|
24773
|
-
import { join as
|
|
25014
|
+
import { join as join8 } from "path";
|
|
24774
25015
|
import { parseAllDocuments as parseYamlDocuments3, stringify as stringify4 } from "yaml";
|
|
24775
25016
|
async function editResource(input) {
|
|
24776
25017
|
const reference = parseProjectResourceReference(input.resource);
|
|
@@ -24790,15 +25031,15 @@ async function editResource(input) {
|
|
|
24790
25031
|
const document = editableAgentFacade(current);
|
|
24791
25032
|
const source = `${stringify4(document).trimEnd()}
|
|
24792
25033
|
`;
|
|
24793
|
-
const tempRoot = mkdtempSync2(
|
|
24794
|
-
const agentsDir =
|
|
24795
|
-
|
|
24796
|
-
const filePath =
|
|
24797
|
-
|
|
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");
|
|
24798
25039
|
let removeTempFile = false;
|
|
24799
25040
|
try {
|
|
24800
25041
|
await runEditor(editor, filePath);
|
|
24801
|
-
const editedSource =
|
|
25042
|
+
const editedSource = readFileSync6(filePath, "utf8");
|
|
24802
25043
|
if (editedSource === source) {
|
|
24803
25044
|
input.writeOutput("No changes; skipped apply.");
|
|
24804
25045
|
removeTempFile = true;
|
|
@@ -24841,7 +25082,7 @@ function resolveEditor(input) {
|
|
|
24841
25082
|
}
|
|
24842
25083
|
async function runEditor(editor, filePath) {
|
|
24843
25084
|
await new Promise((resolve4, reject) => {
|
|
24844
|
-
const child =
|
|
25085
|
+
const child = spawn3(editor, [filePath], {
|
|
24845
25086
|
shell: true,
|
|
24846
25087
|
stdio: "inherit"
|
|
24847
25088
|
});
|
|
@@ -24864,7 +25105,7 @@ async function runEditor(editor, filePath) {
|
|
|
24864
25105
|
});
|
|
24865
25106
|
}
|
|
24866
25107
|
function assertEditedResourceIdentity(filePath, expected) {
|
|
24867
|
-
const source =
|
|
25108
|
+
const source = readFileSync6(filePath, "utf8");
|
|
24868
25109
|
let parsedDocuments;
|
|
24869
25110
|
try {
|
|
24870
25111
|
parsedDocuments = parseYamlDocuments3(source);
|
|
@@ -27986,7 +28227,7 @@ function SessionsView({
|
|
|
27986
28227
|
visibleSessions.map((session, vi) => {
|
|
27987
28228
|
const i = scrollOffset + vi;
|
|
27988
28229
|
const title = sessionDisplayTitle(session);
|
|
27989
|
-
const err = session.status === "failed" ?
|
|
28230
|
+
const err = session.status === "failed" ? errorMessage4(session) : null;
|
|
27990
28231
|
const isSelected = i === safeIndex;
|
|
27991
28232
|
const isMarked = selectedSessionIds.has(session.id);
|
|
27992
28233
|
return /* @__PURE__ */ jsxs10(Box11, { flexDirection: "column", children: [
|
|
@@ -28124,7 +28365,7 @@ function truncateToWidth(value, width) {
|
|
|
28124
28365
|
function agentNameForRun(session) {
|
|
28125
28366
|
return session.snapshot.metadata.name;
|
|
28126
28367
|
}
|
|
28127
|
-
function
|
|
28368
|
+
function errorMessage4(session) {
|
|
28128
28369
|
if (session.error == null) return null;
|
|
28129
28370
|
if (typeof session.error === "string") return session.error;
|
|
28130
28371
|
const msg = readField(session.error, "message");
|
|
@@ -29546,7 +29787,7 @@ function HomeView({ apiUrl, notice, returnToAgent }) {
|
|
|
29546
29787
|
if (inspectedResource) {
|
|
29547
29788
|
sectionTitle = `Inspect ${inspectedResource.kind}/${inspectedResource.name}`;
|
|
29548
29789
|
}
|
|
29549
|
-
const runError =
|
|
29790
|
+
const runError = errorMessage5(triggerSession.error) ?? errorMessage5(archiveSessions.error) ?? errorMessage5(unarchiveSessions.error) ?? errorMessage5(stopSessions.error);
|
|
29550
29791
|
const isRunMutationPending = triggerSession.isPending || archiveSessions.isPending || unarchiveSessions.isPending || stopSessions.isPending;
|
|
29551
29792
|
const isConnectionMutationPending = startConnection.isPending || allowConnection.isPending || removeConnection.isPending || createGithubSyncBinding.isPending;
|
|
29552
29793
|
const serviceAccountStatus = createServiceAccount2.error instanceof Error ? createServiceAccount2.error.message : rotateServiceAccount2.error instanceof Error ? rotateServiceAccount2.error.message : removeServiceAccount2.error instanceof Error ? removeServiceAccount2.error.message : serviceAccountNotice;
|
|
@@ -29959,7 +30200,7 @@ function runActionTargetLabel(sessionIds, markedRunCount) {
|
|
|
29959
30200
|
function pluralizeRunCount(count) {
|
|
29960
30201
|
return `${count} ${count === 1 ? "session" : "sessions"}`;
|
|
29961
30202
|
}
|
|
29962
|
-
function
|
|
30203
|
+
function errorMessage5(error51) {
|
|
29963
30204
|
if (error51 instanceof Error) return error51.message;
|
|
29964
30205
|
return error51 ? String(error51) : null;
|
|
29965
30206
|
}
|
|
@@ -30280,8 +30521,8 @@ __export(launcher_exports, {
|
|
|
30280
30521
|
launch: () => launch
|
|
30281
30522
|
});
|
|
30282
30523
|
import { spawnSync } from "child_process";
|
|
30283
|
-
import { existsSync as
|
|
30284
|
-
import { dirname as
|
|
30524
|
+
import { existsSync as existsSync6 } from "fs";
|
|
30525
|
+
import { dirname as dirname7, resolve as resolve3 } from "path";
|
|
30285
30526
|
import { fileURLToPath } from "url";
|
|
30286
30527
|
import {
|
|
30287
30528
|
QueryClient,
|
|
@@ -30458,7 +30699,7 @@ function resolveSplashVersion() {
|
|
|
30458
30699
|
return resolveLatestReleaseVersionFromCheckout() ?? cliVersion;
|
|
30459
30700
|
}
|
|
30460
30701
|
function resolveLatestReleaseVersionFromCheckout() {
|
|
30461
|
-
const repoRoot = findRepoRoot(
|
|
30702
|
+
const repoRoot = findRepoRoot(dirname7(fileURLToPath(import.meta.url)));
|
|
30462
30703
|
if (!repoRoot) {
|
|
30463
30704
|
return null;
|
|
30464
30705
|
}
|
|
@@ -30475,10 +30716,10 @@ function resolveLatestReleaseVersionFromCheckout() {
|
|
|
30475
30716
|
function findRepoRoot(startDirectory) {
|
|
30476
30717
|
let directory = startDirectory;
|
|
30477
30718
|
while (true) {
|
|
30478
|
-
if (
|
|
30719
|
+
if (existsSync6(resolve3(directory, ".git")) && existsSync6(resolve3(directory, "apps/cli/package.json"))) {
|
|
30479
30720
|
return directory;
|
|
30480
30721
|
}
|
|
30481
|
-
const parent =
|
|
30722
|
+
const parent = dirname7(directory);
|
|
30482
30723
|
if (parent === directory) {
|
|
30483
30724
|
return null;
|
|
30484
30725
|
}
|
|
@@ -31479,6 +31720,9 @@ var AgentBridgeClaudeConfigSchema = AgentBridgeHarnessBaseConfigSchema;
|
|
|
31479
31720
|
var AgentBridgeHarnessConfigSchema = external_exports.discriminatedUnion("kind", [
|
|
31480
31721
|
AgentBridgeHarnessBaseConfigSchema.extend({
|
|
31481
31722
|
kind: external_exports.literal("claude-code")
|
|
31723
|
+
}),
|
|
31724
|
+
AgentBridgeHarnessBaseConfigSchema.extend({
|
|
31725
|
+
kind: external_exports.literal("codex")
|
|
31482
31726
|
})
|
|
31483
31727
|
]);
|
|
31484
31728
|
var RuntimeBridgeBootstrapPlaintextSchema = external_exports.object({
|
|
@@ -33600,112 +33844,1184 @@ function commandLogContext(delivery, fields = {}) {
|
|
|
33600
33844
|
};
|
|
33601
33845
|
}
|
|
33602
33846
|
|
|
33603
|
-
// src/commands/agent-bridge/harness/index.ts
|
|
33604
|
-
|
|
33605
|
-
|
|
33606
|
-
|
|
33607
|
-
|
|
33847
|
+
// src/commands/agent-bridge/harness/codex/index.ts
|
|
33848
|
+
init_src();
|
|
33849
|
+
|
|
33850
|
+
// src/commands/agent-bridge/harness/codex/projector.ts
|
|
33851
|
+
init_src();
|
|
33852
|
+
var CodexProjector = class {
|
|
33853
|
+
project(notification) {
|
|
33854
|
+
switch (notification.type) {
|
|
33855
|
+
case "agentMessageDelta":
|
|
33856
|
+
return [
|
|
33857
|
+
{
|
|
33858
|
+
type: "delta",
|
|
33859
|
+
delta: {
|
|
33860
|
+
messageId: notification.itemId,
|
|
33861
|
+
partId: "0",
|
|
33862
|
+
role: "assistant",
|
|
33863
|
+
kind: "message",
|
|
33864
|
+
delta: { type: "text", text: notification.delta }
|
|
33865
|
+
}
|
|
33866
|
+
}
|
|
33867
|
+
];
|
|
33868
|
+
case "itemStarted":
|
|
33869
|
+
return entryProjections(
|
|
33870
|
+
projectCodexItem({ item: notification.item, phase: "started" })
|
|
33871
|
+
);
|
|
33872
|
+
case "itemCompleted":
|
|
33873
|
+
return entryProjections(
|
|
33874
|
+
projectCodexItem({ item: notification.item, phase: "completed" })
|
|
33875
|
+
);
|
|
33876
|
+
case "turnCompleted":
|
|
33877
|
+
return [turnCompletionEntry(notification)];
|
|
33878
|
+
case "error":
|
|
33879
|
+
return [errorEntry(notification)];
|
|
33880
|
+
default:
|
|
33881
|
+
return [];
|
|
33882
|
+
}
|
|
33883
|
+
}
|
|
33884
|
+
// An approval parks the turn on operator input, so the question entry also
|
|
33885
|
+
// marks the delivered turn as waiting for input.
|
|
33886
|
+
projectApproval(request) {
|
|
33887
|
+
return {
|
|
33888
|
+
type: "entry",
|
|
33889
|
+
entry: {
|
|
33890
|
+
...projectCodexApproval(request),
|
|
33891
|
+
turnStatus: "waiting_for_input"
|
|
33892
|
+
}
|
|
33893
|
+
};
|
|
33894
|
+
}
|
|
33895
|
+
// Surfaces a session-level failure (e.g. the app-server process dying) as a
|
|
33896
|
+
// durable failed status entry rather than only a diagnostic log line.
|
|
33897
|
+
projectSessionFailure(message) {
|
|
33898
|
+
return {
|
|
33899
|
+
type: "entry",
|
|
33900
|
+
entry: {
|
|
33901
|
+
role: "system",
|
|
33902
|
+
kind: "status",
|
|
33903
|
+
status: "failed",
|
|
33904
|
+
turnStatus: "failed",
|
|
33905
|
+
content: {
|
|
33906
|
+
parts: [{ type: "text", text: `codex failed: ${message}` }]
|
|
33907
|
+
}
|
|
33908
|
+
}
|
|
33909
|
+
};
|
|
33910
|
+
}
|
|
33911
|
+
};
|
|
33912
|
+
function entryProjections(projections) {
|
|
33913
|
+
return projections.map((projection) => ({
|
|
33914
|
+
type: "entry",
|
|
33915
|
+
entry: projection
|
|
33916
|
+
}));
|
|
33917
|
+
}
|
|
33918
|
+
function turnCompletionEntry(notification) {
|
|
33919
|
+
if (notification.status === "failed") {
|
|
33920
|
+
const detail = notification.errorMessage ?? "unknown error";
|
|
33921
|
+
return statusEntry({
|
|
33922
|
+
text: `codex turn failed: ${detail}`,
|
|
33923
|
+
status: "failed",
|
|
33924
|
+
turnStatus: "failed"
|
|
33925
|
+
});
|
|
33926
|
+
}
|
|
33927
|
+
const text = notification.status === "interrupted" ? "codex turn interrupted" : "codex turn completed";
|
|
33928
|
+
return statusEntry({
|
|
33929
|
+
text,
|
|
33930
|
+
status: "completed",
|
|
33931
|
+
turnStatus: "completed"
|
|
33608
33932
|
});
|
|
33609
33933
|
}
|
|
33610
|
-
function
|
|
33611
|
-
|
|
33612
|
-
|
|
33613
|
-
|
|
33614
|
-
|
|
33615
|
-
|
|
33616
|
-
|
|
33617
|
-
|
|
33934
|
+
function errorEntry(notification) {
|
|
33935
|
+
if (notification.willRetry) {
|
|
33936
|
+
return statusEntry({
|
|
33937
|
+
text: `codex retrying after error: ${notification.message}`,
|
|
33938
|
+
status: "completed"
|
|
33939
|
+
});
|
|
33940
|
+
}
|
|
33941
|
+
return statusEntry({
|
|
33942
|
+
text: `codex error: ${notification.message}`,
|
|
33943
|
+
status: "failed",
|
|
33944
|
+
turnStatus: "failed"
|
|
33945
|
+
});
|
|
33946
|
+
}
|
|
33947
|
+
function statusEntry(input) {
|
|
33948
|
+
return {
|
|
33949
|
+
type: "entry",
|
|
33950
|
+
entry: {
|
|
33951
|
+
role: "system",
|
|
33952
|
+
kind: "status",
|
|
33953
|
+
status: input.status,
|
|
33954
|
+
...input.turnStatus ? { turnStatus: input.turnStatus } : {},
|
|
33955
|
+
content: { parts: [{ type: "text", text: input.text }] }
|
|
33956
|
+
}
|
|
33618
33957
|
};
|
|
33619
|
-
|
|
33620
|
-
|
|
33621
|
-
|
|
33622
|
-
|
|
33623
|
-
|
|
33624
|
-
|
|
33625
|
-
|
|
33626
|
-
|
|
33958
|
+
}
|
|
33959
|
+
|
|
33960
|
+
// src/commands/agent-bridge/harness/codex/resume-store.ts
|
|
33961
|
+
import { existsSync as existsSync2, mkdirSync as mkdirSync3, readFileSync as readFileSync3, writeFileSync as writeFileSync3 } from "fs";
|
|
33962
|
+
import { dirname as dirname4 } from "path";
|
|
33963
|
+
var AGENT_BRIDGE_RUNTIME_DIR2 = "/tmp/auto-bridge-runtime";
|
|
33964
|
+
var CODEX_THREAD_RESUME_PATH = `${AGENT_BRIDGE_RUNTIME_DIR2}/codex-thread-id`;
|
|
33965
|
+
function fileCodexThreadResumeStore(path2 = CODEX_THREAD_RESUME_PATH) {
|
|
33966
|
+
return {
|
|
33967
|
+
read(sessionId) {
|
|
33968
|
+
if (!existsSync2(path2)) {
|
|
33969
|
+
return null;
|
|
33970
|
+
}
|
|
33971
|
+
const record2 = parseResumeRecord2(readFileSync3(path2, "utf8"));
|
|
33972
|
+
if (!record2 || record2.sessionId !== sessionId) {
|
|
33973
|
+
return null;
|
|
33974
|
+
}
|
|
33975
|
+
return record2.threadId;
|
|
33976
|
+
},
|
|
33977
|
+
write(record2) {
|
|
33978
|
+
mkdirSync3(dirname4(path2), { recursive: true });
|
|
33979
|
+
writeFileSync3(path2, `${JSON.stringify(record2)}
|
|
33980
|
+
`, "utf8");
|
|
33627
33981
|
}
|
|
33628
|
-
}
|
|
33982
|
+
};
|
|
33629
33983
|
}
|
|
33630
|
-
function
|
|
33631
|
-
|
|
33984
|
+
function parseResumeRecord2(raw) {
|
|
33985
|
+
try {
|
|
33986
|
+
const value = JSON.parse(raw);
|
|
33987
|
+
if (value !== null && typeof value === "object" && "sessionId" in value && "threadId" in value && typeof value.sessionId === "string" && typeof value.threadId === "string" && value.threadId.length > 0) {
|
|
33988
|
+
return { sessionId: value.sessionId, threadId: value.threadId };
|
|
33989
|
+
}
|
|
33990
|
+
return null;
|
|
33991
|
+
} catch {
|
|
33992
|
+
return null;
|
|
33993
|
+
}
|
|
33632
33994
|
}
|
|
33633
33995
|
|
|
33634
|
-
// src/commands/agent-bridge/
|
|
33996
|
+
// src/commands/agent-bridge/harness/codex/session.ts
|
|
33635
33997
|
init_src();
|
|
33636
|
-
|
|
33637
|
-
|
|
33638
|
-
|
|
33639
|
-
|
|
33640
|
-
|
|
33641
|
-
|
|
33642
|
-
|
|
33643
|
-
|
|
33644
|
-
|
|
33645
|
-
|
|
33998
|
+
import { spawn as spawn2 } from "child_process";
|
|
33999
|
+
import { mkdirSync as mkdirSync4, writeFileSync as writeFileSync4 } from "fs";
|
|
34000
|
+
import { join as join4 } from "path";
|
|
34001
|
+
|
|
34002
|
+
// src/commands/agent-bridge/harness/codex/options.ts
|
|
34003
|
+
import { join as join3 } from "path";
|
|
34004
|
+
var CODEX_EXECUTABLE_PATH = "codex";
|
|
34005
|
+
var CODEX_DEFAULT_MODEL = "gpt-5.3-codex";
|
|
34006
|
+
var CODEX_HTTP_PROVIDER_ID = "openai-responses-http";
|
|
34007
|
+
var CODEX_OPENAI_BASE_URL = "https://api.openai.com/v1";
|
|
34008
|
+
var CODEX_API_KEY_ENV = "OPENAI_API_KEY";
|
|
34009
|
+
var CODEX_RUNTIME_PROCESS_ENV_KEYS = ["PATH", "HOME"];
|
|
34010
|
+
function codexLaunchOptions(config2) {
|
|
34011
|
+
return {
|
|
34012
|
+
command: codexExecutablePath(),
|
|
34013
|
+
// `--listen stdio://` is the default, but pin it so a config/feature change
|
|
34014
|
+
// cannot silently move the transport off the stdin/stdout the client drives.
|
|
34015
|
+
args: ["app-server", "--listen", "stdio://"],
|
|
34016
|
+
env: codexProcessEnv(config2.env),
|
|
34017
|
+
// Codex reads config/auth/rollout state from its standard home; the caller
|
|
34018
|
+
// writes the rendered config.toml there.
|
|
34019
|
+
codexHome: codexHomeDir(),
|
|
34020
|
+
configToml: renderCodexConfigToml(config2)
|
|
33646
34021
|
};
|
|
34022
|
+
}
|
|
34023
|
+
function codexThreadParams(config2) {
|
|
33647
34024
|
return {
|
|
33648
|
-
|
|
33649
|
-
|
|
33650
|
-
info: emit("info"),
|
|
33651
|
-
warn: emit("warn"),
|
|
33652
|
-
error: emit("error")
|
|
34025
|
+
...config2.cwd ? { cwd: config2.cwd } : {},
|
|
34026
|
+
...config2.systemPromptAppend ? { developerInstructions: config2.systemPromptAppend } : {}
|
|
33653
34027
|
};
|
|
33654
34028
|
}
|
|
33655
|
-
function
|
|
33656
|
-
const
|
|
33657
|
-
|
|
33658
|
-
|
|
33659
|
-
|
|
33660
|
-
|
|
33661
|
-
|
|
34029
|
+
function renderCodexConfigToml(config2) {
|
|
34030
|
+
const lines = [];
|
|
34031
|
+
lines.push(`model = ${tomlString(CODEX_DEFAULT_MODEL)}`);
|
|
34032
|
+
lines.push(`model_provider = ${tomlString(CODEX_HTTP_PROVIDER_ID)}`);
|
|
34033
|
+
lines.push("");
|
|
34034
|
+
lines.push(`[model_providers.${CODEX_HTTP_PROVIDER_ID}]`);
|
|
34035
|
+
lines.push('name = "OpenAI"');
|
|
34036
|
+
lines.push(`base_url = ${tomlString(CODEX_OPENAI_BASE_URL)}`);
|
|
34037
|
+
lines.push('wire_api = "responses"');
|
|
34038
|
+
lines.push(`env_key = ${tomlString(CODEX_API_KEY_ENV)}`);
|
|
34039
|
+
lines.push("supports_websockets = false");
|
|
34040
|
+
for (const [name, server] of Object.entries(config2.mcpServers ?? {})) {
|
|
34041
|
+
lines.push("");
|
|
34042
|
+
lines.push(`[mcp_servers.${tomlKey(name)}]`);
|
|
34043
|
+
lines.push(`url = ${tomlString(server.url)}`);
|
|
34044
|
+
if (server.headers && Object.keys(server.headers).length > 0) {
|
|
34045
|
+
lines.push(`http_headers = ${tomlInlineTable(server.headers)}`);
|
|
34046
|
+
}
|
|
34047
|
+
}
|
|
34048
|
+
return `${lines.join("\n")}
|
|
34049
|
+
`;
|
|
34050
|
+
}
|
|
34051
|
+
function codexProcessEnv(env) {
|
|
34052
|
+
const selected = {};
|
|
34053
|
+
for (const key of CODEX_RUNTIME_PROCESS_ENV_KEYS) {
|
|
34054
|
+
const value = process.env[key];
|
|
34055
|
+
if (value !== void 0) {
|
|
34056
|
+
selected[key] = value;
|
|
34057
|
+
}
|
|
34058
|
+
}
|
|
34059
|
+
return {
|
|
34060
|
+
...selected,
|
|
34061
|
+
...env
|
|
33662
34062
|
};
|
|
33663
|
-
process.stderr.write(`${JSON.stringify(payload, replaceErrors)}
|
|
33664
|
-
`);
|
|
33665
34063
|
}
|
|
33666
|
-
function
|
|
33667
|
-
|
|
33668
|
-
|
|
34064
|
+
function codexHomeDir() {
|
|
34065
|
+
const home = process.env.HOME;
|
|
34066
|
+
if (!home) {
|
|
34067
|
+
throw new Error("codex launch requires HOME to locate the ~/.codex home");
|
|
33669
34068
|
}
|
|
33670
|
-
return
|
|
34069
|
+
return join3(home, ".codex");
|
|
33671
34070
|
}
|
|
33672
|
-
|
|
33673
|
-
|
|
33674
|
-
|
|
33675
|
-
const runAgentBridge = input.runAgentBridge ?? runAgentBridgeHarness;
|
|
33676
|
-
const log = createRuntimeLogger(input.env);
|
|
33677
|
-
log.info("agent bridge process starting", {
|
|
33678
|
-
bridge_url_host: bridgeUrlHost(input.env.AUTO_BRIDGE_URL),
|
|
33679
|
-
log_level: log.level
|
|
33680
|
-
});
|
|
33681
|
-
try {
|
|
33682
|
-
await runAgentBridge({
|
|
33683
|
-
...agentBridgeOptionsFromEnv(input),
|
|
33684
|
-
runtimeLogger: log,
|
|
33685
|
-
onBootstrap: createGitCredentialRelayStarter(input.writeOutput, log)
|
|
33686
|
-
});
|
|
33687
|
-
} catch (error51) {
|
|
33688
|
-
log.error("agent bridge process failed", { error: error51 });
|
|
33689
|
-
throw error51;
|
|
34071
|
+
function codexExecutablePath() {
|
|
34072
|
+
if (process.env.AUTO_AGENT_BRIDGE_TEST_CODEX_COMMAND === "1" && process.env.AUTO_CODEX_COMMAND?.trim()) {
|
|
34073
|
+
return process.env.AUTO_CODEX_COMMAND.trim();
|
|
33690
34074
|
}
|
|
34075
|
+
return CODEX_EXECUTABLE_PATH;
|
|
33691
34076
|
}
|
|
33692
|
-
function
|
|
33693
|
-
|
|
33694
|
-
|
|
33695
|
-
|
|
33696
|
-
|
|
33697
|
-
};
|
|
34077
|
+
function tomlInlineTable(values) {
|
|
34078
|
+
const entries = Object.entries(values).map(
|
|
34079
|
+
([key, value]) => `${tomlKey(key)} = ${tomlString(value)}`
|
|
34080
|
+
);
|
|
34081
|
+
return `{ ${entries.join(", ")} }`;
|
|
33698
34082
|
}
|
|
33699
|
-
function
|
|
33700
|
-
|
|
33701
|
-
|
|
33702
|
-
|
|
33703
|
-
|
|
33704
|
-
|
|
33705
|
-
|
|
33706
|
-
|
|
33707
|
-
|
|
33708
|
-
|
|
34083
|
+
function tomlKey(key) {
|
|
34084
|
+
return /^[A-Za-z0-9_-]+$/.test(key) ? key : tomlString(key);
|
|
34085
|
+
}
|
|
34086
|
+
function tomlString(value) {
|
|
34087
|
+
return `"${value.replace(/\\/g, "\\\\").replace(/"/g, '\\"')}"`;
|
|
34088
|
+
}
|
|
34089
|
+
|
|
34090
|
+
// src/commands/agent-bridge/harness/codex/session.ts
|
|
34091
|
+
var CODEX_REQUEST_TIMEOUT_MS = 3e4;
|
|
34092
|
+
var CODEX_ITEM_SETTLE_TIMEOUT_MS = 1e4;
|
|
34093
|
+
var CODEX_TOOL_ITEM_TYPES = /* @__PURE__ */ new Set([
|
|
34094
|
+
"commandExecution",
|
|
34095
|
+
"fileChange",
|
|
34096
|
+
"mcpToolCall"
|
|
34097
|
+
]);
|
|
34098
|
+
function startCodexAgentBridgeSession(input) {
|
|
34099
|
+
return new CodexAgentBridgeSessionImpl(input);
|
|
34100
|
+
}
|
|
34101
|
+
var codexAgentBridgeRuntime = {
|
|
34102
|
+
start: startCodexAgentBridgeSession
|
|
34103
|
+
};
|
|
34104
|
+
var CodexAgentBridgeSessionImpl = class {
|
|
34105
|
+
input;
|
|
34106
|
+
proc = null;
|
|
34107
|
+
startup = null;
|
|
34108
|
+
closed = false;
|
|
34109
|
+
nextRequestId = 1;
|
|
34110
|
+
pending = /* @__PURE__ */ new Map();
|
|
34111
|
+
stdoutBuffer = "";
|
|
34112
|
+
threadId = null;
|
|
34113
|
+
activeTurnId = null;
|
|
34114
|
+
// Tool-like items started but not yet completed in the active turn. A non-empty
|
|
34115
|
+
// set means an interrupt/steer would race an unsettled item (FRA-3049 analog).
|
|
34116
|
+
pendingToolItemIds = /* @__PURE__ */ new Set();
|
|
34117
|
+
settlementWaiters = /* @__PURE__ */ new Set();
|
|
34118
|
+
// Messages held in "deferred" mode while a turn is in flight; flushed as a
|
|
34119
|
+
// fresh turn once the active turn completes.
|
|
34120
|
+
deferredMessages = [];
|
|
34121
|
+
constructor(input) {
|
|
34122
|
+
this.input = input;
|
|
34123
|
+
}
|
|
34124
|
+
async prepare() {
|
|
34125
|
+
await this.ensureStarted();
|
|
34126
|
+
}
|
|
34127
|
+
async sendMessage(message, options) {
|
|
34128
|
+
await this.ensureStarted();
|
|
34129
|
+
const threadId = this.requireThreadId();
|
|
34130
|
+
const mode = options?.mode ?? "interrupt";
|
|
34131
|
+
if (this.activeTurnId === null) {
|
|
34132
|
+
await this.startTurn(threadId, message);
|
|
34133
|
+
return;
|
|
34134
|
+
}
|
|
34135
|
+
if (mode === "deferred") {
|
|
34136
|
+
this.deferredMessages.push(message);
|
|
34137
|
+
this.input.writeOutput?.("agent_bridge_codex_message_deferred");
|
|
34138
|
+
return;
|
|
34139
|
+
}
|
|
34140
|
+
await this.injectIntoActiveTurn(threadId, message);
|
|
34141
|
+
}
|
|
34142
|
+
resolveApproval(resolution) {
|
|
34143
|
+
this.writeFrame({
|
|
34144
|
+
jsonrpc: "2.0",
|
|
34145
|
+
id: resolution.requestId,
|
|
34146
|
+
result: { decision: resolution.decision }
|
|
34147
|
+
});
|
|
34148
|
+
this.input.writeOutput?.(
|
|
34149
|
+
`agent_bridge_codex_approval_resolved decision=${resolution.decision}`
|
|
34150
|
+
);
|
|
34151
|
+
}
|
|
34152
|
+
close() {
|
|
34153
|
+
if (this.closed) {
|
|
34154
|
+
return;
|
|
34155
|
+
}
|
|
34156
|
+
this.closed = true;
|
|
34157
|
+
if (this.threadId && this.activeTurnId) {
|
|
34158
|
+
this.writeFrame({
|
|
34159
|
+
jsonrpc: "2.0",
|
|
34160
|
+
id: this.allocRequestId(),
|
|
34161
|
+
method: "turn/interrupt",
|
|
34162
|
+
params: { threadId: this.threadId, turnId: this.activeTurnId }
|
|
34163
|
+
});
|
|
34164
|
+
}
|
|
34165
|
+
this.activeTurnId = null;
|
|
34166
|
+
this.pendingToolItemIds.clear();
|
|
34167
|
+
this.resolveSettlement();
|
|
34168
|
+
this.rejectAllPending(new Error("Codex session is closed"));
|
|
34169
|
+
if (this.deferredMessages.length > 0) {
|
|
34170
|
+
this.input.writeOutput?.(
|
|
34171
|
+
`agent_bridge_codex_deferred_dropped count=${this.deferredMessages.length} reason=session_closed`
|
|
34172
|
+
);
|
|
34173
|
+
this.deferredMessages.length = 0;
|
|
34174
|
+
}
|
|
34175
|
+
this.proc?.kill("SIGTERM");
|
|
34176
|
+
this.proc = null;
|
|
34177
|
+
}
|
|
34178
|
+
// ---------------------------------------------------------------------------
|
|
34179
|
+
// Startup
|
|
34180
|
+
// ---------------------------------------------------------------------------
|
|
34181
|
+
ensureStarted() {
|
|
34182
|
+
if (this.startup) {
|
|
34183
|
+
return this.startup;
|
|
34184
|
+
}
|
|
34185
|
+
this.startup = this.start().catch((error51) => {
|
|
34186
|
+
this.startup = null;
|
|
34187
|
+
this.close();
|
|
34188
|
+
throw error51;
|
|
34189
|
+
});
|
|
34190
|
+
return this.startup;
|
|
34191
|
+
}
|
|
34192
|
+
async start() {
|
|
34193
|
+
const options = codexLaunchOptions(this.input.codex);
|
|
34194
|
+
mkdirSync4(options.codexHome, { recursive: true });
|
|
34195
|
+
writeFileSync4(join4(options.codexHome, "config.toml"), options.configToml);
|
|
34196
|
+
const startedAt = Date.now();
|
|
34197
|
+
this.input.writeOutput?.(
|
|
34198
|
+
`agent_bridge_codex_startup_started codex_home=${options.codexHome}`
|
|
34199
|
+
);
|
|
34200
|
+
const proc = spawn2(options.command, options.args, {
|
|
34201
|
+
env: options.env,
|
|
34202
|
+
stdio: ["pipe", "pipe", "pipe"]
|
|
34203
|
+
});
|
|
34204
|
+
this.proc = proc;
|
|
34205
|
+
proc.stdout.setEncoding("utf8");
|
|
34206
|
+
proc.stdout.on("data", (chunk) => this.onStdout(chunk));
|
|
34207
|
+
proc.stderr.setEncoding("utf8");
|
|
34208
|
+
proc.stderr.on(
|
|
34209
|
+
"data",
|
|
34210
|
+
(chunk) => this.input.writeOutput?.(`agent_bridge_codex_stderr ${chunk.trimEnd()}`)
|
|
34211
|
+
);
|
|
34212
|
+
proc.on("exit", (code) => this.onProcessExit(code));
|
|
34213
|
+
proc.on("error", (error51) => void this.input.onError(error51));
|
|
34214
|
+
await this.request("initialize", {
|
|
34215
|
+
clientInfo: {
|
|
34216
|
+
name: "auto-agent-bridge",
|
|
34217
|
+
title: "Auto",
|
|
34218
|
+
version: "1"
|
|
34219
|
+
},
|
|
34220
|
+
capabilities: null
|
|
34221
|
+
});
|
|
34222
|
+
this.notify("initialized");
|
|
34223
|
+
await this.openThread();
|
|
34224
|
+
this.input.writeOutput?.(
|
|
34225
|
+
`agent_bridge_codex_startup_ready duration_ms=${Date.now() - startedAt} thread_id=${this.threadId ?? ""}`
|
|
34226
|
+
);
|
|
34227
|
+
}
|
|
34228
|
+
// Resume the stored thread when present, falling back to a fresh thread if the
|
|
34229
|
+
// resume is rejected (e.g. the rollout was pruned). A fresh thread carries the
|
|
34230
|
+
// neutral thread params (cwd + the agent identity as developerInstructions).
|
|
34231
|
+
async openThread() {
|
|
34232
|
+
if (this.input.resumeThreadId) {
|
|
34233
|
+
try {
|
|
34234
|
+
const resumed = await this.request("thread/resume", {
|
|
34235
|
+
threadId: this.input.resumeThreadId
|
|
34236
|
+
});
|
|
34237
|
+
this.adoptThreadId(resumed);
|
|
34238
|
+
return;
|
|
34239
|
+
} catch (error51) {
|
|
34240
|
+
this.input.writeOutput?.(
|
|
34241
|
+
`agent_bridge_codex_resume_fallback thread_id=${this.input.resumeThreadId} error=${errorMessage2(error51)}`
|
|
34242
|
+
);
|
|
34243
|
+
}
|
|
34244
|
+
}
|
|
34245
|
+
const started = await this.request(
|
|
34246
|
+
"thread/start",
|
|
34247
|
+
codexThreadParams(this.input.codex)
|
|
34248
|
+
);
|
|
34249
|
+
this.adoptThreadId(started);
|
|
34250
|
+
}
|
|
34251
|
+
adoptThreadId(result) {
|
|
34252
|
+
const threadId = threadIdFromResult(result);
|
|
34253
|
+
if (!threadId) {
|
|
34254
|
+
throw new Error("Codex thread response did not include a thread id");
|
|
34255
|
+
}
|
|
34256
|
+
this.threadId = threadId;
|
|
34257
|
+
this.input.onThreadId(threadId);
|
|
34258
|
+
}
|
|
34259
|
+
// ---------------------------------------------------------------------------
|
|
34260
|
+
// Turn delivery
|
|
34261
|
+
// ---------------------------------------------------------------------------
|
|
34262
|
+
async startTurn(threadId, message) {
|
|
34263
|
+
await this.request("turn/start", {
|
|
34264
|
+
threadId,
|
|
34265
|
+
input: [userTextInput(message)]
|
|
34266
|
+
});
|
|
34267
|
+
}
|
|
34268
|
+
// Inject a message into the active turn. Prefers `turn/steer` (codex folds the
|
|
34269
|
+
// input into the running turn and owns transcript consistency); falls back to a
|
|
34270
|
+
// hard `turn/interrupt` + fresh `turn/start` when the turn cannot be steered.
|
|
34271
|
+
async injectIntoActiveTurn(threadId, message) {
|
|
34272
|
+
await this.awaitItemSettlement();
|
|
34273
|
+
const expectedTurnId = this.activeTurnId;
|
|
34274
|
+
if (expectedTurnId === null) {
|
|
34275
|
+
await this.startTurn(threadId, message);
|
|
34276
|
+
return;
|
|
34277
|
+
}
|
|
34278
|
+
try {
|
|
34279
|
+
await this.request("turn/steer", {
|
|
34280
|
+
threadId,
|
|
34281
|
+
input: [userTextInput(message)],
|
|
34282
|
+
expectedTurnId
|
|
34283
|
+
});
|
|
34284
|
+
this.input.writeOutput?.("agent_bridge_codex_steered");
|
|
34285
|
+
return;
|
|
34286
|
+
} catch (error51) {
|
|
34287
|
+
this.input.writeOutput?.(
|
|
34288
|
+
`agent_bridge_codex_steer_failed error=${errorMessage2(error51)}`
|
|
34289
|
+
);
|
|
34290
|
+
}
|
|
34291
|
+
if (this.activeTurnId) {
|
|
34292
|
+
await this.interruptActiveTurn(threadId, this.activeTurnId);
|
|
34293
|
+
}
|
|
34294
|
+
await this.startTurn(threadId, message);
|
|
34295
|
+
}
|
|
34296
|
+
async interruptActiveTurn(threadId, turnId) {
|
|
34297
|
+
try {
|
|
34298
|
+
await this.request("turn/interrupt", { threadId, turnId });
|
|
34299
|
+
this.input.writeOutput?.("agent_bridge_codex_interrupted");
|
|
34300
|
+
} catch (error51) {
|
|
34301
|
+
this.input.writeOutput?.(
|
|
34302
|
+
`agent_bridge_codex_interrupt_failed error=${errorMessage2(error51)}`
|
|
34303
|
+
);
|
|
34304
|
+
}
|
|
34305
|
+
}
|
|
34306
|
+
flushDeferredMessages() {
|
|
34307
|
+
if (this.deferredMessages.length === 0 || this.threadId === null) {
|
|
34308
|
+
return;
|
|
34309
|
+
}
|
|
34310
|
+
const pending = this.deferredMessages.splice(0);
|
|
34311
|
+
this.input.writeOutput?.(
|
|
34312
|
+
`agent_bridge_codex_deferred_flush count=${pending.length}`
|
|
34313
|
+
);
|
|
34314
|
+
void (async () => {
|
|
34315
|
+
for (const message of pending) {
|
|
34316
|
+
try {
|
|
34317
|
+
await this.sendMessage(message, { mode: "interrupt" });
|
|
34318
|
+
} catch (error51) {
|
|
34319
|
+
void this.input.onError(error51);
|
|
34320
|
+
}
|
|
34321
|
+
}
|
|
34322
|
+
})();
|
|
34323
|
+
}
|
|
34324
|
+
// ---------------------------------------------------------------------------
|
|
34325
|
+
// Item settlement
|
|
34326
|
+
// ---------------------------------------------------------------------------
|
|
34327
|
+
awaitItemSettlement() {
|
|
34328
|
+
if (this.pendingToolItemIds.size === 0) {
|
|
34329
|
+
return Promise.resolve();
|
|
34330
|
+
}
|
|
34331
|
+
return new Promise((resolve4) => {
|
|
34332
|
+
let done = false;
|
|
34333
|
+
const finish = () => {
|
|
34334
|
+
if (done) {
|
|
34335
|
+
return;
|
|
34336
|
+
}
|
|
34337
|
+
done = true;
|
|
34338
|
+
clearTimeout(timer);
|
|
34339
|
+
this.settlementWaiters.delete(waiter);
|
|
34340
|
+
resolve4();
|
|
34341
|
+
};
|
|
34342
|
+
const waiter = () => finish();
|
|
34343
|
+
const timer = setTimeout(finish, CODEX_ITEM_SETTLE_TIMEOUT_MS);
|
|
34344
|
+
timer.unref?.();
|
|
34345
|
+
this.settlementWaiters.add(waiter);
|
|
34346
|
+
});
|
|
34347
|
+
}
|
|
34348
|
+
resolveSettlement() {
|
|
34349
|
+
if (this.settlementWaiters.size === 0) {
|
|
34350
|
+
return;
|
|
34351
|
+
}
|
|
34352
|
+
const waiters = [...this.settlementWaiters];
|
|
34353
|
+
this.settlementWaiters.clear();
|
|
34354
|
+
for (const waiter of waiters) {
|
|
34355
|
+
waiter();
|
|
34356
|
+
}
|
|
34357
|
+
}
|
|
34358
|
+
// ---------------------------------------------------------------------------
|
|
34359
|
+
// Incoming frame handling
|
|
34360
|
+
// ---------------------------------------------------------------------------
|
|
34361
|
+
onStdout(chunk) {
|
|
34362
|
+
this.stdoutBuffer += chunk;
|
|
34363
|
+
let newline = this.stdoutBuffer.indexOf("\n");
|
|
34364
|
+
while (newline >= 0) {
|
|
34365
|
+
const line = this.stdoutBuffer.slice(0, newline).trim();
|
|
34366
|
+
this.stdoutBuffer = this.stdoutBuffer.slice(newline + 1);
|
|
34367
|
+
if (line) {
|
|
34368
|
+
this.handleFrame(line);
|
|
34369
|
+
}
|
|
34370
|
+
newline = this.stdoutBuffer.indexOf("\n");
|
|
34371
|
+
}
|
|
34372
|
+
}
|
|
34373
|
+
handleFrame(line) {
|
|
34374
|
+
let message;
|
|
34375
|
+
try {
|
|
34376
|
+
message = parseCodexServerFrame(JSON.parse(line));
|
|
34377
|
+
} catch (error51) {
|
|
34378
|
+
this.input.writeOutput?.(
|
|
34379
|
+
`agent_bridge_codex_parse_failed error=${errorMessage2(error51)}`
|
|
34380
|
+
);
|
|
34381
|
+
return;
|
|
34382
|
+
}
|
|
34383
|
+
switch (message.kind) {
|
|
34384
|
+
case "response":
|
|
34385
|
+
this.settleResponse(message.id, message.result, message.error);
|
|
34386
|
+
return;
|
|
34387
|
+
case "notification":
|
|
34388
|
+
this.trackNotification(message.notification);
|
|
34389
|
+
void this.input.onNotification(message.notification);
|
|
34390
|
+
return;
|
|
34391
|
+
case "serverRequest":
|
|
34392
|
+
void this.input.onServerRequest(message.request);
|
|
34393
|
+
return;
|
|
34394
|
+
case "elicitation":
|
|
34395
|
+
this.writeFrame({
|
|
34396
|
+
jsonrpc: "2.0",
|
|
34397
|
+
id: message.requestId,
|
|
34398
|
+
result: { action: "accept", content: {}, _meta: null }
|
|
34399
|
+
});
|
|
34400
|
+
this.input.writeOutput?.(
|
|
34401
|
+
`agent_bridge_codex_elicitation_accepted server=${message.serverName}`
|
|
34402
|
+
);
|
|
34403
|
+
return;
|
|
34404
|
+
case "unsupportedRequest":
|
|
34405
|
+
this.writeFrame({
|
|
34406
|
+
jsonrpc: "2.0",
|
|
34407
|
+
id: message.requestId,
|
|
34408
|
+
error: { code: -32601, message: "Unsupported by Auto bridge" }
|
|
34409
|
+
});
|
|
34410
|
+
this.input.writeOutput?.(
|
|
34411
|
+
`agent_bridge_codex_unsupported_request method=${message.method}`
|
|
34412
|
+
);
|
|
34413
|
+
return;
|
|
34414
|
+
case "ignored":
|
|
34415
|
+
return;
|
|
34416
|
+
}
|
|
34417
|
+
}
|
|
34418
|
+
// Track turn/item lifecycle so steer/interrupt target the live turn and gate on
|
|
34419
|
+
// tool-item settlement.
|
|
34420
|
+
trackNotification(notification) {
|
|
34421
|
+
switch (notification.type) {
|
|
34422
|
+
case "turnStarted":
|
|
34423
|
+
this.activeTurnId = notification.turnId;
|
|
34424
|
+
return;
|
|
34425
|
+
case "turnCompleted":
|
|
34426
|
+
if (notification.turnId === this.activeTurnId) {
|
|
34427
|
+
this.activeTurnId = null;
|
|
34428
|
+
}
|
|
34429
|
+
this.pendingToolItemIds.clear();
|
|
34430
|
+
this.resolveSettlement();
|
|
34431
|
+
this.flushDeferredMessages();
|
|
34432
|
+
return;
|
|
34433
|
+
case "itemStarted":
|
|
34434
|
+
if (CODEX_TOOL_ITEM_TYPES.has(notification.item.type)) {
|
|
34435
|
+
this.pendingToolItemIds.add(notification.item.id);
|
|
34436
|
+
}
|
|
34437
|
+
return;
|
|
34438
|
+
case "itemCompleted":
|
|
34439
|
+
this.pendingToolItemIds.delete(notification.item.id);
|
|
34440
|
+
if (this.pendingToolItemIds.size === 0) {
|
|
34441
|
+
this.resolveSettlement();
|
|
34442
|
+
}
|
|
34443
|
+
return;
|
|
34444
|
+
default:
|
|
34445
|
+
return;
|
|
34446
|
+
}
|
|
34447
|
+
}
|
|
34448
|
+
onProcessExit(code) {
|
|
34449
|
+
this.rejectAllPending(
|
|
34450
|
+
new Error(`Codex app-server exited (code ${code ?? "unknown"})`)
|
|
34451
|
+
);
|
|
34452
|
+
this.activeTurnId = null;
|
|
34453
|
+
this.pendingToolItemIds.clear();
|
|
34454
|
+
this.resolveSettlement();
|
|
34455
|
+
this.input.writeOutput?.(`agent_bridge_codex_exited code=${code ?? ""}`);
|
|
34456
|
+
if (!this.closed) {
|
|
34457
|
+
this.closed = true;
|
|
34458
|
+
this.input.onExit();
|
|
34459
|
+
}
|
|
34460
|
+
}
|
|
34461
|
+
// ---------------------------------------------------------------------------
|
|
34462
|
+
// JSON-RPC transport
|
|
34463
|
+
// ---------------------------------------------------------------------------
|
|
34464
|
+
request(method, params) {
|
|
34465
|
+
const id = this.allocRequestId();
|
|
34466
|
+
const frame = { jsonrpc: "2.0", id, method, params };
|
|
34467
|
+
return new Promise((resolve4, reject) => {
|
|
34468
|
+
this.pending.set(id, { resolve: resolve4, reject });
|
|
34469
|
+
const timer = setTimeout(() => {
|
|
34470
|
+
if (this.pending.delete(id)) {
|
|
34471
|
+
reject(new Error(`Codex request timed out: ${method}`));
|
|
34472
|
+
}
|
|
34473
|
+
}, CODEX_REQUEST_TIMEOUT_MS);
|
|
34474
|
+
timer.unref?.();
|
|
34475
|
+
this.writeFrame(frame);
|
|
34476
|
+
});
|
|
34477
|
+
}
|
|
34478
|
+
settleResponse(id, result, error51) {
|
|
34479
|
+
if (typeof id !== "number") {
|
|
34480
|
+
return;
|
|
34481
|
+
}
|
|
34482
|
+
const pending = this.pending.get(id);
|
|
34483
|
+
if (!pending) {
|
|
34484
|
+
return;
|
|
34485
|
+
}
|
|
34486
|
+
this.pending.delete(id);
|
|
34487
|
+
if (error51 !== void 0) {
|
|
34488
|
+
pending.reject(new Error(error51));
|
|
34489
|
+
return;
|
|
34490
|
+
}
|
|
34491
|
+
pending.resolve(result);
|
|
34492
|
+
}
|
|
34493
|
+
rejectAllPending(error51) {
|
|
34494
|
+
const pending = [...this.pending.values()];
|
|
34495
|
+
this.pending.clear();
|
|
34496
|
+
for (const request of pending) {
|
|
34497
|
+
request.reject(error51);
|
|
34498
|
+
}
|
|
34499
|
+
}
|
|
34500
|
+
notify(method, params) {
|
|
34501
|
+
this.writeFrame({
|
|
34502
|
+
jsonrpc: "2.0",
|
|
34503
|
+
method,
|
|
34504
|
+
...params !== void 0 ? { params } : {}
|
|
34505
|
+
});
|
|
34506
|
+
}
|
|
34507
|
+
writeFrame(frame) {
|
|
34508
|
+
const proc = this.proc;
|
|
34509
|
+
if (!proc || proc.stdin.destroyed) {
|
|
34510
|
+
return;
|
|
34511
|
+
}
|
|
34512
|
+
proc.stdin.write(`${JSON.stringify(frame)}
|
|
34513
|
+
`);
|
|
34514
|
+
}
|
|
34515
|
+
allocRequestId() {
|
|
34516
|
+
const id = this.nextRequestId;
|
|
34517
|
+
this.nextRequestId += 1;
|
|
34518
|
+
return id;
|
|
34519
|
+
}
|
|
34520
|
+
requireThreadId() {
|
|
34521
|
+
if (this.threadId === null) {
|
|
34522
|
+
throw new Error("Codex session has no active thread");
|
|
34523
|
+
}
|
|
34524
|
+
return this.threadId;
|
|
34525
|
+
}
|
|
34526
|
+
};
|
|
34527
|
+
function userTextInput(text) {
|
|
34528
|
+
return { type: "text", text, text_elements: [] };
|
|
34529
|
+
}
|
|
34530
|
+
function threadIdFromResult(result) {
|
|
34531
|
+
if (result === null || typeof result !== "object") {
|
|
34532
|
+
return null;
|
|
34533
|
+
}
|
|
34534
|
+
const thread = result.thread;
|
|
34535
|
+
if (thread === null || typeof thread !== "object") {
|
|
34536
|
+
return null;
|
|
34537
|
+
}
|
|
34538
|
+
const id = thread.id;
|
|
34539
|
+
return typeof id === "string" && id.length > 0 ? id : null;
|
|
34540
|
+
}
|
|
34541
|
+
function errorMessage2(error51) {
|
|
34542
|
+
return error51 instanceof Error ? error51.message : String(error51);
|
|
34543
|
+
}
|
|
34544
|
+
|
|
34545
|
+
// src/commands/agent-bridge/harness/codex/index.ts
|
|
34546
|
+
function createCodexCommandHandler(input) {
|
|
34547
|
+
return new CodexCommandHandler({
|
|
34548
|
+
...input,
|
|
34549
|
+
sessionResume: input.sessionResume ?? fileCodexThreadResumeStore()
|
|
34550
|
+
});
|
|
34551
|
+
}
|
|
34552
|
+
var CodexCommandHandler = class {
|
|
34553
|
+
constructor(input) {
|
|
34554
|
+
this.input = input;
|
|
34555
|
+
this.outputBuffer = new AgentBridgeOutputBuffer(input);
|
|
34556
|
+
}
|
|
34557
|
+
input;
|
|
34558
|
+
context = null;
|
|
34559
|
+
session = null;
|
|
34560
|
+
injectedCommands = /* @__PURE__ */ new Set();
|
|
34561
|
+
// itemId -> JSON-RPC request id of the parked approval request, so an `answer`
|
|
34562
|
+
// command keyed by toolCallId (= itemId) can resolve the right server request.
|
|
34563
|
+
pendingApprovals = /* @__PURE__ */ new Map();
|
|
34564
|
+
outputBuffer;
|
|
34565
|
+
projector = new CodexProjector();
|
|
34566
|
+
// ---------------------------------------------------------------------------
|
|
34567
|
+
// Lifecycle (public API)
|
|
34568
|
+
// ---------------------------------------------------------------------------
|
|
34569
|
+
setContext(nextContext) {
|
|
34570
|
+
this.context = RuntimeBridgeConnectedPayloadSchema.parse(nextContext);
|
|
34571
|
+
}
|
|
34572
|
+
async replayPendingOutputs() {
|
|
34573
|
+
await this.outputBuffer.replayPendingOutputs();
|
|
34574
|
+
}
|
|
34575
|
+
async prepare() {
|
|
34576
|
+
await this.ensureSession().prepare();
|
|
34577
|
+
}
|
|
34578
|
+
shutdown() {
|
|
34579
|
+
this.session?.close();
|
|
34580
|
+
this.session = null;
|
|
34581
|
+
this.pendingApprovals.clear();
|
|
34582
|
+
}
|
|
34583
|
+
async handleCommand(rawDelivery) {
|
|
34584
|
+
const delivery = RuntimeBridgeCommandDeliverySchema.parse(rawDelivery);
|
|
34585
|
+
const socketId = this.input.socketId?.();
|
|
34586
|
+
const activeContext = this.context;
|
|
34587
|
+
if (!activeContext || delivery.sessionId !== activeContext.sessionId || delivery.runtimeId !== activeContext.runtimeId || delivery.bridgeLeaseId !== activeContext.bridgeLeaseId) {
|
|
34588
|
+
return commandAck({ delivery, socketId, status: "stale_lease" });
|
|
34589
|
+
}
|
|
34590
|
+
if (this.injectedCommands.has(delivery.commandId)) {
|
|
34591
|
+
return commandAck({ delivery, socketId, status: "duplicate" });
|
|
34592
|
+
}
|
|
34593
|
+
if (delivery.kind === "answer") {
|
|
34594
|
+
return this.handleAnswerCommand(delivery, activeContext, socketId);
|
|
34595
|
+
}
|
|
34596
|
+
if (delivery.kind === "stop") {
|
|
34597
|
+
this.injectedCommands.add(delivery.commandId);
|
|
34598
|
+
this.shutdown();
|
|
34599
|
+
return commandAck({ delivery, socketId, status: "injected" });
|
|
34600
|
+
}
|
|
34601
|
+
if (delivery.kind !== "message") {
|
|
34602
|
+
return commandAck({
|
|
34603
|
+
delivery,
|
|
34604
|
+
socketId,
|
|
34605
|
+
status: "failed",
|
|
34606
|
+
error: `Unsupported command kind: ${delivery.kind}`
|
|
34607
|
+
});
|
|
34608
|
+
}
|
|
34609
|
+
const message = deliveryMessage2(delivery);
|
|
34610
|
+
if (message === null) {
|
|
34611
|
+
return commandAck({
|
|
34612
|
+
delivery,
|
|
34613
|
+
socketId,
|
|
34614
|
+
status: "failed",
|
|
34615
|
+
error: "Message command payload must include a string message"
|
|
34616
|
+
});
|
|
34617
|
+
}
|
|
34618
|
+
this.injectedCommands.add(delivery.commandId);
|
|
34619
|
+
try {
|
|
34620
|
+
await this.emitUserMessageEntry(
|
|
34621
|
+
activeContext,
|
|
34622
|
+
delivery.commandId,
|
|
34623
|
+
message
|
|
34624
|
+
);
|
|
34625
|
+
await this.ensureSession().sendMessage(message, {
|
|
34626
|
+
mode: deliveryMode2(delivery)
|
|
34627
|
+
});
|
|
34628
|
+
} catch (error51) {
|
|
34629
|
+
this.injectedCommands.delete(delivery.commandId);
|
|
34630
|
+
return commandAck({
|
|
34631
|
+
delivery,
|
|
34632
|
+
socketId,
|
|
34633
|
+
status: "failed",
|
|
34634
|
+
error: errorMessage3(error51)
|
|
34635
|
+
});
|
|
34636
|
+
}
|
|
34637
|
+
return commandAck({ delivery, socketId, status: "injected" });
|
|
34638
|
+
}
|
|
34639
|
+
// ---------------------------------------------------------------------------
|
|
34640
|
+
// Answering parked approvals
|
|
34641
|
+
// ---------------------------------------------------------------------------
|
|
34642
|
+
async handleAnswerCommand(delivery, activeContext, socketId) {
|
|
34643
|
+
const payload = RuntimeBridgeAnswerCommandPayloadSchema.safeParse(
|
|
34644
|
+
delivery.payload
|
|
34645
|
+
);
|
|
34646
|
+
if (!payload.success) {
|
|
34647
|
+
return commandAck({
|
|
34648
|
+
delivery,
|
|
34649
|
+
socketId,
|
|
34650
|
+
status: "failed",
|
|
34651
|
+
error: "Answer command payload must include toolCallId and answers"
|
|
34652
|
+
});
|
|
34653
|
+
}
|
|
34654
|
+
this.injectedCommands.add(delivery.commandId);
|
|
34655
|
+
const requestId = this.pendingApprovals.get(payload.data.toolCallId);
|
|
34656
|
+
try {
|
|
34657
|
+
if (requestId !== void 0) {
|
|
34658
|
+
this.pendingApprovals.delete(payload.data.toolCallId);
|
|
34659
|
+
const decision = codexApprovalDecision({
|
|
34660
|
+
answers: payload.data.answers,
|
|
34661
|
+
...payload.data.response ? { response: payload.data.response } : {}
|
|
34662
|
+
});
|
|
34663
|
+
this.ensureSession().resolveApproval({ requestId, decision });
|
|
34664
|
+
this.input.writeOutput?.(
|
|
34665
|
+
`agent_bridge_codex_question_answered tool_use_id=${payload.data.toolCallId} decision=${decision}`
|
|
34666
|
+
);
|
|
34667
|
+
} else {
|
|
34668
|
+
const message = answerFallbackMessage2(payload.data);
|
|
34669
|
+
await this.emitUserMessageEntry(
|
|
34670
|
+
activeContext,
|
|
34671
|
+
delivery.commandId,
|
|
34672
|
+
message
|
|
34673
|
+
);
|
|
34674
|
+
await this.ensureSession().sendMessage(message);
|
|
34675
|
+
}
|
|
34676
|
+
} catch (error51) {
|
|
34677
|
+
this.injectedCommands.delete(delivery.commandId);
|
|
34678
|
+
return commandAck({
|
|
34679
|
+
delivery,
|
|
34680
|
+
socketId,
|
|
34681
|
+
status: "failed",
|
|
34682
|
+
error: errorMessage3(error51)
|
|
34683
|
+
});
|
|
34684
|
+
}
|
|
34685
|
+
return commandAck({ delivery, socketId, status: "injected" });
|
|
34686
|
+
}
|
|
34687
|
+
// ---------------------------------------------------------------------------
|
|
34688
|
+
// Session callbacks
|
|
34689
|
+
// ---------------------------------------------------------------------------
|
|
34690
|
+
async emitUserMessageEntry(activeContext, commandId, message) {
|
|
34691
|
+
await this.emit(activeContext, {
|
|
34692
|
+
type: "entry",
|
|
34693
|
+
entry: {
|
|
34694
|
+
messageId: commandId,
|
|
34695
|
+
role: "user",
|
|
34696
|
+
kind: "message",
|
|
34697
|
+
status: "completed",
|
|
34698
|
+
content: { parts: [{ type: "text", text: message }] }
|
|
34699
|
+
}
|
|
34700
|
+
});
|
|
34701
|
+
}
|
|
34702
|
+
async handleNotification(notification) {
|
|
34703
|
+
const activeContext = this.context;
|
|
34704
|
+
if (!activeContext) {
|
|
34705
|
+
return;
|
|
34706
|
+
}
|
|
34707
|
+
for (const projection of this.projector.project(notification)) {
|
|
34708
|
+
await this.emit(activeContext, projection);
|
|
34709
|
+
}
|
|
34710
|
+
}
|
|
34711
|
+
async handleServerRequest(request) {
|
|
34712
|
+
const activeContext = this.context;
|
|
34713
|
+
if (!activeContext) {
|
|
34714
|
+
return;
|
|
34715
|
+
}
|
|
34716
|
+
this.pendingApprovals.set(request.itemId, request.requestId);
|
|
34717
|
+
this.input.writeOutput?.(
|
|
34718
|
+
`agent_bridge_codex_question_pending tool_use_id=${request.itemId}`
|
|
34719
|
+
);
|
|
34720
|
+
await this.emit(activeContext, this.projector.projectApproval(request));
|
|
34721
|
+
}
|
|
34722
|
+
async handleSessionError(error51) {
|
|
34723
|
+
this.input.writeOutput?.(
|
|
34724
|
+
`agent_bridge_codex_session_failed error=${errorMessage3(error51)}`
|
|
34725
|
+
);
|
|
34726
|
+
const activeContext = this.context;
|
|
34727
|
+
if (!activeContext) {
|
|
34728
|
+
return;
|
|
34729
|
+
}
|
|
34730
|
+
await this.emit(
|
|
34731
|
+
activeContext,
|
|
34732
|
+
this.projector.projectSessionFailure(errorMessage3(error51))
|
|
34733
|
+
);
|
|
34734
|
+
}
|
|
34735
|
+
async emit(activeContext, projection) {
|
|
34736
|
+
try {
|
|
34737
|
+
await this.outputBuffer.emitProjection(activeContext, projection);
|
|
34738
|
+
} catch (error51) {
|
|
34739
|
+
this.input.writeOutput?.(
|
|
34740
|
+
`agent_bridge_output_emit_failed error=${errorMessage3(error51)}`
|
|
34741
|
+
);
|
|
34742
|
+
}
|
|
34743
|
+
}
|
|
34744
|
+
ensureSession() {
|
|
34745
|
+
if (this.session) {
|
|
34746
|
+
return this.session;
|
|
34747
|
+
}
|
|
34748
|
+
const resumeThreadId = this.storedResumeThreadId();
|
|
34749
|
+
const session = codexAgentBridgeRuntime.start({
|
|
34750
|
+
codex: this.input.codex,
|
|
34751
|
+
...resumeThreadId ? { resumeThreadId } : {},
|
|
34752
|
+
onNotification: (notification) => this.handleNotification(notification),
|
|
34753
|
+
onServerRequest: (request) => this.handleServerRequest(request),
|
|
34754
|
+
onThreadId: (threadId) => this.persistThreadId(threadId),
|
|
34755
|
+
onError: (error51) => this.handleSessionError(error51),
|
|
34756
|
+
onExit: () => {
|
|
34757
|
+
if (this.session === session) {
|
|
34758
|
+
this.session = null;
|
|
34759
|
+
}
|
|
34760
|
+
this.input.writeOutput?.("agent_bridge_codex_session_exited");
|
|
34761
|
+
},
|
|
34762
|
+
...this.input.writeOutput ? { writeOutput: this.input.writeOutput } : {}
|
|
34763
|
+
});
|
|
34764
|
+
this.session = session;
|
|
34765
|
+
return session;
|
|
34766
|
+
}
|
|
34767
|
+
storedResumeThreadId() {
|
|
34768
|
+
const store = this.input.sessionResume;
|
|
34769
|
+
const activeContext = this.context;
|
|
34770
|
+
if (!store || !activeContext) {
|
|
34771
|
+
return void 0;
|
|
34772
|
+
}
|
|
34773
|
+
try {
|
|
34774
|
+
return store.read(activeContext.sessionId) ?? void 0;
|
|
34775
|
+
} catch (error51) {
|
|
34776
|
+
this.input.writeOutput?.(
|
|
34777
|
+
`agent_bridge_codex_thread_read_failed error=${errorMessage3(error51)}`
|
|
34778
|
+
);
|
|
34779
|
+
return void 0;
|
|
34780
|
+
}
|
|
34781
|
+
}
|
|
34782
|
+
persistThreadId(threadId) {
|
|
34783
|
+
const store = this.input.sessionResume;
|
|
34784
|
+
const activeContext = this.context;
|
|
34785
|
+
if (!store || !activeContext) {
|
|
34786
|
+
return;
|
|
34787
|
+
}
|
|
34788
|
+
try {
|
|
34789
|
+
store.write({ sessionId: activeContext.sessionId, threadId });
|
|
34790
|
+
} catch (error51) {
|
|
34791
|
+
this.input.writeOutput?.(
|
|
34792
|
+
`agent_bridge_codex_thread_persist_failed error=${errorMessage3(error51)}`
|
|
34793
|
+
);
|
|
34794
|
+
}
|
|
34795
|
+
}
|
|
34796
|
+
};
|
|
34797
|
+
function answerFallbackMessage2(answer) {
|
|
34798
|
+
const lines = Object.entries(answer.answers).map(
|
|
34799
|
+
([question, value]) => `- ${question}: ${value}`
|
|
34800
|
+
);
|
|
34801
|
+
if (answer.response) {
|
|
34802
|
+
lines.push(`The user also responded: ${answer.response}`);
|
|
34803
|
+
}
|
|
34804
|
+
return ["The user answered your questions:", ...lines].join("\n");
|
|
34805
|
+
}
|
|
34806
|
+
function deliveryMessage2(delivery) {
|
|
34807
|
+
const payload = delivery.payload;
|
|
34808
|
+
if (payload && typeof payload === "object" && "message" in payload && typeof payload.message === "string") {
|
|
34809
|
+
return payload.message;
|
|
34810
|
+
}
|
|
34811
|
+
return null;
|
|
34812
|
+
}
|
|
34813
|
+
function deliveryMode2(delivery) {
|
|
34814
|
+
const payload = delivery.payload;
|
|
34815
|
+
if (payload && typeof payload === "object" && "deliveryMode" in payload) {
|
|
34816
|
+
const parsed = MessageDeliveryModeSchema.safeParse(payload.deliveryMode);
|
|
34817
|
+
if (parsed.success) {
|
|
34818
|
+
return parsed.data;
|
|
34819
|
+
}
|
|
34820
|
+
}
|
|
34821
|
+
return "interrupt";
|
|
34822
|
+
}
|
|
34823
|
+
function errorMessage3(error51) {
|
|
34824
|
+
return error51 instanceof Error ? error51.message : String(error51);
|
|
34825
|
+
}
|
|
34826
|
+
|
|
34827
|
+
// src/commands/agent-bridge/harness/index.ts
|
|
34828
|
+
async function runAgentBridgeHarness(options) {
|
|
34829
|
+
await runAgentBridgeSocket({
|
|
34830
|
+
...options,
|
|
34831
|
+
createHandler: createHarnessCommandHandler
|
|
34832
|
+
});
|
|
34833
|
+
}
|
|
34834
|
+
function createHarnessCommandHandler(input) {
|
|
34835
|
+
const config2 = resolveHarnessConfig(input.bootstrap);
|
|
34836
|
+
const base = {
|
|
34837
|
+
emitOutput: input.emitOutput,
|
|
34838
|
+
...input.outputSeqStart !== void 0 ? { outputSeqStart: input.outputSeqStart } : {},
|
|
34839
|
+
...input.runtimeLogger ? { runtimeLogger: input.runtimeLogger } : {},
|
|
34840
|
+
socketId: input.socketId,
|
|
34841
|
+
...input.writeOutput ? { writeOutput: input.writeOutput } : {}
|
|
34842
|
+
};
|
|
34843
|
+
switch (config2.kind) {
|
|
34844
|
+
case "claude-code": {
|
|
34845
|
+
const { kind, ...claude } = config2;
|
|
34846
|
+
return createClaudeCodeCommandHandler({
|
|
34847
|
+
...base,
|
|
34848
|
+
claude,
|
|
34849
|
+
sessionResume: fileClaudeSessionResumeStore()
|
|
34850
|
+
});
|
|
34851
|
+
}
|
|
34852
|
+
case "codex": {
|
|
34853
|
+
const { kind, ...codex } = config2;
|
|
34854
|
+
return createCodexCommandHandler({
|
|
34855
|
+
...base,
|
|
34856
|
+
codex,
|
|
34857
|
+
sessionResume: fileCodexThreadResumeStore()
|
|
34858
|
+
});
|
|
34859
|
+
}
|
|
34860
|
+
}
|
|
34861
|
+
}
|
|
34862
|
+
function resolveHarnessConfig(bootstrap) {
|
|
34863
|
+
return bootstrap.harness ?? { kind: "claude-code", ...bootstrap.claude };
|
|
34864
|
+
}
|
|
34865
|
+
|
|
34866
|
+
// src/commands/agent-bridge/runtime-log.ts
|
|
34867
|
+
init_src();
|
|
34868
|
+
var RUNTIME_LOG_COMPONENT = "runtime-cli";
|
|
34869
|
+
var INGEST_BATCH_SIZE = 50;
|
|
34870
|
+
var INGEST_FLUSH_DELAY_MS = 1e3;
|
|
34871
|
+
var INGEST_MAX_QUEUED_LINES = 1e3;
|
|
34872
|
+
function createRuntimeLogger(env = process.env) {
|
|
34873
|
+
const level = parseRuntimeLogLevel(env.AUTO_RUNTIME_LOG_LEVEL);
|
|
34874
|
+
const ingest = createRuntimeLogIngest(env);
|
|
34875
|
+
let nextLogSeq = 1;
|
|
34876
|
+
const emit = (lineLevel) => {
|
|
34877
|
+
return (message, context) => {
|
|
34878
|
+
if (!runtimeLogLevelEnabled(level, lineLevel)) {
|
|
34879
|
+
return;
|
|
34880
|
+
}
|
|
34881
|
+
const line = runtimeLogLine({
|
|
34882
|
+
context,
|
|
34883
|
+
level: lineLevel,
|
|
34884
|
+
logSeq: nextLogSeq,
|
|
34885
|
+
message
|
|
34886
|
+
});
|
|
34887
|
+
nextLogSeq += 1;
|
|
34888
|
+
writeRuntimeLogLine(line);
|
|
34889
|
+
ingest?.enqueue(line);
|
|
34890
|
+
};
|
|
34891
|
+
};
|
|
34892
|
+
return {
|
|
34893
|
+
level,
|
|
34894
|
+
debug: emit("debug"),
|
|
34895
|
+
info: emit("info"),
|
|
34896
|
+
warn: emit("warn"),
|
|
34897
|
+
error: emit("error")
|
|
34898
|
+
};
|
|
34899
|
+
}
|
|
34900
|
+
function runtimeLogLine(input) {
|
|
34901
|
+
return {
|
|
34902
|
+
...input.context ?? {},
|
|
34903
|
+
logSeq: input.logSeq,
|
|
34904
|
+
timestamp: (/* @__PURE__ */ new Date()).toISOString(),
|
|
34905
|
+
level: input.level,
|
|
34906
|
+
component: RUNTIME_LOG_COMPONENT,
|
|
34907
|
+
message: input.message
|
|
34908
|
+
};
|
|
34909
|
+
}
|
|
34910
|
+
function writeRuntimeLogLine(payload) {
|
|
34911
|
+
process.stderr.write(`${JSON.stringify(payload, replaceErrors)}
|
|
34912
|
+
`);
|
|
34913
|
+
}
|
|
34914
|
+
function createRuntimeLogIngest(env) {
|
|
34915
|
+
const url2 = env[RUNTIME_LOG_INGEST_URL_ENV]?.trim();
|
|
34916
|
+
const token2 = env[RUNTIME_LOG_INGEST_TOKEN_ENV]?.trim();
|
|
34917
|
+
if (!url2 || !token2) {
|
|
34918
|
+
return void 0;
|
|
34919
|
+
}
|
|
34920
|
+
const queue = [];
|
|
34921
|
+
let flushTimer;
|
|
34922
|
+
let inFlight = false;
|
|
34923
|
+
const scheduleFlush = () => {
|
|
34924
|
+
if (flushTimer || inFlight) {
|
|
34925
|
+
return;
|
|
34926
|
+
}
|
|
34927
|
+
flushTimer = setTimeout(() => {
|
|
34928
|
+
flushTimer = void 0;
|
|
34929
|
+
void flush();
|
|
34930
|
+
}, INGEST_FLUSH_DELAY_MS);
|
|
34931
|
+
flushTimer.unref?.();
|
|
34932
|
+
};
|
|
34933
|
+
const flush = async () => {
|
|
34934
|
+
if (inFlight || queue.length === 0) {
|
|
34935
|
+
return;
|
|
34936
|
+
}
|
|
34937
|
+
inFlight = true;
|
|
34938
|
+
const batch = queue.splice(0, INGEST_BATCH_SIZE);
|
|
34939
|
+
try {
|
|
34940
|
+
const response = await fetch(url2, {
|
|
34941
|
+
method: "POST",
|
|
34942
|
+
headers: {
|
|
34943
|
+
authorization: `Bearer ${token2}`,
|
|
34944
|
+
"content-type": "application/json"
|
|
34945
|
+
},
|
|
34946
|
+
body: JSON.stringify({ lines: batch }, replaceErrors)
|
|
34947
|
+
});
|
|
34948
|
+
if (!response.ok) {
|
|
34949
|
+
if (shouldRetryIngestResponse(response)) {
|
|
34950
|
+
requeue(batch);
|
|
34951
|
+
}
|
|
34952
|
+
}
|
|
34953
|
+
} catch {
|
|
34954
|
+
requeue(batch);
|
|
34955
|
+
} finally {
|
|
34956
|
+
inFlight = false;
|
|
34957
|
+
if (queue.length > 0) {
|
|
34958
|
+
scheduleFlush();
|
|
34959
|
+
}
|
|
34960
|
+
}
|
|
34961
|
+
};
|
|
34962
|
+
const requeue = (batch) => {
|
|
34963
|
+
queue.unshift(...batch);
|
|
34964
|
+
trimQueue();
|
|
34965
|
+
};
|
|
34966
|
+
const trimQueue = () => {
|
|
34967
|
+
if (queue.length > INGEST_MAX_QUEUED_LINES) {
|
|
34968
|
+
queue.splice(0, queue.length - INGEST_MAX_QUEUED_LINES);
|
|
34969
|
+
}
|
|
34970
|
+
};
|
|
34971
|
+
return {
|
|
34972
|
+
enqueue(line) {
|
|
34973
|
+
queue.push(line);
|
|
34974
|
+
trimQueue();
|
|
34975
|
+
scheduleFlush();
|
|
34976
|
+
}
|
|
34977
|
+
};
|
|
34978
|
+
}
|
|
34979
|
+
function shouldRetryIngestResponse(response) {
|
|
34980
|
+
return response.status === 429 || response.status >= 500;
|
|
34981
|
+
}
|
|
34982
|
+
function replaceErrors(_key, value) {
|
|
34983
|
+
if (value instanceof Error) {
|
|
34984
|
+
return { name: value.name, message: value.message, stack: value.stack };
|
|
34985
|
+
}
|
|
34986
|
+
return value;
|
|
34987
|
+
}
|
|
34988
|
+
|
|
34989
|
+
// src/commands/agent-bridge/entrypoint.ts
|
|
34990
|
+
async function runAgentBridgeProcess(input) {
|
|
34991
|
+
const runAgentBridge = input.runAgentBridge ?? runAgentBridgeHarness;
|
|
34992
|
+
const log = createRuntimeLogger(input.env);
|
|
34993
|
+
log.info("agent bridge process starting", {
|
|
34994
|
+
bridge_url_host: bridgeUrlHost(input.env.AUTO_BRIDGE_URL),
|
|
34995
|
+
log_level: log.level
|
|
34996
|
+
});
|
|
34997
|
+
try {
|
|
34998
|
+
await runAgentBridge({
|
|
34999
|
+
...agentBridgeOptionsFromEnv(input),
|
|
35000
|
+
runtimeLogger: log,
|
|
35001
|
+
onBootstrap: createGitCredentialRelayStarter(input.writeOutput, log)
|
|
35002
|
+
});
|
|
35003
|
+
} catch (error51) {
|
|
35004
|
+
log.error("agent bridge process failed", { error: error51 });
|
|
35005
|
+
throw error51;
|
|
35006
|
+
}
|
|
35007
|
+
}
|
|
35008
|
+
function agentBridgeOptionsFromEnv(input) {
|
|
35009
|
+
return {
|
|
35010
|
+
bridgeUrl: requiredEnv(input.env, "AUTO_BRIDGE_URL"),
|
|
35011
|
+
token: requiredEnv(input.env, "AGENT_BRIDGE_TOKEN"),
|
|
35012
|
+
writeOutput: input.writeOutput
|
|
35013
|
+
};
|
|
35014
|
+
}
|
|
35015
|
+
function createGitCredentialRelayStarter(writeOutput, log) {
|
|
35016
|
+
let relay;
|
|
35017
|
+
let startup;
|
|
35018
|
+
return async (bootstrap) => {
|
|
35019
|
+
const gitCredentials = bootstrap.gitCredentials;
|
|
35020
|
+
if (!gitCredentials) {
|
|
35021
|
+
return;
|
|
35022
|
+
}
|
|
35023
|
+
if (relay) {
|
|
35024
|
+
relay.update(gitCredentials);
|
|
33709
35025
|
return;
|
|
33710
35026
|
}
|
|
33711
35027
|
if (startup) {
|
|
@@ -33825,9 +35141,9 @@ function statusAgents(input) {
|
|
|
33825
35141
|
// src/commands/agents/connect.ts
|
|
33826
35142
|
init_resources2();
|
|
33827
35143
|
init_browser();
|
|
33828
|
-
import { existsSync as
|
|
35144
|
+
import { existsSync as existsSync3, mkdtempSync, writeFileSync as writeFileSync5 } from "fs";
|
|
33829
35145
|
import { homedir as homedir3, tmpdir } from "os";
|
|
33830
|
-
import { join as
|
|
35146
|
+
import { join as join6 } from "path";
|
|
33831
35147
|
|
|
33832
35148
|
// src/lib/stdio/secret.ts
|
|
33833
35149
|
async function questionSecret(context, prompt) {
|
|
@@ -34018,7 +35334,7 @@ async function promptForIconUploads(input, options) {
|
|
|
34018
35334
|
}
|
|
34019
35335
|
}
|
|
34020
35336
|
function stagedLocationLabel(stagedPath) {
|
|
34021
|
-
return stagedPath.startsWith(`${
|
|
35337
|
+
return stagedPath.startsWith(`${join6(homedir3(), "Downloads")}/`) ? "Downloads" : "the printed path";
|
|
34022
35338
|
}
|
|
34023
35339
|
async function stageAvatarImage(input) {
|
|
34024
35340
|
try {
|
|
@@ -34030,10 +35346,10 @@ async function stageAvatarImage(input) {
|
|
|
34030
35346
|
}
|
|
34031
35347
|
const contentType = response.headers.get("content-type") ?? "";
|
|
34032
35348
|
const extension = contentType.includes("jpeg") ? ".jpg" : ".png";
|
|
34033
|
-
const downloads =
|
|
34034
|
-
const directory =
|
|
34035
|
-
const path2 =
|
|
34036
|
-
|
|
35349
|
+
const downloads = join6(homedir3(), "Downloads");
|
|
35350
|
+
const directory = existsSync3(downloads) ? downloads : mkdtempSync(join6(tmpdir(), "auto-avatar-"));
|
|
35351
|
+
const path2 = join6(directory, `${input.agent}-avatar${extension}`);
|
|
35352
|
+
writeFileSync5(path2, Buffer.from(await response.arrayBuffer()));
|
|
34037
35353
|
return path2;
|
|
34038
35354
|
} catch {
|
|
34039
35355
|
return void 0;
|
|
@@ -35497,19 +36813,19 @@ init_src();
|
|
|
35497
36813
|
// src/commands/logs/actions.ts
|
|
35498
36814
|
import {
|
|
35499
36815
|
closeSync,
|
|
35500
|
-
existsSync as
|
|
36816
|
+
existsSync as existsSync5,
|
|
35501
36817
|
openSync,
|
|
35502
|
-
readFileSync as
|
|
36818
|
+
readFileSync as readFileSync7,
|
|
35503
36819
|
readSync,
|
|
35504
36820
|
statSync as statSync3
|
|
35505
36821
|
} from "fs";
|
|
35506
36822
|
var DEFAULT_POLL_INTERVAL_MS = 1e3;
|
|
35507
36823
|
async function tailRuntimeLog(input) {
|
|
35508
|
-
if (!
|
|
36824
|
+
if (!existsSync5(input.path)) {
|
|
35509
36825
|
input.writeError(`No runtime log at ${input.path}`);
|
|
35510
36826
|
return;
|
|
35511
36827
|
}
|
|
35512
|
-
const content =
|
|
36828
|
+
const content = readFileSync7(input.path, "utf8");
|
|
35513
36829
|
for (const line of selectLastLines(content, input.lines)) {
|
|
35514
36830
|
input.writeOutput(line);
|
|
35515
36831
|
}
|