@autohq/cli 0.1.582 → 0.1.584
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 +37639 -27101
- package/dist/index.js +706 -123
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -16681,13 +16681,13 @@ function parseClaudeCodeStreamRecord(parsed) {
|
|
|
16681
16681
|
}
|
|
16682
16682
|
const isError = record2.is_error === true || record2.subtype === "error";
|
|
16683
16683
|
const sdkErrorMessage = record2.errors?.map((error51) => error51.trim()).filter(Boolean).join("\n");
|
|
16684
|
-
const
|
|
16684
|
+
const errorMessage7 = isError ? record2.error ?? record2.result ?? (sdkErrorMessage || void 0) ?? "claude-code reported an error" : void 0;
|
|
16685
16685
|
const usage = claudeCodeUsageFromRecord(record2);
|
|
16686
16686
|
return {
|
|
16687
16687
|
projections: [],
|
|
16688
16688
|
result: {
|
|
16689
16689
|
isError,
|
|
16690
|
-
errorMessage:
|
|
16690
|
+
errorMessage: errorMessage7,
|
|
16691
16691
|
...usage ? { usage } : {}
|
|
16692
16692
|
}
|
|
16693
16693
|
};
|
|
@@ -16705,11 +16705,11 @@ function isClaudeCodeInterruptMarker(record2) {
|
|
|
16705
16705
|
(block) => block !== null && block.type === "text" && block.text.startsWith(CLAUDE_CODE_INTERRUPT_MARKER_PREFIX)
|
|
16706
16706
|
);
|
|
16707
16707
|
}
|
|
16708
|
-
function isClaudeCodeEdeDiagnosticOnlyError(
|
|
16709
|
-
if (!
|
|
16708
|
+
function isClaudeCodeEdeDiagnosticOnlyError(errorMessage7) {
|
|
16709
|
+
if (!errorMessage7) {
|
|
16710
16710
|
return false;
|
|
16711
16711
|
}
|
|
16712
|
-
const lines =
|
|
16712
|
+
const lines = errorMessage7.split("\n").map((line) => line.trim()).filter((line) => line.length > 0);
|
|
16713
16713
|
return lines.length > 0 && lines.every((line) => line.startsWith(CLAUDE_CODE_EDE_DIAGNOSTIC_PREFIX));
|
|
16714
16714
|
}
|
|
16715
16715
|
function isClaudeCodePermissionDenialText(text) {
|
|
@@ -19375,7 +19375,7 @@ var init_trigger_filters = __esm({
|
|
|
19375
19375
|
});
|
|
19376
19376
|
|
|
19377
19377
|
// ../../packages/schemas/src/tasks.ts
|
|
19378
|
-
var TASK_STATUSES, TaskStatusSchema, TASK_COMPLETION_KINDS, TaskCompletionKindSchema, TASK_LINK_ROLES, TaskLinkRoleSchema, TASK_LINK_STATUSES, TaskLinkStatusSchema, TASK_LINK_TARGET_TYPES, TaskLinkTargetTypeSchema, TaskLinkTargetSchema, TaskOutcomeSchema, TaskArchiveRequestSchema, TasksArchiveRequestSchema, TaskArchiveFilterSchema, TaskReadModelSchema, TaskListResponseSchema;
|
|
19378
|
+
var TASK_STATUSES, TaskStatusSchema, TASK_COMPLETION_KINDS, TaskCompletionKindSchema, TASK_LINK_ROLES, TaskLinkRoleSchema, TASK_LINK_STATUSES, TaskLinkStatusSchema, TASK_LINK_TARGET_TYPES, TaskLinkTargetTypeSchema, TaskLinkTargetSchema, TaskOutcomeSchema, TaskPullRequestSchema, TaskArchiveRequestSchema, TasksArchiveRequestSchema, TaskArchiveFilterSchema, TaskReadModelSchema, TaskListResponseSchema;
|
|
19379
19379
|
var init_tasks = __esm({
|
|
19380
19380
|
"../../packages/schemas/src/tasks.ts"() {
|
|
19381
19381
|
"use strict";
|
|
@@ -19413,6 +19413,11 @@ var init_tasks = __esm({
|
|
|
19413
19413
|
"Target type cannot be linked to a task"
|
|
19414
19414
|
);
|
|
19415
19415
|
TaskOutcomeSchema = JsonObjectSchema;
|
|
19416
|
+
TaskPullRequestSchema = external_exports.object({
|
|
19417
|
+
externalId: external_exports.string(),
|
|
19418
|
+
repository: external_exports.string(),
|
|
19419
|
+
number: external_exports.number().int().positive()
|
|
19420
|
+
});
|
|
19416
19421
|
TaskArchiveRequestSchema = external_exports.object({ archived: external_exports.boolean() }).strict();
|
|
19417
19422
|
TasksArchiveRequestSchema = external_exports.object({
|
|
19418
19423
|
task_ids: external_exports.array(external_exports.string().trim().min(1)).min(1).max(100),
|
|
@@ -19432,6 +19437,7 @@ var init_tasks = __esm({
|
|
|
19432
19437
|
context: JsonObjectSchema.nullable(),
|
|
19433
19438
|
createdBySessionId: external_exports.string().nullable(),
|
|
19434
19439
|
requester: JsonObjectSchema.nullable(),
|
|
19440
|
+
pullRequests: external_exports.array(TaskPullRequestSchema).optional(),
|
|
19435
19441
|
revision: external_exports.number().int().positive(),
|
|
19436
19442
|
archivedAt: external_exports.string().datetime().nullable(),
|
|
19437
19443
|
createdAt: external_exports.string().datetime(),
|
|
@@ -88600,7 +88606,7 @@ var init_package = __esm({
|
|
|
88600
88606
|
"package.json"() {
|
|
88601
88607
|
package_default = {
|
|
88602
88608
|
name: "@autohq/cli",
|
|
88603
|
-
version: "0.1.
|
|
88609
|
+
version: "0.1.584",
|
|
88604
88610
|
license: "SEE LICENSE IN README.md",
|
|
88605
88611
|
publishConfig: {
|
|
88606
88612
|
access: "public"
|
|
@@ -92331,9 +92337,9 @@ var init_actions = __esm({
|
|
|
92331
92337
|
});
|
|
92332
92338
|
|
|
92333
92339
|
// src/commands/auth/pkce.ts
|
|
92334
|
-
import { createHash as createHash6, randomBytes as
|
|
92340
|
+
import { createHash as createHash6, randomBytes as randomBytes4 } from "crypto";
|
|
92335
92341
|
function pkceVerifier() {
|
|
92336
|
-
return
|
|
92342
|
+
return randomBytes4(32).toString("base64url");
|
|
92337
92343
|
}
|
|
92338
92344
|
function pkceChallenge(verifier) {
|
|
92339
92345
|
return createHash6("sha256").update(verifier).digest("base64url");
|
|
@@ -95898,7 +95904,7 @@ function SessionsView({
|
|
|
95898
95904
|
visibleSessions.map((session, vi) => {
|
|
95899
95905
|
const i = scrollOffset + vi;
|
|
95900
95906
|
const title = sessionDisplayTitle(session);
|
|
95901
|
-
const err = session.status === "failed" ?
|
|
95907
|
+
const err = session.status === "failed" ? errorMessage5(session) : null;
|
|
95902
95908
|
const isSelected = i === safeIndex;
|
|
95903
95909
|
const isMarked = selectedSessionIds.has(session.id);
|
|
95904
95910
|
return /* @__PURE__ */ jsxs10(Box11, { flexDirection: "column", children: [
|
|
@@ -96036,7 +96042,7 @@ function truncateToWidth(value, width) {
|
|
|
96036
96042
|
function agentNameForRun(session) {
|
|
96037
96043
|
return session.snapshot.metadata.name;
|
|
96038
96044
|
}
|
|
96039
|
-
function
|
|
96045
|
+
function errorMessage5(session) {
|
|
96040
96046
|
if (session.error == null) return null;
|
|
96041
96047
|
if (typeof session.error === "string") return session.error;
|
|
96042
96048
|
const msg = readField(session.error, "message");
|
|
@@ -97471,7 +97477,7 @@ function HomeView({
|
|
|
97471
97477
|
if (inspectedResource) {
|
|
97472
97478
|
sectionTitle = `Inspect ${inspectedResource.kind}/${inspectedResource.name}`;
|
|
97473
97479
|
}
|
|
97474
|
-
const runError =
|
|
97480
|
+
const runError = errorMessage6(triggerSession.error) ?? errorMessage6(archiveSessions.error) ?? errorMessage6(unarchiveSessions.error) ?? errorMessage6(stopSessions.error);
|
|
97475
97481
|
const isRunMutationPending = triggerSession.isPending || archiveSessions.isPending || unarchiveSessions.isPending || stopSessions.isPending;
|
|
97476
97482
|
const isConnectionMutationPending = startConnection.isPending || allowConnection.isPending || removeConnection.isPending || createGithubSyncBinding.isPending;
|
|
97477
97483
|
const serviceAccountStatus = createServiceAccount2.error instanceof Error ? createServiceAccount2.error.message : rotateServiceAccount2.error instanceof Error ? rotateServiceAccount2.error.message : removeServiceAccount2.error instanceof Error ? removeServiceAccount2.error.message : serviceAccountNotice;
|
|
@@ -97884,7 +97890,7 @@ function runActionTargetLabel(sessionIds, markedRunCount) {
|
|
|
97884
97890
|
function pluralizeRunCount(count) {
|
|
97885
97891
|
return `${count} ${count === 1 ? "session" : "sessions"}`;
|
|
97886
97892
|
}
|
|
97887
|
-
function
|
|
97893
|
+
function errorMessage6(error51) {
|
|
97888
97894
|
if (error51 instanceof Error) return error51.message;
|
|
97889
97895
|
return error51 ? String(error51) : null;
|
|
97890
97896
|
}
|
|
@@ -100727,7 +100733,7 @@ function jsonRecordString(value, key) {
|
|
|
100727
100733
|
init_src();
|
|
100728
100734
|
|
|
100729
100735
|
// src/commands/agent-bridge/harness/agent-facing-auto-mcp.ts
|
|
100730
|
-
import { randomBytes as randomBytes2
|
|
100736
|
+
import { randomBytes as randomBytes2 } from "crypto";
|
|
100731
100737
|
import { lstatSync, readFileSync as readFileSync3, realpathSync, statSync } from "fs";
|
|
100732
100738
|
import {
|
|
100733
100739
|
createServer as createServer3
|
|
@@ -100745,7 +100751,17 @@ import {
|
|
|
100745
100751
|
import { parseAllDocuments as parseAllDocuments2 } from "yaml";
|
|
100746
100752
|
|
|
100747
100753
|
// src/commands/agent-bridge/harness/turn-bound-mcp.ts
|
|
100754
|
+
import { timingSafeEqual } from "crypto";
|
|
100748
100755
|
var AGENT_BRIDGE_MCP_CAPABILITY_HEADER = "x-auto-agent-bridge-mcp-capability";
|
|
100756
|
+
function requestHasMcpCapability(headers, expected) {
|
|
100757
|
+
const received = headers[AGENT_BRIDGE_MCP_CAPABILITY_HEADER];
|
|
100758
|
+
if (typeof received !== "string") {
|
|
100759
|
+
return false;
|
|
100760
|
+
}
|
|
100761
|
+
const expectedBytes = Buffer.from(expected);
|
|
100762
|
+
const receivedBytes = Buffer.from(received);
|
|
100763
|
+
return expectedBytes.length === receivedBytes.length && timingSafeEqual(expectedBytes, receivedBytes);
|
|
100764
|
+
}
|
|
100749
100765
|
|
|
100750
100766
|
// src/commands/agent-bridge/harness/agent-facing-auto-mcp.ts
|
|
100751
100767
|
var MAX_DRY_RUN_PATH_FILES = 100;
|
|
@@ -101215,7 +101231,7 @@ async function startAutoMcpProxy(input) {
|
|
|
101215
101231
|
let pathsCompatible = false;
|
|
101216
101232
|
const server = createServer3(async (request, response) => {
|
|
101217
101233
|
try {
|
|
101218
|
-
if (!
|
|
101234
|
+
if (!requestHasMcpCapability(request.headers, input.capability)) {
|
|
101219
101235
|
writeResponse(
|
|
101220
101236
|
response,
|
|
101221
101237
|
401,
|
|
@@ -101421,15 +101437,6 @@ function exactActiveCommandId(activeTurnCommandIds) {
|
|
|
101421
101437
|
const commandIds = activeTurnCommandIds();
|
|
101422
101438
|
return commandIds.length === 1 ? commandIds[0] ?? null : null;
|
|
101423
101439
|
}
|
|
101424
|
-
function requestHasCapability(headers, expected) {
|
|
101425
|
-
const received = headers[AGENT_BRIDGE_MCP_CAPABILITY_HEADER];
|
|
101426
|
-
if (typeof received !== "string") {
|
|
101427
|
-
return false;
|
|
101428
|
-
}
|
|
101429
|
-
const expectedBytes = Buffer.from(expected);
|
|
101430
|
-
const receivedBytes = Buffer.from(received);
|
|
101431
|
-
return expectedBytes.length === receivedBytes.length && timingSafeEqual(expectedBytes, receivedBytes);
|
|
101432
|
-
}
|
|
101433
101440
|
function readRequestBody(request) {
|
|
101434
101441
|
return new Promise((resolveBody, reject) => {
|
|
101435
101442
|
const chunks = [];
|
|
@@ -101462,6 +101469,384 @@ function isRecord2(value) {
|
|
|
101462
101469
|
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
101463
101470
|
}
|
|
101464
101471
|
|
|
101472
|
+
// src/commands/agent-bridge/harness/ask-user-projection.ts
|
|
101473
|
+
init_src();
|
|
101474
|
+
var ASK_USER_MCP_SERVER_NAME = "user";
|
|
101475
|
+
var ASK_USER_MCP_TOOL_NAME = "ask_question";
|
|
101476
|
+
var ASK_USER_TOOL_NAME = `${ASK_USER_MCP_SERVER_NAME}.${ASK_USER_MCP_TOOL_NAME}`;
|
|
101477
|
+
var CLAUDE_ASK_USER_TOOL_NAME = `mcp__${ASK_USER_MCP_SERVER_NAME}__${ASK_USER_MCP_TOOL_NAME}`;
|
|
101478
|
+
function isAskUserMcpTool(server, tool) {
|
|
101479
|
+
return server === ASK_USER_MCP_SERVER_NAME && tool === ASK_USER_MCP_TOOL_NAME;
|
|
101480
|
+
}
|
|
101481
|
+
function projectAskUserQuestion(input) {
|
|
101482
|
+
return [
|
|
101483
|
+
{
|
|
101484
|
+
type: "entry",
|
|
101485
|
+
entry: {
|
|
101486
|
+
role: "assistant",
|
|
101487
|
+
kind: "question",
|
|
101488
|
+
turnStatus: "waiting_for_input",
|
|
101489
|
+
content: {
|
|
101490
|
+
parts: [
|
|
101491
|
+
{
|
|
101492
|
+
type: "question",
|
|
101493
|
+
toolCallId: input.id,
|
|
101494
|
+
questions: input.questions
|
|
101495
|
+
}
|
|
101496
|
+
]
|
|
101497
|
+
}
|
|
101498
|
+
}
|
|
101499
|
+
},
|
|
101500
|
+
{
|
|
101501
|
+
type: "ui_message_chunk",
|
|
101502
|
+
chunk: {
|
|
101503
|
+
type: "tool-input-available",
|
|
101504
|
+
toolCallId: input.id,
|
|
101505
|
+
toolName: ASK_USER_TOOL_NAME,
|
|
101506
|
+
input: { questions: input.questions }
|
|
101507
|
+
},
|
|
101508
|
+
turnStatus: "waiting_for_input"
|
|
101509
|
+
}
|
|
101510
|
+
];
|
|
101511
|
+
}
|
|
101512
|
+
function projectAskUserAnswer(answer) {
|
|
101513
|
+
return {
|
|
101514
|
+
type: "ui_message_chunk",
|
|
101515
|
+
chunk: {
|
|
101516
|
+
type: "tool-output-available",
|
|
101517
|
+
toolCallId: answer.toolCallId || UNKNOWN_MESSAGE_ID,
|
|
101518
|
+
output: toJsonValue({
|
|
101519
|
+
answers: answer.answers,
|
|
101520
|
+
...answer.response ? { response: answer.response } : {}
|
|
101521
|
+
})
|
|
101522
|
+
}
|
|
101523
|
+
};
|
|
101524
|
+
}
|
|
101525
|
+
|
|
101526
|
+
// src/commands/agent-bridge/harness/ask-user-server.ts
|
|
101527
|
+
init_src();
|
|
101528
|
+
init_zod();
|
|
101529
|
+
import { randomBytes as randomBytes3, randomUUID } from "crypto";
|
|
101530
|
+
import {
|
|
101531
|
+
createServer as createServer4
|
|
101532
|
+
} from "http";
|
|
101533
|
+
import { Server as McpProtocolServer } from "@modelcontextprotocol/sdk/server/index.js";
|
|
101534
|
+
import { StreamableHTTPServerTransport } from "@modelcontextprotocol/sdk/server/streamableHttp.js";
|
|
101535
|
+
import {
|
|
101536
|
+
CallToolRequestSchema as CallToolRequestSchema2,
|
|
101537
|
+
ListToolsRequestSchema as ListToolsRequestSchema2
|
|
101538
|
+
} from "@modelcontextprotocol/sdk/types.js";
|
|
101539
|
+
var ASK_USER_PROGRESS_INTERVAL_MS = 3e4;
|
|
101540
|
+
var ASK_USER_CALL_DEADLINE_MS = 84e4;
|
|
101541
|
+
var ASK_USER_FALLBACK_MESSAGE = "The question remains pending for the user. Continue this turn; the answer will arrive as a user message.";
|
|
101542
|
+
var AuthoredQuestionSchema = ConversationQuestionSchema.extend({
|
|
101543
|
+
question: external_exports.string().trim().min(1).max(1024),
|
|
101544
|
+
header: external_exports.string().trim().min(1).max(64),
|
|
101545
|
+
options: external_exports.array(
|
|
101546
|
+
external_exports.object({
|
|
101547
|
+
label: external_exports.string().trim().min(1).max(128),
|
|
101548
|
+
description: external_exports.string().trim().max(512)
|
|
101549
|
+
}).strict()
|
|
101550
|
+
).min(2).max(6)
|
|
101551
|
+
}).strict();
|
|
101552
|
+
var AskUserQuestionInputSchema2 = external_exports.object({
|
|
101553
|
+
questions: external_exports.array(AuthoredQuestionSchema).min(1).max(4)
|
|
101554
|
+
}).strict();
|
|
101555
|
+
var AskUserQuestionRegistry = class {
|
|
101556
|
+
pending = /* @__PURE__ */ new Map();
|
|
101557
|
+
deadlineMs;
|
|
101558
|
+
progressIntervalMs;
|
|
101559
|
+
constructor(options = {}) {
|
|
101560
|
+
this.deadlineMs = positiveDuration(
|
|
101561
|
+
options.deadlineMs ?? ASK_USER_CALL_DEADLINE_MS,
|
|
101562
|
+
"ask-user deadline"
|
|
101563
|
+
);
|
|
101564
|
+
this.progressIntervalMs = positiveDuration(
|
|
101565
|
+
options.progressIntervalMs ?? ASK_USER_PROGRESS_INTERVAL_MS,
|
|
101566
|
+
"ask-user progress interval"
|
|
101567
|
+
);
|
|
101568
|
+
}
|
|
101569
|
+
get size() {
|
|
101570
|
+
return this.pending.size;
|
|
101571
|
+
}
|
|
101572
|
+
has(id) {
|
|
101573
|
+
return this.pending.has(id);
|
|
101574
|
+
}
|
|
101575
|
+
park(input) {
|
|
101576
|
+
const { questions } = AskUserQuestionInputSchema2.parse({
|
|
101577
|
+
questions: input.questions
|
|
101578
|
+
});
|
|
101579
|
+
const id = `q_${randomUUID()}`;
|
|
101580
|
+
let resolveWait = () => {
|
|
101581
|
+
};
|
|
101582
|
+
const wait = new Promise((resolve6) => {
|
|
101583
|
+
resolveWait = resolve6;
|
|
101584
|
+
});
|
|
101585
|
+
const progress = setInterval(() => {
|
|
101586
|
+
try {
|
|
101587
|
+
void Promise.resolve(input.onProgress?.()).catch(() => {
|
|
101588
|
+
});
|
|
101589
|
+
} catch {
|
|
101590
|
+
}
|
|
101591
|
+
}, this.progressIntervalMs);
|
|
101592
|
+
const deadline = setTimeout(() => {
|
|
101593
|
+
this.settle(id, {
|
|
101594
|
+
kind: "fallback",
|
|
101595
|
+
message: ASK_USER_FALLBACK_MESSAGE,
|
|
101596
|
+
reason: "deadline"
|
|
101597
|
+
});
|
|
101598
|
+
}, this.deadlineMs);
|
|
101599
|
+
this.pending.set(id, {
|
|
101600
|
+
id,
|
|
101601
|
+
questions,
|
|
101602
|
+
deadline,
|
|
101603
|
+
progress,
|
|
101604
|
+
resolve: resolveWait,
|
|
101605
|
+
onSettled: input.onSettled
|
|
101606
|
+
});
|
|
101607
|
+
return { id, wait };
|
|
101608
|
+
}
|
|
101609
|
+
answer(id, answer) {
|
|
101610
|
+
if (answer.toolCallId !== id) {
|
|
101611
|
+
return false;
|
|
101612
|
+
}
|
|
101613
|
+
return this.settle(id, { kind: "answered", answer });
|
|
101614
|
+
}
|
|
101615
|
+
quarantine(id, reason) {
|
|
101616
|
+
return this.settle(id, {
|
|
101617
|
+
kind: "fallback",
|
|
101618
|
+
message: ASK_USER_FALLBACK_MESSAGE,
|
|
101619
|
+
reason
|
|
101620
|
+
});
|
|
101621
|
+
}
|
|
101622
|
+
quarantineAll(reason) {
|
|
101623
|
+
let settled = 0;
|
|
101624
|
+
for (const id of [...this.pending.keys()]) {
|
|
101625
|
+
if (this.quarantine(id, reason)) {
|
|
101626
|
+
settled += 1;
|
|
101627
|
+
}
|
|
101628
|
+
}
|
|
101629
|
+
return settled;
|
|
101630
|
+
}
|
|
101631
|
+
settle(id, settlement) {
|
|
101632
|
+
const pending = this.pending.get(id);
|
|
101633
|
+
if (!pending || !this.pending.delete(id)) {
|
|
101634
|
+
return false;
|
|
101635
|
+
}
|
|
101636
|
+
clearTimeout(pending.deadline);
|
|
101637
|
+
clearInterval(pending.progress);
|
|
101638
|
+
pending.resolve(settlement);
|
|
101639
|
+
try {
|
|
101640
|
+
pending.onSettled?.(settlement);
|
|
101641
|
+
} catch {
|
|
101642
|
+
}
|
|
101643
|
+
return true;
|
|
101644
|
+
}
|
|
101645
|
+
};
|
|
101646
|
+
var AskUserServer = class {
|
|
101647
|
+
constructor(options) {
|
|
101648
|
+
this.options = options;
|
|
101649
|
+
this.registry = new AskUserQuestionRegistry(options);
|
|
101650
|
+
}
|
|
101651
|
+
options;
|
|
101652
|
+
registry;
|
|
101653
|
+
path = `/mcp/${randomBytes3(24).toString("base64url")}`;
|
|
101654
|
+
capability = randomBytes3(32).toString("base64url");
|
|
101655
|
+
server = null;
|
|
101656
|
+
prepared = null;
|
|
101657
|
+
prepare() {
|
|
101658
|
+
this.prepared ??= this.prepareOnce();
|
|
101659
|
+
return this.prepared;
|
|
101660
|
+
}
|
|
101661
|
+
answer(answer) {
|
|
101662
|
+
return this.registry.answer(answer.toolCallId, answer);
|
|
101663
|
+
}
|
|
101664
|
+
quarantineAll(reason) {
|
|
101665
|
+
return this.registry.quarantineAll(reason);
|
|
101666
|
+
}
|
|
101667
|
+
close() {
|
|
101668
|
+
this.quarantineAll("harness shutdown");
|
|
101669
|
+
this.server?.close();
|
|
101670
|
+
this.server = null;
|
|
101671
|
+
}
|
|
101672
|
+
async prepareOnce() {
|
|
101673
|
+
const server = createServer4((request, response) => {
|
|
101674
|
+
void this.handleRequest(request, response);
|
|
101675
|
+
});
|
|
101676
|
+
this.server = server;
|
|
101677
|
+
await new Promise((resolve6, reject) => {
|
|
101678
|
+
server.once("error", reject);
|
|
101679
|
+
server.listen(0, "127.0.0.1", () => {
|
|
101680
|
+
server.off("error", reject);
|
|
101681
|
+
resolve6();
|
|
101682
|
+
});
|
|
101683
|
+
});
|
|
101684
|
+
const address = server.address();
|
|
101685
|
+
if (!address || typeof address === "string") {
|
|
101686
|
+
server.close();
|
|
101687
|
+
throw new Error("ask-user MCP server did not receive a TCP address");
|
|
101688
|
+
}
|
|
101689
|
+
server.unref();
|
|
101690
|
+
return {
|
|
101691
|
+
url: `http://127.0.0.1:${address.port}${this.path}`,
|
|
101692
|
+
headers: {
|
|
101693
|
+
[AGENT_BRIDGE_MCP_CAPABILITY_HEADER]: this.capability
|
|
101694
|
+
}
|
|
101695
|
+
};
|
|
101696
|
+
}
|
|
101697
|
+
async handleRequest(request, response) {
|
|
101698
|
+
if (request.url !== this.path || request.method !== "POST") {
|
|
101699
|
+
response.writeHead(request.url === this.path ? 405 : 404).end();
|
|
101700
|
+
return;
|
|
101701
|
+
}
|
|
101702
|
+
if (!requestHasMcpCapability(request.headers, this.capability)) {
|
|
101703
|
+
response.writeHead(401, { "content-type": "application/json" }).end(JSON.stringify({ error: "Invalid ask-user MCP capability" }));
|
|
101704
|
+
return;
|
|
101705
|
+
}
|
|
101706
|
+
try {
|
|
101707
|
+
await this.handleMcpRequest(request, response);
|
|
101708
|
+
} catch (error51) {
|
|
101709
|
+
this.options.writeOutput?.(
|
|
101710
|
+
`agent_bridge_ask_user_http_error error=${errorMessage2(error51)}`
|
|
101711
|
+
);
|
|
101712
|
+
if (!response.headersSent) {
|
|
101713
|
+
response.writeHead(500, { "content-type": "application/json" });
|
|
101714
|
+
response.end(
|
|
101715
|
+
JSON.stringify({
|
|
101716
|
+
jsonrpc: "2.0",
|
|
101717
|
+
id: null,
|
|
101718
|
+
error: { code: -32603, message: "Ask-user server failed" }
|
|
101719
|
+
})
|
|
101720
|
+
);
|
|
101721
|
+
}
|
|
101722
|
+
}
|
|
101723
|
+
}
|
|
101724
|
+
async handleMcpRequest(request, response) {
|
|
101725
|
+
const body = await readJsonRequest(request);
|
|
101726
|
+
this.options.writeOutput?.(
|
|
101727
|
+
`agent_bridge_ask_user_mcp_request method=${typeof body.method === "string" ? body.method : "unknown"}`
|
|
101728
|
+
);
|
|
101729
|
+
const server = this.createMcpServer();
|
|
101730
|
+
const transport = new StreamableHTTPServerTransport({
|
|
101731
|
+
sessionIdGenerator: void 0,
|
|
101732
|
+
// Codex 0.145.0 requires ordinary initialize/list responses as JSON. A
|
|
101733
|
+
// parked tool call keeps SSE enabled so progress notifications can flow
|
|
101734
|
+
// over the held response without extending the hard client deadline.
|
|
101735
|
+
enableJsonResponse: body.method !== "tools/call"
|
|
101736
|
+
});
|
|
101737
|
+
response.once("close", () => {
|
|
101738
|
+
void transport.close();
|
|
101739
|
+
void server.close();
|
|
101740
|
+
});
|
|
101741
|
+
await server.connect(transport);
|
|
101742
|
+
await transport.handleRequest(request, response, body);
|
|
101743
|
+
}
|
|
101744
|
+
createMcpServer() {
|
|
101745
|
+
const server = new McpProtocolServer(
|
|
101746
|
+
{ name: "auto-ask-user", version: "1.0.0" },
|
|
101747
|
+
{ capabilities: { tools: {} } }
|
|
101748
|
+
);
|
|
101749
|
+
server.setRequestHandler(ListToolsRequestSchema2, () => ({
|
|
101750
|
+
tools: [
|
|
101751
|
+
{
|
|
101752
|
+
name: ASK_USER_MCP_TOOL_NAME,
|
|
101753
|
+
title: ASK_USER_TOOL_NAME,
|
|
101754
|
+
description: "Ask the user one to four blocking questions and wait for their answer.",
|
|
101755
|
+
inputSchema: external_exports.toJSONSchema(AskUserQuestionInputSchema2)
|
|
101756
|
+
}
|
|
101757
|
+
]
|
|
101758
|
+
}));
|
|
101759
|
+
server.setRequestHandler(
|
|
101760
|
+
CallToolRequestSchema2,
|
|
101761
|
+
async (request, extra) => {
|
|
101762
|
+
if (request.params.name !== ASK_USER_MCP_TOOL_NAME) {
|
|
101763
|
+
throw new Error(`Unknown ask-user tool: ${request.params.name}`);
|
|
101764
|
+
}
|
|
101765
|
+
const { questions } = AskUserQuestionInputSchema2.parse(
|
|
101766
|
+
request.params.arguments
|
|
101767
|
+
);
|
|
101768
|
+
let questionId = "";
|
|
101769
|
+
const parked = this.registry.park({
|
|
101770
|
+
questions,
|
|
101771
|
+
onProgress: async () => {
|
|
101772
|
+
const progressToken = extra._meta?.progressToken;
|
|
101773
|
+
if (progressToken === void 0) {
|
|
101774
|
+
return;
|
|
101775
|
+
}
|
|
101776
|
+
await extra.sendNotification({
|
|
101777
|
+
method: "notifications/progress",
|
|
101778
|
+
params: {
|
|
101779
|
+
progressToken,
|
|
101780
|
+
progress: Date.now(),
|
|
101781
|
+
message: "Waiting for the user to answer"
|
|
101782
|
+
}
|
|
101783
|
+
});
|
|
101784
|
+
},
|
|
101785
|
+
onSettled: (settlement2) => {
|
|
101786
|
+
this.options.onQuestionSettled?.({ id: questionId, settlement: settlement2 });
|
|
101787
|
+
}
|
|
101788
|
+
});
|
|
101789
|
+
questionId = parked.id;
|
|
101790
|
+
try {
|
|
101791
|
+
await this.options.onQuestionPending({
|
|
101792
|
+
id: parked.id,
|
|
101793
|
+
questions
|
|
101794
|
+
});
|
|
101795
|
+
} catch (error51) {
|
|
101796
|
+
this.registry.quarantine(parked.id, "question projection failed");
|
|
101797
|
+
throw error51;
|
|
101798
|
+
}
|
|
101799
|
+
const settlement = await parked.wait;
|
|
101800
|
+
return settlementResult(settlement);
|
|
101801
|
+
}
|
|
101802
|
+
);
|
|
101803
|
+
return server;
|
|
101804
|
+
}
|
|
101805
|
+
};
|
|
101806
|
+
function settlementResult(settlement) {
|
|
101807
|
+
if (settlement.kind === "fallback") {
|
|
101808
|
+
return {
|
|
101809
|
+
content: [{ type: "text", text: settlement.message }]
|
|
101810
|
+
};
|
|
101811
|
+
}
|
|
101812
|
+
const answer = settlement.answer;
|
|
101813
|
+
const lines = Object.entries(answer.answers).map(
|
|
101814
|
+
([question, value]) => `- ${question}: ${value}`
|
|
101815
|
+
);
|
|
101816
|
+
return {
|
|
101817
|
+
content: [
|
|
101818
|
+
{
|
|
101819
|
+
type: "text",
|
|
101820
|
+
text: [
|
|
101821
|
+
"The user answered your questions:",
|
|
101822
|
+
...lines,
|
|
101823
|
+
...answer.response ? [`The user also responded: ${answer.response}`] : []
|
|
101824
|
+
].join("\n")
|
|
101825
|
+
}
|
|
101826
|
+
]
|
|
101827
|
+
};
|
|
101828
|
+
}
|
|
101829
|
+
function positiveDuration(value, label) {
|
|
101830
|
+
if (!Number.isSafeInteger(value) || value < 1) {
|
|
101831
|
+
throw new Error(`${label} must be a positive safe integer`);
|
|
101832
|
+
}
|
|
101833
|
+
return value;
|
|
101834
|
+
}
|
|
101835
|
+
function errorMessage2(error51) {
|
|
101836
|
+
return error51 instanceof Error ? error51.message : String(error51);
|
|
101837
|
+
}
|
|
101838
|
+
async function readJsonRequest(request) {
|
|
101839
|
+
const chunks = [];
|
|
101840
|
+
for await (const chunk of request) {
|
|
101841
|
+
chunks.push(Buffer.from(chunk));
|
|
101842
|
+
}
|
|
101843
|
+
const parsed = JSON.parse(Buffer.concat(chunks).toString("utf8"));
|
|
101844
|
+
if (!parsed || typeof parsed !== "object" || Array.isArray(parsed)) {
|
|
101845
|
+
throw new Error("ask-user MCP request body must be a JSON object");
|
|
101846
|
+
}
|
|
101847
|
+
return parsed;
|
|
101848
|
+
}
|
|
101849
|
+
|
|
101465
101850
|
// src/commands/agent-bridge/harness/liveness-ticker.ts
|
|
101466
101851
|
var RUNTIME_LIVENESS_INTERVAL_MS = 2e4;
|
|
101467
101852
|
function startRuntimeLivenessTicker(input) {
|
|
@@ -102591,7 +102976,7 @@ function isTerminalUiMessageChunk(chunk) {
|
|
|
102591
102976
|
function legacyToolEntries(chunk) {
|
|
102592
102977
|
switch (chunk.type) {
|
|
102593
102978
|
case "tool-input-available":
|
|
102594
|
-
if (chunk.toolName === ASK_USER_QUESTION_TOOL_NAME) {
|
|
102979
|
+
if (chunk.toolName === ASK_USER_QUESTION_TOOL_NAME || chunk.toolName === ASK_USER_TOOL_NAME) {
|
|
102595
102980
|
return [];
|
|
102596
102981
|
}
|
|
102597
102982
|
return [
|
|
@@ -102915,6 +103300,111 @@ function jsonRecordString2(value, key) {
|
|
|
102915
103300
|
return typeof field === "string" ? field : void 0;
|
|
102916
103301
|
}
|
|
102917
103302
|
|
|
103303
|
+
// src/commands/agent-bridge/harness/mcp-timeout.ts
|
|
103304
|
+
var HARNESS_MCP_TOOL_TIMEOUT_SECONDS = 900;
|
|
103305
|
+
var MAX_HARNESS_MCP_TOOL_TIMEOUT_SECONDS = 3600;
|
|
103306
|
+
function validatedMcpToolTimeoutSeconds(value) {
|
|
103307
|
+
if (!Number.isSafeInteger(value) || value < 1 || value > MAX_HARNESS_MCP_TOOL_TIMEOUT_SECONDS) {
|
|
103308
|
+
throw new Error(
|
|
103309
|
+
`MCP tool timeout must be a safe integer from 1 to ${MAX_HARNESS_MCP_TOOL_TIMEOUT_SECONDS} seconds`
|
|
103310
|
+
);
|
|
103311
|
+
}
|
|
103312
|
+
return value;
|
|
103313
|
+
}
|
|
103314
|
+
function validatedMcpToolTimeoutMilliseconds(value) {
|
|
103315
|
+
return validatedMcpToolTimeoutSeconds(value) * 1e3;
|
|
103316
|
+
}
|
|
103317
|
+
|
|
103318
|
+
// src/commands/agent-bridge/harness/claude-code/options.ts
|
|
103319
|
+
var CLAUDE_AGENT_SDK_CLIENT_APP = "auto-agent-bridge";
|
|
103320
|
+
var CLAUDE_RUNTIME_PROCESS_ENV_KEYS = ["PATH", "HOME"];
|
|
103321
|
+
var CLAUDE_CODE_EXECUTABLE_PATH = "/usr/local/bin/claude";
|
|
103322
|
+
var CLAUDE_CODE_SHELL_PATH = "/bin/bash";
|
|
103323
|
+
var CLAUDE_CODE_DEFAULT_MODEL = "claude-opus-4-8";
|
|
103324
|
+
function claudeAgentOptions(config2, input = {}) {
|
|
103325
|
+
return {
|
|
103326
|
+
...config2.cwd ? { cwd: config2.cwd } : {},
|
|
103327
|
+
...input.resume ? { resume: input.resume } : {},
|
|
103328
|
+
env: claudeProcessEnv(
|
|
103329
|
+
config2.env,
|
|
103330
|
+
input.clientApp ?? CLAUDE_AGENT_SDK_CLIENT_APP
|
|
103331
|
+
),
|
|
103332
|
+
includePartialMessages: true,
|
|
103333
|
+
thinking: { type: "adaptive", display: "summarized" },
|
|
103334
|
+
settings: { showThinkingSummaries: true },
|
|
103335
|
+
model: config2.model?.id ?? CLAUDE_CODE_DEFAULT_MODEL,
|
|
103336
|
+
...config2.reasoningEffort ? { effort: config2.reasoningEffort } : {},
|
|
103337
|
+
permissionMode: "bypassPermissions",
|
|
103338
|
+
allowDangerouslySkipPermissions: true,
|
|
103339
|
+
pathToClaudeCodeExecutable: claudeCodeExecutablePath(),
|
|
103340
|
+
...input.mcpServers ?? config2.mcpServers ? {
|
|
103341
|
+
mcpServers: input.mcpServers ?? config2.mcpServers,
|
|
103342
|
+
strictMcpConfig: true
|
|
103343
|
+
} : {},
|
|
103344
|
+
systemPrompt: {
|
|
103345
|
+
type: "preset",
|
|
103346
|
+
preset: "claude_code",
|
|
103347
|
+
...config2.systemPromptAppend ? { append: config2.systemPromptAppend } : {}
|
|
103348
|
+
},
|
|
103349
|
+
settingSources: [],
|
|
103350
|
+
tools: {
|
|
103351
|
+
type: "preset",
|
|
103352
|
+
preset: "claude_code"
|
|
103353
|
+
},
|
|
103354
|
+
stderr: input.onStderrChunk ?? (() => {
|
|
103355
|
+
})
|
|
103356
|
+
};
|
|
103357
|
+
}
|
|
103358
|
+
function withClaudeAskUserMcpServer(mcpServers, url2, headers) {
|
|
103359
|
+
if (mcpServers?.[ASK_USER_MCP_SERVER_NAME]) {
|
|
103360
|
+
throw new Error(
|
|
103361
|
+
`MCP server name ${ASK_USER_MCP_SERVER_NAME} is reserved by the harness`
|
|
103362
|
+
);
|
|
103363
|
+
}
|
|
103364
|
+
return {
|
|
103365
|
+
...mcpServers,
|
|
103366
|
+
[ASK_USER_MCP_SERVER_NAME]: {
|
|
103367
|
+
type: "http",
|
|
103368
|
+
url: url2,
|
|
103369
|
+
headers,
|
|
103370
|
+
timeout: validatedMcpToolTimeoutMilliseconds(
|
|
103371
|
+
HARNESS_MCP_TOOL_TIMEOUT_SECONDS
|
|
103372
|
+
)
|
|
103373
|
+
}
|
|
103374
|
+
};
|
|
103375
|
+
}
|
|
103376
|
+
function claudeProcessEnv(env, clientApp) {
|
|
103377
|
+
const runtimeEnv = runtimeProcessEnv();
|
|
103378
|
+
return {
|
|
103379
|
+
// Claude Code only needs ambient shell basics from the bridge process.
|
|
103380
|
+
// Dynamic Claude/MCP/session secrets arrive through encrypted bootstrap env.
|
|
103381
|
+
...runtimeEnv,
|
|
103382
|
+
...env,
|
|
103383
|
+
// Claude Code auto-detects a shell when this is absent. Hosted sandboxes run
|
|
103384
|
+
// Bash tool commands, so pin the shell snapshot source to bash instead of
|
|
103385
|
+
// letting zsh profile functions leak into bash snapshots and inherit user
|
|
103386
|
+
// strict-mode options such as `set -u`.
|
|
103387
|
+
CLAUDE_CODE_SHELL: CLAUDE_CODE_SHELL_PATH,
|
|
103388
|
+
CLAUDE_AGENT_SDK_CLIENT_APP: clientApp
|
|
103389
|
+
};
|
|
103390
|
+
}
|
|
103391
|
+
function runtimeProcessEnv() {
|
|
103392
|
+
const selected = {};
|
|
103393
|
+
for (const key of CLAUDE_RUNTIME_PROCESS_ENV_KEYS) {
|
|
103394
|
+
const value = process.env[key];
|
|
103395
|
+
if (value !== void 0) {
|
|
103396
|
+
selected[key] = value;
|
|
103397
|
+
}
|
|
103398
|
+
}
|
|
103399
|
+
return selected;
|
|
103400
|
+
}
|
|
103401
|
+
function claudeCodeExecutablePath() {
|
|
103402
|
+
if (process.env.AUTO_AGENT_BRIDGE_TEST_CLAUDE_COMMAND === "1" && process.env.AUTO_CLAUDE_CODE_COMMAND?.trim()) {
|
|
103403
|
+
return process.env.AUTO_CLAUDE_CODE_COMMAND.trim();
|
|
103404
|
+
}
|
|
103405
|
+
return CLAUDE_CODE_EXECUTABLE_PATH;
|
|
103406
|
+
}
|
|
103407
|
+
|
|
102918
103408
|
// src/commands/agent-bridge/harness/claude-code/projector.ts
|
|
102919
103409
|
init_src();
|
|
102920
103410
|
var ClaudeCodeProjector = class {
|
|
@@ -102933,6 +103423,7 @@ var ClaudeCodeProjector = class {
|
|
|
102933
103423
|
activeResponseMessageId = null;
|
|
102934
103424
|
activeParts = /* @__PURE__ */ new Map();
|
|
102935
103425
|
activeToolInputs = /* @__PURE__ */ new Map();
|
|
103426
|
+
suppressedAskUserToolCallIds = /* @__PURE__ */ new Set();
|
|
102936
103427
|
streamedMessageIds = /* @__PURE__ */ new Set();
|
|
102937
103428
|
// The SDK's "[Request interrupted by user]" transcript marker was seen since
|
|
102938
103429
|
// the last terminal result: the very next diagnostic-only
|
|
@@ -102952,6 +103443,7 @@ var ClaudeCodeProjector = class {
|
|
|
102952
103443
|
bridge: context.bridgeInterruptSettling === true
|
|
102953
103444
|
};
|
|
102954
103445
|
const parsed = parseClaudeCodeStreamRecord(message);
|
|
103446
|
+
parsed.projections = this.suppressAskUserProjections(parsed.projections);
|
|
102955
103447
|
const snapshotMessageId = assistantSnapshotMessageId(message);
|
|
102956
103448
|
const suppressStreamed = snapshotMessageId !== null && this.streamedMessageIds.has(snapshotMessageId);
|
|
102957
103449
|
if (message.type === "assistant" && !suppressStreamed) {
|
|
@@ -102984,6 +103476,7 @@ var ClaudeCodeProjector = class {
|
|
|
102984
103476
|
);
|
|
102985
103477
|
}
|
|
102986
103478
|
outputs.push(projectClaudeCodeResult(parsed.result, { interrupted }));
|
|
103479
|
+
this.suppressedAskUserToolCallIds.clear();
|
|
102987
103480
|
this.interruptMarkerSeen = false;
|
|
102988
103481
|
}
|
|
102989
103482
|
return outputs;
|
|
@@ -103068,6 +103561,11 @@ var ClaudeCodeProjector = class {
|
|
|
103068
103561
|
return [uiChunk({ type: `${type}-end`, id })];
|
|
103069
103562
|
}
|
|
103070
103563
|
startToolInput(message) {
|
|
103564
|
+
const askUserToolCallId = askUserMcpToolCallId(message);
|
|
103565
|
+
if (askUserToolCallId) {
|
|
103566
|
+
this.suppressedAskUserToolCallIds.add(askUserToolCallId);
|
|
103567
|
+
return [];
|
|
103568
|
+
}
|
|
103071
103569
|
const started = toolInputStartFromEvent(message);
|
|
103072
103570
|
if (!started) {
|
|
103073
103571
|
return [];
|
|
@@ -103086,6 +103584,32 @@ var ClaudeCodeProjector = class {
|
|
|
103086
103584
|
})
|
|
103087
103585
|
];
|
|
103088
103586
|
}
|
|
103587
|
+
suppressAskUserProjections(projections) {
|
|
103588
|
+
return projections.flatMap((projection) => {
|
|
103589
|
+
if (projection.kind === "tool_call") {
|
|
103590
|
+
const askUserParts = projection.content.parts.filter(
|
|
103591
|
+
(part) => part.type === "tool_call" && (part.name === ASK_USER_TOOL_NAME || part.name === CLAUDE_ASK_USER_TOOL_NAME)
|
|
103592
|
+
);
|
|
103593
|
+
for (const part of askUserParts) {
|
|
103594
|
+
if (part.type === "tool_call" && part.toolCallId) {
|
|
103595
|
+
this.suppressedAskUserToolCallIds.add(part.toolCallId);
|
|
103596
|
+
}
|
|
103597
|
+
}
|
|
103598
|
+
if (askUserParts.length > 0) {
|
|
103599
|
+
return [];
|
|
103600
|
+
}
|
|
103601
|
+
}
|
|
103602
|
+
if (projection.kind === "tool_result") {
|
|
103603
|
+
const suppressed = projection.content.parts.some(
|
|
103604
|
+
(part) => part.type === "tool_result" && part.toolUseId !== null && this.suppressedAskUserToolCallIds.has(part.toolUseId)
|
|
103605
|
+
);
|
|
103606
|
+
if (suppressed) {
|
|
103607
|
+
return [];
|
|
103608
|
+
}
|
|
103609
|
+
}
|
|
103610
|
+
return [projection];
|
|
103611
|
+
});
|
|
103612
|
+
}
|
|
103089
103613
|
finishActiveToolInput(index) {
|
|
103090
103614
|
const active = this.activeToolInputs.get(index);
|
|
103091
103615
|
if (!active) {
|
|
@@ -103282,6 +103806,17 @@ function toolInputStartFromEvent(message) {
|
|
|
103282
103806
|
input: contentBlock.input
|
|
103283
103807
|
};
|
|
103284
103808
|
}
|
|
103809
|
+
function askUserMcpToolCallId(message) {
|
|
103810
|
+
const event = message.event;
|
|
103811
|
+
if (event.type !== "content_block_start") {
|
|
103812
|
+
return null;
|
|
103813
|
+
}
|
|
103814
|
+
const block = event.content_block;
|
|
103815
|
+
if (block.type !== "mcp_tool_use" || typeof block.id !== "string" || typeof block.server_name !== "string" || typeof block.name !== "string" || !isAskUserMcpTool(block.server_name, block.name)) {
|
|
103816
|
+
return null;
|
|
103817
|
+
}
|
|
103818
|
+
return block.id;
|
|
103819
|
+
}
|
|
103285
103820
|
function toolInputDeltaFromDelta(delta) {
|
|
103286
103821
|
if (delta.type !== "input_json_delta") {
|
|
103287
103822
|
return null;
|
|
@@ -103802,78 +104337,6 @@ function serverStatusList(servers, context) {
|
|
|
103802
104337
|
return reported.map((server) => `${server.name}:${server.status}`).join(",");
|
|
103803
104338
|
}
|
|
103804
104339
|
|
|
103805
|
-
// src/commands/agent-bridge/harness/claude-code/options.ts
|
|
103806
|
-
var CLAUDE_AGENT_SDK_CLIENT_APP = "auto-agent-bridge";
|
|
103807
|
-
var CLAUDE_RUNTIME_PROCESS_ENV_KEYS = ["PATH", "HOME"];
|
|
103808
|
-
var CLAUDE_CODE_EXECUTABLE_PATH = "/usr/local/bin/claude";
|
|
103809
|
-
var CLAUDE_CODE_SHELL_PATH = "/bin/bash";
|
|
103810
|
-
var CLAUDE_CODE_DEFAULT_MODEL = "claude-opus-4-8";
|
|
103811
|
-
function claudeAgentOptions(config2, input = {}) {
|
|
103812
|
-
return {
|
|
103813
|
-
...config2.cwd ? { cwd: config2.cwd } : {},
|
|
103814
|
-
...input.resume ? { resume: input.resume } : {},
|
|
103815
|
-
env: claudeProcessEnv(
|
|
103816
|
-
config2.env,
|
|
103817
|
-
input.clientApp ?? CLAUDE_AGENT_SDK_CLIENT_APP
|
|
103818
|
-
),
|
|
103819
|
-
includePartialMessages: true,
|
|
103820
|
-
thinking: { type: "adaptive", display: "summarized" },
|
|
103821
|
-
settings: { showThinkingSummaries: true },
|
|
103822
|
-
model: config2.model?.id ?? CLAUDE_CODE_DEFAULT_MODEL,
|
|
103823
|
-
...config2.reasoningEffort ? { effort: config2.reasoningEffort } : {},
|
|
103824
|
-
permissionMode: "bypassPermissions",
|
|
103825
|
-
allowDangerouslySkipPermissions: true,
|
|
103826
|
-
pathToClaudeCodeExecutable: claudeCodeExecutablePath(),
|
|
103827
|
-
...input.mcpServers ?? config2.mcpServers ? {
|
|
103828
|
-
mcpServers: input.mcpServers ?? config2.mcpServers,
|
|
103829
|
-
strictMcpConfig: true
|
|
103830
|
-
} : {},
|
|
103831
|
-
systemPrompt: {
|
|
103832
|
-
type: "preset",
|
|
103833
|
-
preset: "claude_code",
|
|
103834
|
-
...config2.systemPromptAppend ? { append: config2.systemPromptAppend } : {}
|
|
103835
|
-
},
|
|
103836
|
-
settingSources: [],
|
|
103837
|
-
tools: {
|
|
103838
|
-
type: "preset",
|
|
103839
|
-
preset: "claude_code"
|
|
103840
|
-
},
|
|
103841
|
-
stderr: input.onStderrChunk ?? (() => {
|
|
103842
|
-
})
|
|
103843
|
-
};
|
|
103844
|
-
}
|
|
103845
|
-
function claudeProcessEnv(env, clientApp) {
|
|
103846
|
-
const runtimeEnv = runtimeProcessEnv();
|
|
103847
|
-
return {
|
|
103848
|
-
// Claude Code only needs ambient shell basics from the bridge process.
|
|
103849
|
-
// Dynamic Claude/MCP/session secrets arrive through encrypted bootstrap env.
|
|
103850
|
-
...runtimeEnv,
|
|
103851
|
-
...env,
|
|
103852
|
-
// Claude Code auto-detects a shell when this is absent. Hosted sandboxes run
|
|
103853
|
-
// Bash tool commands, so pin the shell snapshot source to bash instead of
|
|
103854
|
-
// letting zsh profile functions leak into bash snapshots and inherit user
|
|
103855
|
-
// strict-mode options such as `set -u`.
|
|
103856
|
-
CLAUDE_CODE_SHELL: CLAUDE_CODE_SHELL_PATH,
|
|
103857
|
-
CLAUDE_AGENT_SDK_CLIENT_APP: clientApp
|
|
103858
|
-
};
|
|
103859
|
-
}
|
|
103860
|
-
function runtimeProcessEnv() {
|
|
103861
|
-
const selected = {};
|
|
103862
|
-
for (const key of CLAUDE_RUNTIME_PROCESS_ENV_KEYS) {
|
|
103863
|
-
const value = process.env[key];
|
|
103864
|
-
if (value !== void 0) {
|
|
103865
|
-
selected[key] = value;
|
|
103866
|
-
}
|
|
103867
|
-
}
|
|
103868
|
-
return selected;
|
|
103869
|
-
}
|
|
103870
|
-
function claudeCodeExecutablePath() {
|
|
103871
|
-
if (process.env.AUTO_AGENT_BRIDGE_TEST_CLAUDE_COMMAND === "1" && process.env.AUTO_CLAUDE_CODE_COMMAND?.trim()) {
|
|
103872
|
-
return process.env.AUTO_CLAUDE_CODE_COMMAND.trim();
|
|
103873
|
-
}
|
|
103874
|
-
return CLAUDE_CODE_EXECUTABLE_PATH;
|
|
103875
|
-
}
|
|
103876
|
-
|
|
103877
104340
|
// src/commands/agent-bridge/harness/claude-code/stderr.ts
|
|
103878
104341
|
var STDERR_LINE_MAX_CHARS = 400;
|
|
103879
104342
|
var STDERR_FORWARD_MAX_LINES = 200;
|
|
@@ -105049,6 +105512,10 @@ var ClaudeCodeCommandHandler = class {
|
|
|
105049
105512
|
mcpServers: input.claude.mcpServers,
|
|
105050
105513
|
writeOutput: input.writeOutput
|
|
105051
105514
|
});
|
|
105515
|
+
this.askUserServer = new AskUserServer({
|
|
105516
|
+
onQuestionPending: (question) => this.handleAskUserQuestion(question),
|
|
105517
|
+
writeOutput: input.writeOutput
|
|
105518
|
+
});
|
|
105052
105519
|
this.outputBuffer = new AgentBridgeOutputBuffer(input);
|
|
105053
105520
|
this.projector = new ClaudeCodeProjector({
|
|
105054
105521
|
writeOutput: input.writeOutput
|
|
@@ -105061,6 +105528,7 @@ var ClaudeCodeCommandHandler = class {
|
|
|
105061
105528
|
claudeConfig;
|
|
105062
105529
|
claudeMcpServers;
|
|
105063
105530
|
autoMcpShim;
|
|
105531
|
+
askUserServer;
|
|
105064
105532
|
// Selection-change restarts happen in-process, so prefer the live SDK id even
|
|
105065
105533
|
// when the file resume store is stale or temporarily unreadable.
|
|
105066
105534
|
lastObservedAgentId = null;
|
|
@@ -105096,7 +105564,13 @@ var ClaudeCodeCommandHandler = class {
|
|
|
105096
105564
|
return this.outputBuffer.pendingOutputStats();
|
|
105097
105565
|
}
|
|
105098
105566
|
async prepare() {
|
|
105099
|
-
|
|
105567
|
+
const mcpServers = await this.autoMcpShim.prepareClaude();
|
|
105568
|
+
const askUserEndpoint = await this.askUserServer.prepare();
|
|
105569
|
+
this.claudeMcpServers = withClaudeAskUserMcpServer(
|
|
105570
|
+
mcpServers,
|
|
105571
|
+
askUserEndpoint.url,
|
|
105572
|
+
askUserEndpoint.headers
|
|
105573
|
+
);
|
|
105100
105574
|
await this.ensureAgentSession().prepare();
|
|
105101
105575
|
}
|
|
105102
105576
|
shutdown() {
|
|
@@ -105105,6 +105579,7 @@ var ClaudeCodeCommandHandler = class {
|
|
|
105105
105579
|
this.agentSession?.close();
|
|
105106
105580
|
this.agentSession = null;
|
|
105107
105581
|
this.autoMcpShim.close();
|
|
105582
|
+
this.askUserServer.close();
|
|
105108
105583
|
this.settlePendingQuestions("Runtime is shutting down");
|
|
105109
105584
|
}
|
|
105110
105585
|
async handleCommand(rawDelivery) {
|
|
@@ -105164,6 +105639,7 @@ var ClaudeCodeCommandHandler = class {
|
|
|
105164
105639
|
}
|
|
105165
105640
|
if (delivery.kind === "interrupt") {
|
|
105166
105641
|
this.injectedCommands.add(delivery.commandId);
|
|
105642
|
+
this.askUserServer.quarantineAll("turn interrupted");
|
|
105167
105643
|
await this.agentSession?.interruptActiveTurn();
|
|
105168
105644
|
this.input.runtimeLogger?.info(
|
|
105169
105645
|
"agent_bridge_claude_command_interrupt_ready",
|
|
@@ -105372,6 +105848,17 @@ var ClaudeCodeCommandHandler = class {
|
|
|
105372
105848
|
);
|
|
105373
105849
|
return;
|
|
105374
105850
|
}
|
|
105851
|
+
if (this.askUserServer.answer(answer)) {
|
|
105852
|
+
this.agentSession?.noteActiveTurnCommand(delivery.commandId);
|
|
105853
|
+
await this.emitRequiredBridgeOutput(
|
|
105854
|
+
activeContext,
|
|
105855
|
+
projectAskUserAnswer(answer)
|
|
105856
|
+
);
|
|
105857
|
+
this.input.writeOutput?.(
|
|
105858
|
+
`agent_bridge_question_answered tool_use_id=${answer.toolCallId}`
|
|
105859
|
+
);
|
|
105860
|
+
return;
|
|
105861
|
+
}
|
|
105375
105862
|
const message = answerFallbackMessage(answer);
|
|
105376
105863
|
await this.emitRequiredBridgeOutput(activeContext, {
|
|
105377
105864
|
type: "entry",
|
|
@@ -105402,11 +105889,28 @@ var ClaudeCodeCommandHandler = class {
|
|
|
105402
105889
|
}
|
|
105403
105890
|
this.pendingQuestions.clear();
|
|
105404
105891
|
}
|
|
105892
|
+
async handleAskUserQuestion(input) {
|
|
105893
|
+
const activeContext = this.context;
|
|
105894
|
+
if (!activeContext) {
|
|
105895
|
+
throw new Error(
|
|
105896
|
+
"Cannot publish an ask-user question without bridge context"
|
|
105897
|
+
);
|
|
105898
|
+
}
|
|
105899
|
+
this.input.writeOutput?.(
|
|
105900
|
+
`agent_bridge_question_pending tool_use_id=${input.id}`
|
|
105901
|
+
);
|
|
105902
|
+
for (const projection of projectAskUserQuestion(input)) {
|
|
105903
|
+
await this.emitRequiredBridgeOutput(activeContext, projection);
|
|
105904
|
+
}
|
|
105905
|
+
}
|
|
105405
105906
|
// Permission callback for the Claude Agent SDK session. The sessions with
|
|
105406
105907
|
// bypassPermissions, so regular tools are auto-approved and only the
|
|
105407
105908
|
// AskUserQuestion tool reaches this callback for a real decision: it parks
|
|
105408
105909
|
// the SDK on a promise that an `answer` bridge command later resolves.
|
|
105409
105910
|
canUseTool = (toolName, toolInput, options) => {
|
|
105911
|
+
if (toolName === CLAUDE_ASK_USER_TOOL_NAME) {
|
|
105912
|
+
return Promise.resolve({ behavior: "allow", updatedInput: toolInput });
|
|
105913
|
+
}
|
|
105410
105914
|
if (toolName !== ASK_USER_QUESTION_TOOL_NAME) {
|
|
105411
105915
|
return Promise.resolve({ behavior: "allow", updatedInput: toolInput });
|
|
105412
105916
|
}
|
|
@@ -105485,6 +105989,9 @@ var ClaudeCodeCommandHandler = class {
|
|
|
105485
105989
|
}
|
|
105486
105990
|
this.persistAgentId(activeContext, message);
|
|
105487
105991
|
this.trackReadState(activeContext, message);
|
|
105992
|
+
if (message.type === "result") {
|
|
105993
|
+
this.askUserServer.quarantineAll("turn ended");
|
|
105994
|
+
}
|
|
105488
105995
|
let projections;
|
|
105489
105996
|
try {
|
|
105490
105997
|
projections = this.projector.project(message, {
|
|
@@ -105504,6 +106011,7 @@ var ClaudeCodeCommandHandler = class {
|
|
|
105504
106011
|
}
|
|
105505
106012
|
}
|
|
105506
106013
|
async handleAgentError(error51) {
|
|
106014
|
+
this.askUserServer.quarantineAll("harness session failed");
|
|
105507
106015
|
this.input.writeOutput?.(
|
|
105508
106016
|
`agent_bridge_claude_sdk_failed error=${error51 instanceof Error ? error51.message : String(error51)}`
|
|
105509
106017
|
);
|
|
@@ -105623,6 +106131,7 @@ var ClaudeCodeCommandHandler = class {
|
|
|
105623
106131
|
onMessage: (message, meta3) => this.handleAgentMessage(message, meta3),
|
|
105624
106132
|
onError: (error51) => this.handleAgentError(error51),
|
|
105625
106133
|
onExit: () => {
|
|
106134
|
+
this.askUserServer.quarantineAll("harness child exited");
|
|
105626
106135
|
if (this.agentSession === session) {
|
|
105627
106136
|
this.agentSession = null;
|
|
105628
106137
|
}
|
|
@@ -105651,6 +106160,7 @@ var ClaudeCodeCommandHandler = class {
|
|
|
105651
106160
|
this.requireResumeForNextAgentSession = this.lastObservedAgentId !== null;
|
|
105652
106161
|
this.agentSession?.close();
|
|
105653
106162
|
this.agentSession = null;
|
|
106163
|
+
this.askUserServer.quarantineAll("harness session restarted");
|
|
105654
106164
|
this.settlePendingQuestions("The runtime restarted to change model");
|
|
105655
106165
|
this.input.writeOutput?.(
|
|
105656
106166
|
`agent_bridge_claude_model_selection_changed provider=${next.model?.provider ?? ""} model=${next.model?.id ?? ""} reasoning_effort=${next.reasoningEffort ?? ""}`
|
|
@@ -105844,6 +106354,9 @@ var CodexProjector = class {
|
|
|
105844
106354
|
toolMetadata: statusMetadata(item.status)
|
|
105845
106355
|
});
|
|
105846
106356
|
case "mcpToolCall":
|
|
106357
|
+
if (isAskUserMcpTool(item.server, item.tool)) {
|
|
106358
|
+
return [];
|
|
106359
|
+
}
|
|
105847
106360
|
return this.projectToolItem({
|
|
105848
106361
|
phase,
|
|
105849
106362
|
itemId: item.id,
|
|
@@ -106187,6 +106700,9 @@ function renderCodexConfigToml(config2) {
|
|
|
106187
106700
|
lines.push("");
|
|
106188
106701
|
lines.push(`[mcp_servers.${tomlKey(name)}]`);
|
|
106189
106702
|
lines.push(`url = ${tomlString(server.url)}`);
|
|
106703
|
+
lines.push(
|
|
106704
|
+
`tool_timeout_sec = ${validatedMcpToolTimeoutSeconds(HARNESS_MCP_TOOL_TIMEOUT_SECONDS)}`
|
|
106705
|
+
);
|
|
106190
106706
|
const persistedHeaders = Object.fromEntries(
|
|
106191
106707
|
Object.entries(server.headers ?? {}).filter(
|
|
106192
106708
|
([name2]) => name2 !== AGENT_BRIDGE_MCP_CAPABILITY_HEADER
|
|
@@ -106200,20 +106716,30 @@ function renderCodexConfigToml(config2) {
|
|
|
106200
106716
|
`;
|
|
106201
106717
|
}
|
|
106202
106718
|
function turnOnlyMcpConfig(mcpServers) {
|
|
106719
|
+
const hasTurnOnlyCapability = Object.values(mcpServers ?? {}).some(
|
|
106720
|
+
(server) => server.headers?.[AGENT_BRIDGE_MCP_CAPABILITY_HEADER] !== void 0
|
|
106721
|
+
);
|
|
106722
|
+
if (!hasTurnOnlyCapability) {
|
|
106723
|
+
return void 0;
|
|
106724
|
+
}
|
|
106203
106725
|
const servers = Object.fromEntries(
|
|
106204
|
-
Object.entries(mcpServers ?? {}).
|
|
106726
|
+
Object.entries(mcpServers ?? {}).map(([name, server]) => {
|
|
106205
106727
|
const capability = server.headers?.[AGENT_BRIDGE_MCP_CAPABILITY_HEADER];
|
|
106206
|
-
return
|
|
106207
|
-
|
|
106208
|
-
|
|
106209
|
-
|
|
106210
|
-
|
|
106728
|
+
return [
|
|
106729
|
+
name,
|
|
106730
|
+
{
|
|
106731
|
+
url: server.url,
|
|
106732
|
+
tool_timeout_sec: validatedMcpToolTimeoutSeconds(
|
|
106733
|
+
HARNESS_MCP_TOOL_TIMEOUT_SECONDS
|
|
106734
|
+
),
|
|
106735
|
+
...server.headers ? {
|
|
106211
106736
|
http_headers: {
|
|
106212
|
-
|
|
106737
|
+
...server.headers,
|
|
106738
|
+
...capability ? { [AGENT_BRIDGE_MCP_CAPABILITY_HEADER]: capability } : {}
|
|
106213
106739
|
}
|
|
106214
|
-
}
|
|
106215
|
-
|
|
106216
|
-
]
|
|
106740
|
+
} : {}
|
|
106741
|
+
}
|
|
106742
|
+
];
|
|
106217
106743
|
})
|
|
106218
106744
|
);
|
|
106219
106745
|
return Object.keys(servers).length > 0 ? { mcp_servers: servers } : void 0;
|
|
@@ -106807,7 +107333,7 @@ var CodexAgentBridgeSessionImpl = class {
|
|
|
106807
107333
|
return;
|
|
106808
107334
|
} catch (error51) {
|
|
106809
107335
|
this.input.writeOutput?.(
|
|
106810
|
-
`agent_bridge_codex_resume_fallback thread_id=${this.input.resumeThreadId} error=${
|
|
107336
|
+
`agent_bridge_codex_resume_fallback thread_id=${this.input.resumeThreadId} error=${errorMessage3(error51)}`
|
|
106811
107337
|
);
|
|
106812
107338
|
}
|
|
106813
107339
|
}
|
|
@@ -106885,7 +107411,7 @@ var CodexAgentBridgeSessionImpl = class {
|
|
|
106885
107411
|
this.activeCommandIds = previousCommandIds;
|
|
106886
107412
|
this.publishActiveTurnCommandIds();
|
|
106887
107413
|
this.input.writeOutput?.(
|
|
106888
|
-
`agent_bridge_codex_steer_failed error=${
|
|
107414
|
+
`agent_bridge_codex_steer_failed error=${errorMessage3(error51)}`
|
|
106889
107415
|
);
|
|
106890
107416
|
}
|
|
106891
107417
|
if (this.activeTurnId) {
|
|
@@ -106899,7 +107425,7 @@ var CodexAgentBridgeSessionImpl = class {
|
|
|
106899
107425
|
this.input.writeOutput?.("agent_bridge_codex_interrupted");
|
|
106900
107426
|
} catch (error51) {
|
|
106901
107427
|
this.input.writeOutput?.(
|
|
106902
|
-
`agent_bridge_codex_interrupt_failed error=${
|
|
107428
|
+
`agent_bridge_codex_interrupt_failed error=${errorMessage3(error51)}`
|
|
106903
107429
|
);
|
|
106904
107430
|
}
|
|
106905
107431
|
}
|
|
@@ -106974,7 +107500,7 @@ var CodexAgentBridgeSessionImpl = class {
|
|
|
106974
107500
|
message = parseCodexServerFrame(JSON.parse(line));
|
|
106975
107501
|
} catch (error51) {
|
|
106976
107502
|
this.input.writeOutput?.(
|
|
106977
|
-
`agent_bridge_codex_parse_failed error=${
|
|
107503
|
+
`agent_bridge_codex_parse_failed error=${errorMessage3(error51)}`
|
|
106978
107504
|
);
|
|
106979
107505
|
return;
|
|
106980
107506
|
}
|
|
@@ -107169,7 +107695,7 @@ var CodexAgentBridgeSessionImpl = class {
|
|
|
107169
107695
|
);
|
|
107170
107696
|
} catch (error51) {
|
|
107171
107697
|
this.input.writeOutput?.(
|
|
107172
|
-
`agent_bridge_codex_turn_retry_failed attempt=${input.attempt} error=${
|
|
107698
|
+
`agent_bridge_codex_turn_retry_failed attempt=${input.attempt} error=${errorMessage3(error51)}`
|
|
107173
107699
|
);
|
|
107174
107700
|
this.turnRetry = null;
|
|
107175
107701
|
this.clearPendingRetryableError();
|
|
@@ -107384,7 +107910,7 @@ function threadIdFromResult(result) {
|
|
|
107384
107910
|
const id = thread.id;
|
|
107385
107911
|
return typeof id === "string" && id.length > 0 ? id : null;
|
|
107386
107912
|
}
|
|
107387
|
-
function
|
|
107913
|
+
function errorMessage3(error51) {
|
|
107388
107914
|
return error51 instanceof Error ? error51.message : String(error51);
|
|
107389
107915
|
}
|
|
107390
107916
|
function toErrnoException(error51) {
|
|
@@ -107410,6 +107936,11 @@ var CodexCommandHandler = class {
|
|
|
107410
107936
|
mcpServers: input.codex.mcpServers,
|
|
107411
107937
|
writeOutput: input.writeOutput
|
|
107412
107938
|
});
|
|
107939
|
+
this.askUserServer = new AskUserServer({
|
|
107940
|
+
onQuestionPending: (question) => this.handleAskUserQuestion(question),
|
|
107941
|
+
onQuestionSettled: ({ id }) => this.pendingQuestions.delete(id),
|
|
107942
|
+
writeOutput: input.writeOutput
|
|
107943
|
+
});
|
|
107413
107944
|
this.outputBuffer = new AgentBridgeOutputBuffer(input);
|
|
107414
107945
|
}
|
|
107415
107946
|
input;
|
|
@@ -107417,10 +107948,12 @@ var CodexCommandHandler = class {
|
|
|
107417
107948
|
session = null;
|
|
107418
107949
|
codexConfig;
|
|
107419
107950
|
autoMcpShim;
|
|
107951
|
+
askUserServer;
|
|
107420
107952
|
injectedCommands = /* @__PURE__ */ new Set();
|
|
107421
107953
|
// itemId -> JSON-RPC request id of the parked approval request, so an `answer`
|
|
107422
107954
|
// command keyed by toolCallId (= itemId) can resolve the right server request.
|
|
107423
107955
|
pendingApprovals = /* @__PURE__ */ new Map();
|
|
107956
|
+
pendingQuestions = /* @__PURE__ */ new Set();
|
|
107424
107957
|
outputBuffer;
|
|
107425
107958
|
projector = new CodexProjector();
|
|
107426
107959
|
livenessTicker = null;
|
|
@@ -107442,9 +107975,23 @@ var CodexCommandHandler = class {
|
|
|
107442
107975
|
return this.outputBuffer.pendingOutputStats();
|
|
107443
107976
|
}
|
|
107444
107977
|
async prepare() {
|
|
107978
|
+
const mcpServers = await this.autoMcpShim.prepare();
|
|
107979
|
+
if (mcpServers?.[ASK_USER_MCP_SERVER_NAME]) {
|
|
107980
|
+
throw new Error(
|
|
107981
|
+
`MCP server name ${ASK_USER_MCP_SERVER_NAME} is reserved by the harness`
|
|
107982
|
+
);
|
|
107983
|
+
}
|
|
107984
|
+
const askUserEndpoint = await this.askUserServer.prepare();
|
|
107445
107985
|
this.codexConfig = {
|
|
107446
107986
|
...this.codexConfig,
|
|
107447
|
-
mcpServers:
|
|
107987
|
+
mcpServers: {
|
|
107988
|
+
...mcpServers,
|
|
107989
|
+
[ASK_USER_MCP_SERVER_NAME]: {
|
|
107990
|
+
type: "http",
|
|
107991
|
+
url: askUserEndpoint.url,
|
|
107992
|
+
headers: askUserEndpoint.headers
|
|
107993
|
+
}
|
|
107994
|
+
}
|
|
107448
107995
|
};
|
|
107449
107996
|
await this.ensureSession().prepare();
|
|
107450
107997
|
}
|
|
@@ -107454,7 +108001,9 @@ var CodexCommandHandler = class {
|
|
|
107454
108001
|
this.session?.close();
|
|
107455
108002
|
this.session = null;
|
|
107456
108003
|
this.autoMcpShim.close();
|
|
108004
|
+
this.askUserServer.close();
|
|
107457
108005
|
this.pendingApprovals.clear();
|
|
108006
|
+
this.pendingQuestions.clear();
|
|
107458
108007
|
}
|
|
107459
108008
|
async handleCommand(rawDelivery) {
|
|
107460
108009
|
const delivery = RuntimeBridgeCommandDeliverySchema.parse(rawDelivery);
|
|
@@ -107471,6 +108020,7 @@ var CodexCommandHandler = class {
|
|
|
107471
108020
|
}
|
|
107472
108021
|
if (delivery.kind === "interrupt") {
|
|
107473
108022
|
this.injectedCommands.add(delivery.commandId);
|
|
108023
|
+
this.askUserServer.quarantineAll("turn interrupted");
|
|
107474
108024
|
await this.session?.interruptActiveTurn();
|
|
107475
108025
|
return commandAck({ delivery, socketId, status: "injected" });
|
|
107476
108026
|
}
|
|
@@ -107514,7 +108064,7 @@ var CodexCommandHandler = class {
|
|
|
107514
108064
|
delivery,
|
|
107515
108065
|
socketId,
|
|
107516
108066
|
status: "failed",
|
|
107517
|
-
error:
|
|
108067
|
+
error: errorMessage4(error51)
|
|
107518
108068
|
});
|
|
107519
108069
|
}
|
|
107520
108070
|
return commandAck({ delivery, socketId, status: "injected" });
|
|
@@ -107547,6 +108097,11 @@ var CodexCommandHandler = class {
|
|
|
107547
108097
|
this.input.writeOutput?.(
|
|
107548
108098
|
`agent_bridge_codex_question_answered tool_use_id=${payload.data.toolCallId} decision=${decision}`
|
|
107549
108099
|
);
|
|
108100
|
+
} else if (this.pendingQuestions.has(payload.data.toolCallId) && this.askUserServer.answer(payload.data)) {
|
|
108101
|
+
await this.emit(activeContext, projectAskUserAnswer(payload.data));
|
|
108102
|
+
this.input.writeOutput?.(
|
|
108103
|
+
`agent_bridge_codex_question_answered tool_use_id=${payload.data.toolCallId} decision=answered`
|
|
108104
|
+
);
|
|
107550
108105
|
} else {
|
|
107551
108106
|
const message = answerFallbackMessage2(payload.data);
|
|
107552
108107
|
await this.emitUserMessageEntry(
|
|
@@ -107564,7 +108119,7 @@ var CodexCommandHandler = class {
|
|
|
107564
108119
|
delivery,
|
|
107565
108120
|
socketId,
|
|
107566
108121
|
status: "failed",
|
|
107567
|
-
error:
|
|
108122
|
+
error: errorMessage4(error51)
|
|
107568
108123
|
});
|
|
107569
108124
|
}
|
|
107570
108125
|
return commandAck({ delivery, socketId, status: "injected" });
|
|
@@ -107592,6 +108147,9 @@ var CodexCommandHandler = class {
|
|
|
107592
108147
|
if (notification.type === "tokenUsage") {
|
|
107593
108148
|
return;
|
|
107594
108149
|
}
|
|
108150
|
+
if (notification.type === "turnCompleted") {
|
|
108151
|
+
this.askUserServer.quarantineAll("turn ended");
|
|
108152
|
+
}
|
|
107595
108153
|
for (const projection of this.projector.project(notification)) {
|
|
107596
108154
|
await this.emit(activeContext, projection);
|
|
107597
108155
|
}
|
|
@@ -107609,9 +108167,25 @@ var CodexCommandHandler = class {
|
|
|
107609
108167
|
await this.emit(activeContext, projection);
|
|
107610
108168
|
}
|
|
107611
108169
|
}
|
|
108170
|
+
async handleAskUserQuestion(input) {
|
|
108171
|
+
const activeContext = this.context;
|
|
108172
|
+
if (!activeContext) {
|
|
108173
|
+
throw new Error(
|
|
108174
|
+
"Cannot publish an ask-user question without bridge context"
|
|
108175
|
+
);
|
|
108176
|
+
}
|
|
108177
|
+
this.pendingQuestions.add(input.id);
|
|
108178
|
+
this.input.writeOutput?.(
|
|
108179
|
+
`agent_bridge_codex_question_pending tool_use_id=${input.id}`
|
|
108180
|
+
);
|
|
108181
|
+
for (const projection of projectAskUserQuestion(input)) {
|
|
108182
|
+
await this.emitRequired(activeContext, projection);
|
|
108183
|
+
}
|
|
108184
|
+
}
|
|
107612
108185
|
async handleSessionError(error51) {
|
|
108186
|
+
this.askUserServer.quarantineAll("harness session failed");
|
|
107613
108187
|
this.input.writeOutput?.(
|
|
107614
|
-
`agent_bridge_codex_session_failed error=${
|
|
108188
|
+
`agent_bridge_codex_session_failed error=${errorMessage4(error51)}`
|
|
107615
108189
|
);
|
|
107616
108190
|
const activeContext = this.context;
|
|
107617
108191
|
if (!activeContext) {
|
|
@@ -107619,7 +108193,7 @@ var CodexCommandHandler = class {
|
|
|
107619
108193
|
}
|
|
107620
108194
|
await this.emit(
|
|
107621
108195
|
activeContext,
|
|
107622
|
-
this.projector.projectSessionFailure(
|
|
108196
|
+
this.projector.projectSessionFailure(errorMessage4(error51))
|
|
107623
108197
|
);
|
|
107624
108198
|
}
|
|
107625
108199
|
async emitLivenessBeat() {
|
|
@@ -107644,10 +108218,16 @@ var CodexCommandHandler = class {
|
|
|
107644
108218
|
await this.outputBuffer.emitProjection(activeContext, projection);
|
|
107645
108219
|
} catch (error51) {
|
|
107646
108220
|
this.input.writeOutput?.(
|
|
107647
|
-
`agent_bridge_output_emit_failed error=${
|
|
108221
|
+
`agent_bridge_output_emit_failed error=${errorMessage4(error51)}`
|
|
107648
108222
|
);
|
|
107649
108223
|
}
|
|
107650
108224
|
}
|
|
108225
|
+
async emitRequired(activeContext, projection) {
|
|
108226
|
+
await this.outputBuffer.emitProjection(activeContext, projection, {
|
|
108227
|
+
discardOnFailure: true,
|
|
108228
|
+
requireDrain: true
|
|
108229
|
+
});
|
|
108230
|
+
}
|
|
107651
108231
|
ensureSession() {
|
|
107652
108232
|
if (this.session) {
|
|
107653
108233
|
return this.session;
|
|
@@ -107664,6 +108244,7 @@ var CodexCommandHandler = class {
|
|
|
107664
108244
|
onUsageTurnChanged: (turnId) => this.emitUsageTurn(turnId),
|
|
107665
108245
|
onError: (error51) => this.handleSessionError(error51),
|
|
107666
108246
|
onExit: () => {
|
|
108247
|
+
this.askUserServer.quarantineAll("harness child exited");
|
|
107667
108248
|
if (this.session === session) {
|
|
107668
108249
|
this.session = null;
|
|
107669
108250
|
}
|
|
@@ -107691,7 +108272,9 @@ var CodexCommandHandler = class {
|
|
|
107691
108272
|
this.skipResumeForNextSession = true;
|
|
107692
108273
|
this.session?.close();
|
|
107693
108274
|
this.session = null;
|
|
108275
|
+
this.askUserServer.quarantineAll("harness session restarted");
|
|
107694
108276
|
this.pendingApprovals.clear();
|
|
108277
|
+
this.pendingQuestions.clear();
|
|
107695
108278
|
this.input.writeOutput?.(
|
|
107696
108279
|
`agent_bridge_codex_model_selection_changed provider=${next.model?.provider ?? ""} model=${next.model?.id ?? ""} reasoning_effort=${next.reasoningEffort ?? ""}`
|
|
107697
108280
|
);
|
|
@@ -107706,7 +108289,7 @@ var CodexCommandHandler = class {
|
|
|
107706
108289
|
return store.read(activeContext.sessionId) ?? void 0;
|
|
107707
108290
|
} catch (error51) {
|
|
107708
108291
|
this.input.writeOutput?.(
|
|
107709
|
-
`agent_bridge_codex_thread_read_failed error=${
|
|
108292
|
+
`agent_bridge_codex_thread_read_failed error=${errorMessage4(error51)}`
|
|
107710
108293
|
);
|
|
107711
108294
|
return void 0;
|
|
107712
108295
|
}
|
|
@@ -107721,7 +108304,7 @@ var CodexCommandHandler = class {
|
|
|
107721
108304
|
store.write({ sessionId: activeContext.sessionId, threadId });
|
|
107722
108305
|
} catch (error51) {
|
|
107723
108306
|
this.input.writeOutput?.(
|
|
107724
|
-
`agent_bridge_codex_thread_persist_failed error=${
|
|
108307
|
+
`agent_bridge_codex_thread_persist_failed error=${errorMessage4(error51)}`
|
|
107725
108308
|
);
|
|
107726
108309
|
}
|
|
107727
108310
|
}
|
|
@@ -107763,7 +108346,7 @@ function deliveryMode2(delivery) {
|
|
|
107763
108346
|
}
|
|
107764
108347
|
return "interrupt";
|
|
107765
108348
|
}
|
|
107766
|
-
function
|
|
108349
|
+
function errorMessage4(error51) {
|
|
107767
108350
|
return error51 instanceof Error ? error51.message : String(error51);
|
|
107768
108351
|
}
|
|
107769
108352
|
|