@autohq/cli 0.1.225 → 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/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 errorMessage4 = isError ? record2.error ?? record2.result ?? (sdkErrorMessage || void 0) ?? "claude-code reported an error" : void 0;
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: errorMessage4
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
- var CodexRequestIdSchema, CodexTurnStatusSchema, CodexUserMessageItemSchema, CodexAgentMessageItemSchema, CodexReasoningItemSchema, CodexCommandExecutionItemSchema, CodexFileChangeItemSchema, CodexMcpToolCallItemSchema, CodexItemSchema, OptionalCodexItemSchema, CodexItemEnvelopeSchema, CodexTurnEnvelopeSchema, CodexFrameSchema;
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.225",
22241
+ version: "0.1.226",
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 readFileSync3, readdirSync as readdirSync2, statSync } from "fs";
22305
+ import { readFileSync as readFileSync4, readdirSync as readdirSync2, statSync } from "fs";
22062
22306
  import {
22063
22307
  basename as basename2,
22064
- dirname as dirname4,
22308
+ dirname as dirname5,
22065
22309
  extname,
22066
22310
  isAbsolute,
22067
- join as join3,
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 = join3(
22120
- input?.directory ?? join3(process.cwd(), ".auto"),
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 = join3(directory, entry.name);
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 = join3(
22180
- input.directory ?? join3(process.cwd(), ".auto"),
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 = join3(agentsDirectory, `${input.agent}${extension}`);
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 = readFileSync3(path2, "utf8");
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(dirname4(importerPath), importPath);
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 readFileSync3(resolve(dirname4(input.path), filePath), "utf8");
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 existsSync3,
24023
- readFileSync as readFileSync4,
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 dirname5,
24274
+ dirname as dirname6,
24031
24275
  extname as extname3,
24032
24276
  isAbsolute as isAbsolute2,
24033
- join as join5,
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 ?? join5(process.cwd(), ".auto"));
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 = join5(root, entry.name);
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: readFileSync4(path2).toString("base64")
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: readFileSync4(path2)
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" ? dirname5(resolved) : resolved;
24390
+ return basename3(resolved) === ".auto" ? dirname6(resolved) : resolved;
24147
24391
  }
24148
24392
  function applyFileProjectRoot(file2) {
24149
- let dir = dirname5(resolve2(file2));
24393
+ let dir = dirname6(resolve2(file2));
24150
24394
  while (true) {
24151
24395
  if (basename3(dir) === ".auto") {
24152
- return dirname5(dir);
24396
+ return dirname6(dir);
24153
24397
  }
24154
24398
  if (directoryHasAutoRoot(dir)) {
24155
24399
  return dir;
24156
24400
  }
24157
- const parent = dirname5(dir);
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 : dirname5(file2);
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 (!existsSync3(autoRoot)) {
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 spawn2 } from "child_process";
25005
+ import { spawn as spawn3 } from "child_process";
24762
25006
  import {
24763
- mkdirSync as mkdirSync3,
25007
+ mkdirSync as mkdirSync5,
24764
25008
  mkdtempSync as mkdtempSync2,
24765
- readFileSync as readFileSync5,
25009
+ readFileSync as readFileSync6,
24766
25010
  rmSync as rmSync2,
24767
- writeFileSync as writeFileSync4
25011
+ writeFileSync as writeFileSync6
24768
25012
  } from "fs";
24769
25013
  import { tmpdir as tmpdir2 } from "os";
24770
- import { join as join6 } from "path";
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(join6(tmpdir2(), "auto-edit-"));
24791
- const agentsDir = join6(tempRoot, ".auto", "agents");
24792
- mkdirSync3(agentsDir, { recursive: true });
24793
- const filePath = join6(agentsDir, `${reference.name}.yaml`);
24794
- writeFileSync4(filePath, source, "utf8");
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 = readFileSync5(filePath, "utf8");
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 = spawn2(editor, [filePath], {
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 = readFileSync5(filePath, "utf8");
25108
+ const source = readFileSync6(filePath, "utf8");
24865
25109
  let parsedDocuments;
24866
25110
  try {
24867
25111
  parsedDocuments = parseYamlDocuments3(source);
@@ -27983,7 +28227,7 @@ function SessionsView({
27983
28227
  visibleSessions.map((session, vi) => {
27984
28228
  const i = scrollOffset + vi;
27985
28229
  const title = sessionDisplayTitle(session);
27986
- const err = session.status === "failed" ? errorMessage2(session) : null;
28230
+ const err = session.status === "failed" ? errorMessage4(session) : null;
27987
28231
  const isSelected = i === safeIndex;
27988
28232
  const isMarked = selectedSessionIds.has(session.id);
27989
28233
  return /* @__PURE__ */ jsxs10(Box11, { flexDirection: "column", children: [
@@ -28121,7 +28365,7 @@ function truncateToWidth(value, width) {
28121
28365
  function agentNameForRun(session) {
28122
28366
  return session.snapshot.metadata.name;
28123
28367
  }
28124
- function errorMessage2(session) {
28368
+ function errorMessage4(session) {
28125
28369
  if (session.error == null) return null;
28126
28370
  if (typeof session.error === "string") return session.error;
28127
28371
  const msg = readField(session.error, "message");
@@ -29543,7 +29787,7 @@ function HomeView({ apiUrl, notice, returnToAgent }) {
29543
29787
  if (inspectedResource) {
29544
29788
  sectionTitle = `Inspect ${inspectedResource.kind}/${inspectedResource.name}`;
29545
29789
  }
29546
- const runError = errorMessage3(triggerSession.error) ?? errorMessage3(archiveSessions.error) ?? errorMessage3(unarchiveSessions.error) ?? errorMessage3(stopSessions.error);
29790
+ const runError = errorMessage5(triggerSession.error) ?? errorMessage5(archiveSessions.error) ?? errorMessage5(unarchiveSessions.error) ?? errorMessage5(stopSessions.error);
29547
29791
  const isRunMutationPending = triggerSession.isPending || archiveSessions.isPending || unarchiveSessions.isPending || stopSessions.isPending;
29548
29792
  const isConnectionMutationPending = startConnection.isPending || allowConnection.isPending || removeConnection.isPending || createGithubSyncBinding.isPending;
29549
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;
@@ -29956,7 +30200,7 @@ function runActionTargetLabel(sessionIds, markedRunCount) {
29956
30200
  function pluralizeRunCount(count) {
29957
30201
  return `${count} ${count === 1 ? "session" : "sessions"}`;
29958
30202
  }
29959
- function errorMessage3(error51) {
30203
+ function errorMessage5(error51) {
29960
30204
  if (error51 instanceof Error) return error51.message;
29961
30205
  return error51 ? String(error51) : null;
29962
30206
  }
@@ -30277,8 +30521,8 @@ __export(launcher_exports, {
30277
30521
  launch: () => launch
30278
30522
  });
30279
30523
  import { spawnSync } from "child_process";
30280
- import { existsSync as existsSync5 } from "fs";
30281
- import { dirname as dirname6, resolve as resolve3 } from "path";
30524
+ import { existsSync as existsSync6 } from "fs";
30525
+ import { dirname as dirname7, resolve as resolve3 } from "path";
30282
30526
  import { fileURLToPath } from "url";
30283
30527
  import {
30284
30528
  QueryClient,
@@ -30455,7 +30699,7 @@ function resolveSplashVersion() {
30455
30699
  return resolveLatestReleaseVersionFromCheckout() ?? cliVersion;
30456
30700
  }
30457
30701
  function resolveLatestReleaseVersionFromCheckout() {
30458
- const repoRoot = findRepoRoot(dirname6(fileURLToPath(import.meta.url)));
30702
+ const repoRoot = findRepoRoot(dirname7(fileURLToPath(import.meta.url)));
30459
30703
  if (!repoRoot) {
30460
30704
  return null;
30461
30705
  }
@@ -30472,10 +30716,10 @@ function resolveLatestReleaseVersionFromCheckout() {
30472
30716
  function findRepoRoot(startDirectory) {
30473
30717
  let directory = startDirectory;
30474
30718
  while (true) {
30475
- if (existsSync5(resolve3(directory, ".git")) && existsSync5(resolve3(directory, "apps/cli/package.json"))) {
30719
+ if (existsSync6(resolve3(directory, ".git")) && existsSync6(resolve3(directory, "apps/cli/package.json"))) {
30476
30720
  return directory;
30477
30721
  }
30478
- const parent = dirname6(directory);
30722
+ const parent = dirname7(directory);
30479
30723
  if (parent === directory) {
30480
30724
  return null;
30481
30725
  }
@@ -31476,6 +31720,9 @@ var AgentBridgeClaudeConfigSchema = AgentBridgeHarnessBaseConfigSchema;
31476
31720
  var AgentBridgeHarnessConfigSchema = external_exports.discriminatedUnion("kind", [
31477
31721
  AgentBridgeHarnessBaseConfigSchema.extend({
31478
31722
  kind: external_exports.literal("claude-code")
31723
+ }),
31724
+ AgentBridgeHarnessBaseConfigSchema.extend({
31725
+ kind: external_exports.literal("codex")
31479
31726
  })
31480
31727
  ]);
31481
31728
  var RuntimeBridgeBootstrapPlaintextSchema = external_exports.object({
@@ -33597,96 +33844,1084 @@ function commandLogContext(delivery, fields = {}) {
33597
33844
  };
33598
33845
  }
33599
33846
 
33600
- // src/commands/agent-bridge/harness/index.ts
33601
- async function runAgentBridgeHarness(options) {
33602
- await runAgentBridgeSocket({
33603
- ...options,
33604
- createHandler: createHarnessCommandHandler
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"
33605
33932
  });
33606
33933
  }
33607
- function createHarnessCommandHandler(input) {
33608
- const config2 = resolveHarnessConfig(input.bootstrap);
33609
- const base = {
33610
- emitOutput: input.emitOutput,
33611
- ...input.outputSeqStart !== void 0 ? { outputSeqStart: input.outputSeqStart } : {},
33612
- ...input.runtimeLogger ? { runtimeLogger: input.runtimeLogger } : {},
33613
- socketId: input.socketId,
33614
- ...input.writeOutput ? { writeOutput: input.writeOutput } : {}
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
+ }
33615
33957
  };
33616
- switch (config2.kind) {
33617
- case "claude-code": {
33618
- const { kind, ...claude } = config2;
33619
- return createClaudeCodeCommandHandler({
33620
- ...base,
33621
- claude,
33622
- sessionResume: fileClaudeSessionResumeStore()
33623
- });
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");
33624
33981
  }
33625
- }
33982
+ };
33626
33983
  }
33627
- function resolveHarnessConfig(bootstrap) {
33628
- return bootstrap.harness ?? { kind: "claude-code", ...bootstrap.claude };
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
+ }
33629
33994
  }
33630
33995
 
33631
- // src/commands/agent-bridge/runtime-log.ts
33996
+ // src/commands/agent-bridge/harness/codex/session.ts
33632
33997
  init_src();
33633
- var RUNTIME_LOG_COMPONENT = "runtime-cli";
33634
- var INGEST_BATCH_SIZE = 50;
33635
- var INGEST_FLUSH_DELAY_MS = 1e3;
33636
- var INGEST_MAX_QUEUED_LINES = 1e3;
33637
- function createRuntimeLogger(env = process.env) {
33638
- const level = parseRuntimeLogLevel(env.AUTO_RUNTIME_LOG_LEVEL);
33639
- const ingest = createRuntimeLogIngest(env);
33640
- let nextLogSeq = 1;
33641
- const emit = (lineLevel) => {
33642
- return (message, context) => {
33643
- if (!runtimeLogLevelEnabled(level, lineLevel)) {
33644
- return;
33645
- }
33646
- const line = runtimeLogLine({
33647
- context,
33648
- level: lineLevel,
33649
- logSeq: nextLogSeq,
33650
- message
33651
- });
33652
- nextLogSeq += 1;
33653
- writeRuntimeLogLine(line);
33654
- ingest?.enqueue(line);
33655
- };
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)
33656
34021
  };
34022
+ }
34023
+ function codexThreadParams(config2) {
33657
34024
  return {
33658
- level,
33659
- debug: emit("debug"),
33660
- info: emit("info"),
33661
- warn: emit("warn"),
33662
- error: emit("error")
34025
+ ...config2.cwd ? { cwd: config2.cwd } : {},
34026
+ ...config2.systemPromptAppend ? { developerInstructions: config2.systemPromptAppend } : {}
33663
34027
  };
33664
34028
  }
33665
- function runtimeLogLine(input) {
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
+ }
33666
34059
  return {
33667
- ...input.context ?? {},
33668
- logSeq: input.logSeq,
33669
- timestamp: (/* @__PURE__ */ new Date()).toISOString(),
33670
- level: input.level,
33671
- component: RUNTIME_LOG_COMPONENT,
33672
- message: input.message
34060
+ ...selected,
34061
+ ...env
33673
34062
  };
33674
34063
  }
33675
- function writeRuntimeLogLine(payload) {
33676
- process.stderr.write(`${JSON.stringify(payload, replaceErrors)}
33677
- `);
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");
34068
+ }
34069
+ return join3(home, ".codex");
33678
34070
  }
33679
- function createRuntimeLogIngest(env) {
33680
- const url2 = env[RUNTIME_LOG_INGEST_URL_ENV]?.trim();
33681
- const token2 = env[RUNTIME_LOG_INGEST_TOKEN_ENV]?.trim();
33682
- if (!url2 || !token2) {
33683
- return void 0;
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();
33684
34074
  }
33685
- const queue = [];
33686
- let flushTimer;
33687
- let inFlight = false;
33688
- const scheduleFlush = () => {
33689
- if (flushTimer || inFlight) {
34075
+ return CODEX_EXECUTABLE_PATH;
34076
+ }
34077
+ function tomlInlineTable(values) {
34078
+ const entries = Object.entries(values).map(
34079
+ ([key, value]) => `${tomlKey(key)} = ${tomlString(value)}`
34080
+ );
34081
+ return `{ ${entries.join(", ")} }`;
34082
+ }
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) {
33690
34925
  return;
33691
34926
  }
33692
34927
  flushTimer = setTimeout(() => {
@@ -33906,9 +35141,9 @@ function statusAgents(input) {
33906
35141
  // src/commands/agents/connect.ts
33907
35142
  init_resources2();
33908
35143
  init_browser();
33909
- import { existsSync as existsSync2, mkdtempSync, writeFileSync as writeFileSync3 } from "fs";
35144
+ import { existsSync as existsSync3, mkdtempSync, writeFileSync as writeFileSync5 } from "fs";
33910
35145
  import { homedir as homedir3, tmpdir } from "os";
33911
- import { join as join4 } from "path";
35146
+ import { join as join6 } from "path";
33912
35147
 
33913
35148
  // src/lib/stdio/secret.ts
33914
35149
  async function questionSecret(context, prompt) {
@@ -34099,7 +35334,7 @@ async function promptForIconUploads(input, options) {
34099
35334
  }
34100
35335
  }
34101
35336
  function stagedLocationLabel(stagedPath) {
34102
- return stagedPath.startsWith(`${join4(homedir3(), "Downloads")}/`) ? "Downloads" : "the printed path";
35337
+ return stagedPath.startsWith(`${join6(homedir3(), "Downloads")}/`) ? "Downloads" : "the printed path";
34103
35338
  }
34104
35339
  async function stageAvatarImage(input) {
34105
35340
  try {
@@ -34111,10 +35346,10 @@ async function stageAvatarImage(input) {
34111
35346
  }
34112
35347
  const contentType = response.headers.get("content-type") ?? "";
34113
35348
  const extension = contentType.includes("jpeg") ? ".jpg" : ".png";
34114
- const downloads = join4(homedir3(), "Downloads");
34115
- const directory = existsSync2(downloads) ? downloads : mkdtempSync(join4(tmpdir(), "auto-avatar-"));
34116
- const path2 = join4(directory, `${input.agent}-avatar${extension}`);
34117
- writeFileSync3(path2, Buffer.from(await response.arrayBuffer()));
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()));
34118
35353
  return path2;
34119
35354
  } catch {
34120
35355
  return void 0;
@@ -35578,19 +36813,19 @@ init_src();
35578
36813
  // src/commands/logs/actions.ts
35579
36814
  import {
35580
36815
  closeSync,
35581
- existsSync as existsSync4,
36816
+ existsSync as existsSync5,
35582
36817
  openSync,
35583
- readFileSync as readFileSync6,
36818
+ readFileSync as readFileSync7,
35584
36819
  readSync,
35585
36820
  statSync as statSync3
35586
36821
  } from "fs";
35587
36822
  var DEFAULT_POLL_INTERVAL_MS = 1e3;
35588
36823
  async function tailRuntimeLog(input) {
35589
- if (!existsSync4(input.path)) {
36824
+ if (!existsSync5(input.path)) {
35590
36825
  input.writeError(`No runtime log at ${input.path}`);
35591
36826
  return;
35592
36827
  }
35593
- const content = readFileSync6(input.path, "utf8");
36828
+ const content = readFileSync7(input.path, "utf8");
35594
36829
  for (const line of selectLastLines(content, input.lines)) {
35595
36830
  input.writeOutput(line);
35596
36831
  }