very-happy-cli 0.2.134 → 0.2.135
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/{AcpBackend-CeNp7tgD.cjs → AcpBackend-C0Bwx6bc.cjs} +2 -2
- package/dist/{AcpBackend-B8KEjDwF.mjs → AcpBackend-CkDpu1n_.mjs} +2 -2
- package/dist/{AcpSessionManager-KlDZbEmZ.mjs → AcpSessionManager-DB_mfFaH.mjs} +1 -1
- package/dist/{AcpSessionManager-Bu1d05bx.cjs → AcpSessionManager-DqvUp-UU.cjs} +1 -1
- package/dist/{agentGuidance-CPG5Cr5T.mjs → agentGuidance-7MByWxKj.mjs} +1 -1
- package/dist/{agentGuidance-Cg8Lha39.cjs → agentGuidance-DlZM_YPV.cjs} +1 -1
- package/dist/codex/happyMcpStdioBridge.cjs +2 -2
- package/dist/codex/happyMcpStdioBridge.mjs +2 -2
- package/dist/{config-C3e90AIH.cjs → config-BO0ZHyoB.cjs} +4 -4
- package/dist/{config-C4gWfnJX.mjs → config-DzvbcL_x.mjs} +4 -4
- package/dist/{index-jqG8CV0c.cjs → index-BEpZjXs4.cjs} +6 -6
- package/dist/{index-B6UvB88K.mjs → index-C33JB4xB.mjs} +7 -7
- package/dist/{index-CEDPokKf.mjs → index-CpEdOGpe.mjs} +4 -4
- package/dist/{index-CX-zp3FH.cjs → index-DHI6Y1xW.cjs} +4 -4
- package/dist/{index-B1plzL9M.cjs → index-DNbKbe23.cjs} +1522 -1200
- package/dist/{index-BqUOj1zK.mjs → index-gefLe1Bk.mjs} +1520 -1198
- package/dist/index.cjs +4 -4
- package/dist/index.mjs +4 -4
- package/dist/{installTerminalHooks-BT4Dq28Y.mjs → installTerminalHooks-BWoHGCew.mjs} +4 -4
- package/dist/{installTerminalHooks-DPmEaHg2.cjs → installTerminalHooks-gmWKACNb.cjs} +4 -4
- package/dist/lib.cjs +2 -2
- package/dist/lib.d.cts +14 -0
- package/dist/lib.d.mts +14 -0
- package/dist/lib.mjs +2 -2
- package/dist/{limits-BGeIBBE3.mjs → limits-CPTgiQ9A.mjs} +8 -8
- package/dist/{limits-D6kiAfXJ.cjs → limits-K17AgMHD.cjs} +8 -8
- package/dist/{mcp-DGZmUpuZ.cjs → mcp-CK1NCZm0.cjs} +4 -4
- package/dist/{mcp-BGu_dUaJ.mjs → mcp-DhuxpwTB.mjs} +4 -4
- package/dist/{runGemini-DGTNwiLo.mjs → runGemini-BVJE7LZl.mjs} +6 -6
- package/dist/{runGemini-BPPnulIk.cjs → runGemini-n0wD2Z9R.cjs} +6 -6
- package/dist/{runOpenClaw-CxgTFOSM.mjs → runOpenClaw-CJaIYpB7.mjs} +5 -5
- package/dist/{runOpenClaw-BB3Ivt1S.cjs → runOpenClaw-fYx1XweW.cjs} +5 -5
- package/dist/{send-Bo6iKuXr.cjs → send-WlJ4r3U2.cjs} +4 -4
- package/dist/{send-DHShoBeq.mjs → send-fWHOFJV9.mjs} +4 -4
- package/dist/{sessions-CJuwvEr0.mjs → sessions-5fJxQ2xj.mjs} +4 -4
- package/dist/{sessions-DyC5Attg.cjs → sessions-Cx_3cvN6.cjs} +4 -4
- package/dist/{spawn-QtKlr8Ig.mjs → spawn-CF1ZV-YH.mjs} +4 -4
- package/dist/{spawn-gha6nGx-.cjs → spawn-DVJtNwWN.cjs} +4 -4
- package/dist/{teams-BbzWNV9e.cjs → teams-BbYi0fWG.cjs} +4 -4
- package/dist/{teams-BF-GxUZc.mjs → teams-gzvKrMfn.mjs} +4 -4
- package/dist/{todo-CkJ5UjWs.mjs → todo-BAK2DVLV.mjs} +3 -3
- package/dist/{todo-BaNaNZ8c.cjs → todo-DHY20tpD.cjs} +3 -3
- package/dist/{types-Cq-tvv9t.mjs → types-BEXGahmj.mjs} +45 -9
- package/dist/{types-Dabm17Ln.cjs → types-DjAHWb4J.cjs} +46 -9
- package/package.json +8 -8
|
@@ -3,13 +3,13 @@
|
|
|
3
3
|
var chalk = require('chalk');
|
|
4
4
|
var os = require('node:os');
|
|
5
5
|
var node_crypto = require('node:crypto');
|
|
6
|
-
var api = require('./types-
|
|
7
|
-
var persistence = require('./limits-
|
|
6
|
+
var api = require('./types-DjAHWb4J.cjs');
|
|
7
|
+
var persistence = require('./limits-K17AgMHD.cjs');
|
|
8
8
|
var spawn = require('cross-spawn');
|
|
9
9
|
var path = require('node:path');
|
|
10
10
|
var node_readline = require('node:readline');
|
|
11
11
|
var node_fs = require('node:fs');
|
|
12
|
-
var agentGuidance = require('./agentGuidance-
|
|
12
|
+
var agentGuidance = require('./agentGuidance-DlZM_YPV.cjs');
|
|
13
13
|
var promises = require('node:fs/promises');
|
|
14
14
|
var fs = require('fs/promises');
|
|
15
15
|
var ink = require('ink');
|
|
@@ -1353,6 +1353,152 @@ async function claudeLocalLauncher(session) {
|
|
|
1353
1353
|
return exitReason || { type: "exit", code: 0 };
|
|
1354
1354
|
}
|
|
1355
1355
|
|
|
1356
|
+
const text = (value) => typeof value === "string" && value.length > 0 && value.length <= 1024 && !value.includes("\0") ? value : null;
|
|
1357
|
+
const publicMcpStatus = (servers) => servers.map(({ name, status, serverInfo, scope, tools }) => ({ name, status, serverInfo, scope, tools: tools?.map(({ name: name2 }) => ({ name: name2 })) }));
|
|
1358
|
+
const fingerprint = (result) => JSON.stringify([result.canRewind, [...result.filesChanged ?? []].sort(), result.insertions, result.deletions]);
|
|
1359
|
+
function isRuntimeCheckpointReplay(message) {
|
|
1360
|
+
const m = message;
|
|
1361
|
+
return m.type === "user" && m.isReplay === true && !m.parent_tool_use_id && !(Array.isArray(m.message?.content) && m.message.content.some((block) => block.type === "tool_result"));
|
|
1362
|
+
}
|
|
1363
|
+
function createRuntimeControls(isThinking) {
|
|
1364
|
+
let query = null, generation = node_crypto.randomInt(0, 2 ** 40), activityRevision = 0;
|
|
1365
|
+
const operations = /* @__PURE__ */ new Map();
|
|
1366
|
+
const confirmations = /* @__PURE__ */ new Map();
|
|
1367
|
+
const tasks = /* @__PURE__ */ new Map();
|
|
1368
|
+
const checkpoints = /* @__PURE__ */ new Map();
|
|
1369
|
+
let pending = false;
|
|
1370
|
+
const setQuery = (next) => {
|
|
1371
|
+
for (const operation of operations.values()) if (operation.status === "running") {
|
|
1372
|
+
operation.status = "failed";
|
|
1373
|
+
operation.error = "Claude query ended before this operation completed";
|
|
1374
|
+
}
|
|
1375
|
+
query = next;
|
|
1376
|
+
generation++;
|
|
1377
|
+
pending = false;
|
|
1378
|
+
confirmations.clear();
|
|
1379
|
+
tasks.clear();
|
|
1380
|
+
checkpoints.clear();
|
|
1381
|
+
};
|
|
1382
|
+
function observe(message) {
|
|
1383
|
+
const m = message;
|
|
1384
|
+
if (m.type === "user" || m.type === "assistant") {
|
|
1385
|
+
activityRevision++;
|
|
1386
|
+
confirmations.clear();
|
|
1387
|
+
}
|
|
1388
|
+
const content = typeof m.message?.content === "string" ? m.message.content : Array.isArray(m.message?.content) ? m.message.content.filter((block) => block.type === "text").map((block) => block.text).join(" ") : "";
|
|
1389
|
+
if (isRuntimeCheckpointReplay(message) && text(m.uuid) && content) {
|
|
1390
|
+
checkpoints.set(m.uuid, { id: m.uuid, title: content.slice(0, 120) });
|
|
1391
|
+
if (checkpoints.size > 100) checkpoints.delete(checkpoints.keys().next().value);
|
|
1392
|
+
}
|
|
1393
|
+
if (m.type === "system" && text(m.task_id) && ["task_started", "task_updated", "task_progress", "task_notification"].includes(m.subtype)) {
|
|
1394
|
+
const previous = tasks.get(m.task_id);
|
|
1395
|
+
if (m.subtype !== "task_notification" && ["completed", "failed", "stopped", "cancelled"].includes(String(previous?.status))) return;
|
|
1396
|
+
tasks.set(m.task_id, {
|
|
1397
|
+
...previous,
|
|
1398
|
+
id: m.task_id,
|
|
1399
|
+
...text(m.tool_use_id) ? { toolUseId: m.tool_use_id } : {},
|
|
1400
|
+
...text(m.description) ? { description: m.description } : {},
|
|
1401
|
+
...text(m.task_type) ? { type: m.task_type } : {},
|
|
1402
|
+
status: m.subtype === "task_notification" ? m.status ?? "completed" : "running"
|
|
1403
|
+
});
|
|
1404
|
+
if (tasks.size > 100) tasks.delete(tasks.keys().next().value);
|
|
1405
|
+
}
|
|
1406
|
+
}
|
|
1407
|
+
function request(input) {
|
|
1408
|
+
const r = input && typeof input === "object" ? input : {};
|
|
1409
|
+
if (r.action === "status") return { queryGeneration: generation, active: !!query, isRunning: isThinking(), canRewind: !!query && !isThinking() && !pending && query.canControl(), busy: pending || !!query && !query.canControl(), tasks: [...tasks.values()], checkpoints: [...checkpoints.values()], operations: [...operations.values()].filter((op2) => op2.queryGeneration === generation) };
|
|
1410
|
+
if (r.action === "operation") {
|
|
1411
|
+
const op2 = operations.get(String(r.operationId));
|
|
1412
|
+
return op2 ? { ...op2 } : { error: "Operation not found" };
|
|
1413
|
+
}
|
|
1414
|
+
const q = query;
|
|
1415
|
+
if (!q) return { error: "No active Claude SDK query" };
|
|
1416
|
+
if (pending || !q.canControl()) return { error: "Claude is waiting for an interaction or another control operation; retry after it finishes" };
|
|
1417
|
+
const action = String(r.action), server = text(r.serverName), task = text(r.taskId), target = text(r.userMessageId);
|
|
1418
|
+
const runGeneration = generation, runRevision = activityRevision;
|
|
1419
|
+
let execute;
|
|
1420
|
+
switch (action) {
|
|
1421
|
+
case "reload-skills":
|
|
1422
|
+
execute = () => q.reloadSkills();
|
|
1423
|
+
break;
|
|
1424
|
+
case "reload-plugins":
|
|
1425
|
+
execute = async () => {
|
|
1426
|
+
const result = await q.reloadPlugins();
|
|
1427
|
+
return { ...result, mcpServers: publicMcpStatus(result.mcpServers ?? []) };
|
|
1428
|
+
};
|
|
1429
|
+
break;
|
|
1430
|
+
case "mcp-status":
|
|
1431
|
+
execute = async () => publicMcpStatus(await q.mcpServerStatus());
|
|
1432
|
+
break;
|
|
1433
|
+
case "mcp-reconnect":
|
|
1434
|
+
if (!server) return { error: "Invalid server name" };
|
|
1435
|
+
execute = () => q.reconnectMcpServer(server);
|
|
1436
|
+
break;
|
|
1437
|
+
case "mcp-toggle":
|
|
1438
|
+
if (!server || typeof r.enabled !== "boolean") return { error: "Invalid server or enabled flag" };
|
|
1439
|
+
execute = () => q.toggleMcpServer(server, r.enabled);
|
|
1440
|
+
break;
|
|
1441
|
+
case "stop-task":
|
|
1442
|
+
if (!task || !tasks.has(task)) return { error: "Unknown task in this query" };
|
|
1443
|
+
execute = () => q.stopTask(task);
|
|
1444
|
+
break;
|
|
1445
|
+
case "background-tasks":
|
|
1446
|
+
if (r.toolUseId !== void 0 && !text(r.toolUseId)) return { error: "Invalid tool use ID" };
|
|
1447
|
+
execute = async () => ({ backgrounded: await q.backgroundTasks(r.toolUseId) });
|
|
1448
|
+
break;
|
|
1449
|
+
case "rewind-preview":
|
|
1450
|
+
if (isThinking() || !target || !checkpoints.has(target)) return { error: "Rewind requires an idle query and a known user checkpoint" };
|
|
1451
|
+
execute = async () => {
|
|
1452
|
+
const result = await q.rewindFiles(target, { dryRun: true });
|
|
1453
|
+
if (!result.canRewind) return result;
|
|
1454
|
+
if (query !== q || generation !== runGeneration || activityRevision !== runRevision || isThinking() || !q.canControl()) throw Error("Query changed; preview again");
|
|
1455
|
+
const token = node_crypto.randomUUID();
|
|
1456
|
+
confirmations.set(token, { generation, revision: activityRevision, userMessageId: target, fingerprint: fingerprint(result), expires: Date.now() + 3e5 });
|
|
1457
|
+
return { ...result, confirmationToken: token };
|
|
1458
|
+
};
|
|
1459
|
+
break;
|
|
1460
|
+
case "rewind-apply": {
|
|
1461
|
+
const confirmation = confirmations.get(String(r.confirmationToken));
|
|
1462
|
+
if (isThinking() || !confirmation || confirmation.generation !== generation || confirmation.expires < Date.now()) return { error: "Preview expired or query is running; preview again" };
|
|
1463
|
+
confirmations.delete(String(r.confirmationToken));
|
|
1464
|
+
execute = async () => {
|
|
1465
|
+
const fresh = await q.rewindFiles(confirmation.userMessageId, { dryRun: true });
|
|
1466
|
+
if (query !== q || generation !== runGeneration || activityRevision !== confirmation.revision || isThinking() || !q.canControl() || fingerprint(fresh) !== confirmation.fingerprint) throw Error("Files or query changed; preview again");
|
|
1467
|
+
return q.rewindFiles(confirmation.userMessageId, { dryRun: false });
|
|
1468
|
+
};
|
|
1469
|
+
break;
|
|
1470
|
+
}
|
|
1471
|
+
default:
|
|
1472
|
+
return { error: "Unknown Claude control action" };
|
|
1473
|
+
}
|
|
1474
|
+
pending = true;
|
|
1475
|
+
const op = { id: node_crypto.randomUUID(), queryGeneration: runGeneration, action, status: "running" };
|
|
1476
|
+
operations.set(op.id, op);
|
|
1477
|
+
if (operations.size > 50) for (const [id, old] of operations) {
|
|
1478
|
+
if (old.status !== "running") {
|
|
1479
|
+
operations.delete(id);
|
|
1480
|
+
break;
|
|
1481
|
+
}
|
|
1482
|
+
}
|
|
1483
|
+
void Promise.resolve().then(() => {
|
|
1484
|
+
if (query !== q || generation !== runGeneration || !q.canControl()) throw Error("Claude query changed or is waiting for an interaction");
|
|
1485
|
+
return execute();
|
|
1486
|
+
}).then((result) => {
|
|
1487
|
+
if (generation !== runGeneration || op.status !== "running") return;
|
|
1488
|
+
op.status = "completed";
|
|
1489
|
+
op.result = result ?? null;
|
|
1490
|
+
}, (error) => {
|
|
1491
|
+
if (generation !== runGeneration || op.status !== "running") return;
|
|
1492
|
+
op.status = "failed";
|
|
1493
|
+
op.error = error instanceof Error ? error.message : "Claude control failed";
|
|
1494
|
+
}).finally(() => {
|
|
1495
|
+
if (generation === runGeneration) pending = false;
|
|
1496
|
+
});
|
|
1497
|
+
return { operationId: op.id };
|
|
1498
|
+
}
|
|
1499
|
+
return { setQuery, observe, request };
|
|
1500
|
+
}
|
|
1501
|
+
|
|
1356
1502
|
class MessageBuffer {
|
|
1357
1503
|
messages = [];
|
|
1358
1504
|
listeners = [];
|
|
@@ -1622,6 +1768,9 @@ function query(params) {
|
|
|
1622
1768
|
tools: opts?.tools,
|
|
1623
1769
|
persistSession: opts?.persistSession,
|
|
1624
1770
|
includePartialMessages: opts?.includePartialMessages,
|
|
1771
|
+
forwardSubagentText: true,
|
|
1772
|
+
enableFileCheckpointing: true,
|
|
1773
|
+
extraArgs: { "replay-user-messages": null },
|
|
1625
1774
|
onElicitation: opts?.onElicitation,
|
|
1626
1775
|
onUserDialog: opts?.onUserDialog,
|
|
1627
1776
|
supportedDialogKinds: opts?.onUserDialog ? opts.supportedDialogKinds : void 0
|
|
@@ -2064,6 +2213,20 @@ async function claudeRemote(opts) {
|
|
|
2064
2213
|
content: initial.message
|
|
2065
2214
|
}
|
|
2066
2215
|
});
|
|
2216
|
+
let callbackDepth = 0;
|
|
2217
|
+
const guardCallback = (callback) => (async (...args) => {
|
|
2218
|
+
callbackDepth++;
|
|
2219
|
+
try {
|
|
2220
|
+
return await callback(...args);
|
|
2221
|
+
} finally {
|
|
2222
|
+
setImmediate(() => {
|
|
2223
|
+
callbackDepth--;
|
|
2224
|
+
});
|
|
2225
|
+
}
|
|
2226
|
+
});
|
|
2227
|
+
if (sdkOptions.canCallTool) sdkOptions.canCallTool = guardCallback(sdkOptions.canCallTool);
|
|
2228
|
+
if (sdkOptions.onElicitation) sdkOptions.onElicitation = guardCallback(sdkOptions.onElicitation);
|
|
2229
|
+
if (sdkOptions.onUserDialog) sdkOptions.onUserDialog = guardCallback(sdkOptions.onUserDialog);
|
|
2067
2230
|
const response = query({
|
|
2068
2231
|
prompt: messages,
|
|
2069
2232
|
options: sdkOptions
|
|
@@ -2084,6 +2247,15 @@ async function claudeRemote(opts) {
|
|
|
2084
2247
|
}
|
|
2085
2248
|
if (opts.onQueryReady) {
|
|
2086
2249
|
opts.onQueryReady({
|
|
2250
|
+
canControl: () => callbackDepth === 0,
|
|
2251
|
+
reloadSkills: () => response.reloadSkills(),
|
|
2252
|
+
reloadPlugins: () => response.reloadPlugins(),
|
|
2253
|
+
mcpServerStatus: () => response.mcpServerStatus(),
|
|
2254
|
+
reconnectMcpServer: (name) => response.reconnectMcpServer(name),
|
|
2255
|
+
toggleMcpServer: (name, enabled) => response.toggleMcpServer(name, enabled),
|
|
2256
|
+
stopTask: (id) => response.stopTask(id),
|
|
2257
|
+
backgroundTasks: (id) => response.backgroundTasks(id),
|
|
2258
|
+
rewindFiles: (id, options) => response.rewindFiles(id, options),
|
|
2087
2259
|
setPermissionMode: (mode2) => response.setPermissionMode(mode2),
|
|
2088
2260
|
setModel: (model) => response.setModel(modelTarget(model)),
|
|
2089
2261
|
interrupt: async () => {
|
|
@@ -2727,7 +2899,7 @@ class PermissionHandler {
|
|
|
2727
2899
|
} else if (pending.kind === "elicitation") {
|
|
2728
2900
|
pending.resolve(message.approved ? { action: "accept", content: elicitationContent(message.updatedInput) } : { action: message.decision === "abort" ? "cancel" : "decline" });
|
|
2729
2901
|
} else {
|
|
2730
|
-
pending.resolve(message.approved ? { behavior: "completed", result:
|
|
2902
|
+
pending.resolve(message.approved && pending.request.dialogKind === "refusal_fallback_prompt" && (message.updatedInput?.result === void 0 || message.updatedInput.result === "retry_fallback") ? { behavior: "completed", result: "retry_fallback" } : { behavior: "cancelled" });
|
|
2731
2903
|
}
|
|
2732
2904
|
this.recordCompletedRequest(id, effectiveResponse);
|
|
2733
2905
|
this.scheduleDeferredPermissionModeUpdate();
|
|
@@ -3189,6 +3361,7 @@ class SDKToLogConverter {
|
|
|
3189
3361
|
}
|
|
3190
3362
|
}
|
|
3191
3363
|
|
|
3364
|
+
const transcriptSystemSubtypes = /* @__PURE__ */ new Set(["task_started", "task_updated", "task_progress", "task_notification"]);
|
|
3192
3365
|
class OutgoingMessageQueue {
|
|
3193
3366
|
constructor(sendFunction) {
|
|
3194
3367
|
this.sendFunction = sendFunction;
|
|
@@ -3270,7 +3443,7 @@ class OutgoingMessageQueue {
|
|
|
3270
3443
|
break;
|
|
3271
3444
|
}
|
|
3272
3445
|
if (!item.sent) {
|
|
3273
|
-
if (item.logMessage.type !== "system") {
|
|
3446
|
+
if (item.logMessage.type !== "system" || transcriptSystemSubtypes.has(item.logMessage.subtype)) {
|
|
3274
3447
|
this.sendFunction(item.logMessage);
|
|
3275
3448
|
}
|
|
3276
3449
|
item.sent = true;
|
|
@@ -3898,6 +4071,8 @@ async function claudeRemoteLauncher(session, onPermissionModeChange, onEffective
|
|
|
3898
4071
|
let abortController = null;
|
|
3899
4072
|
let abortFuture = null;
|
|
3900
4073
|
const turnSteering = createTurnSteeringController();
|
|
4074
|
+
const runtimeControls = createRuntimeControls(() => session.thinking);
|
|
4075
|
+
session.client.rpcHandlerManager.registerHandler("claude-runtime-control", async (input) => runtimeControls.request(input));
|
|
3901
4076
|
async function abort() {
|
|
3902
4077
|
if (abortController && !abortController.signal.aborted) {
|
|
3903
4078
|
abortController.abort();
|
|
@@ -3958,6 +4133,8 @@ async function claudeRemoteLauncher(session, onPermissionModeChange, onEffective
|
|
|
3958
4133
|
let ongoingToolCalls = /* @__PURE__ */ new Map();
|
|
3959
4134
|
let notifiedQuestionToolCalls = /* @__PURE__ */ new Set();
|
|
3960
4135
|
function onMessage(message) {
|
|
4136
|
+
runtimeControls.observe(message);
|
|
4137
|
+
if (isRuntimeCheckpointReplay(message)) return;
|
|
3961
4138
|
if (message.type === "user" && isClaudeInterruptSentinelContent(message.message.content)) {
|
|
3962
4139
|
sdkToLogConverter.convert(message);
|
|
3963
4140
|
return;
|
|
@@ -4180,6 +4357,7 @@ async function claudeRemoteLauncher(session, onPermissionModeChange, onEffective
|
|
|
4180
4357
|
if (metadata.permissionMode) onEffectivePermissionMode?.(metadata.permissionMode);
|
|
4181
4358
|
},
|
|
4182
4359
|
onQueryReady: (q) => {
|
|
4360
|
+
runtimeControls.setQuery(q);
|
|
4183
4361
|
turnSteering.setInterrupt(q.interrupt);
|
|
4184
4362
|
session.setSteerHandler(async (input) => {
|
|
4185
4363
|
if (!modeGate.matches(input.mode)) return false;
|
|
@@ -4269,6 +4447,7 @@ async function claudeRemoteLauncher(session, onPermissionModeChange, onEffective
|
|
|
4269
4447
|
continue;
|
|
4270
4448
|
}
|
|
4271
4449
|
} finally {
|
|
4450
|
+
runtimeControls.setQuery(null);
|
|
4272
4451
|
turnSteering.reset();
|
|
4273
4452
|
session.setSteerHandler(null);
|
|
4274
4453
|
livePermissionModeHandler = null;
|
|
@@ -5319,6 +5498,80 @@ ${typeLabels[type] || type}:`));
|
|
|
5319
5498
|
console.log(chalk.green("\n\u2705 Doctor diagnosis complete!\n"));
|
|
5320
5499
|
}
|
|
5321
5500
|
|
|
5501
|
+
const AGENT_CHECK_INTERVAL = 6 * 60 * 60 * 1e3;
|
|
5502
|
+
function stableVersion(value) {
|
|
5503
|
+
const match = value.trim().match(/(?:^|\s|v)(\d+\.\d+\.\d+)([-+][\w.-]+)?(?=\s|$)/);
|
|
5504
|
+
return match && !match[2] ? match[1] : null;
|
|
5505
|
+
}
|
|
5506
|
+
function newerVersion(current, latest) {
|
|
5507
|
+
const a = current.split(".").map(Number), b = latest.split(".").map(Number);
|
|
5508
|
+
for (let i = 0; i < 3; i++) {
|
|
5509
|
+
if (b[i] !== a[i]) return b[i] > a[i];
|
|
5510
|
+
}
|
|
5511
|
+
return false;
|
|
5512
|
+
}
|
|
5513
|
+
const runVersionCommand = (command, args, shell) => new Promise((resolve, reject) => {
|
|
5514
|
+
node_child_process.execFile(
|
|
5515
|
+
command,
|
|
5516
|
+
args,
|
|
5517
|
+
{ timeout: 5e3, maxBuffer: 32 * 1024, windowsHide: true, shell },
|
|
5518
|
+
(error, stdout) => error ? reject(error) : resolve(stdout)
|
|
5519
|
+
);
|
|
5520
|
+
});
|
|
5521
|
+
async function probeAgentVersion(command, platform = process.platform, run = runVersionCommand) {
|
|
5522
|
+
if (platform === "win32") {
|
|
5523
|
+
try {
|
|
5524
|
+
await run("where.exe", [command], false);
|
|
5525
|
+
} catch (error) {
|
|
5526
|
+
return { version: null, missing: error.code === 1 };
|
|
5527
|
+
}
|
|
5528
|
+
}
|
|
5529
|
+
try {
|
|
5530
|
+
return { version: stableVersion(await run(command, ["--version"], platform === "win32")), missing: false };
|
|
5531
|
+
} catch (error) {
|
|
5532
|
+
return { version: null, missing: error.code === "ENOENT" };
|
|
5533
|
+
}
|
|
5534
|
+
}
|
|
5535
|
+
async function registryVersion(name) {
|
|
5536
|
+
const response = await fetch(`https://registry.npmjs.org/${encodeURIComponent(name)}/latest`, { signal: AbortSignal.timeout(5e3) });
|
|
5537
|
+
if (!response.ok) throw new Error("Registry unavailable");
|
|
5538
|
+
const data = await response.json();
|
|
5539
|
+
return typeof data.version === "string" ? stableVersion(data.version) : null;
|
|
5540
|
+
}
|
|
5541
|
+
async function detectAgentVersions(deps = { probe: probeAgentVersion, registryVersion }, now = Date.now()) {
|
|
5542
|
+
const agents = await Promise.all(api.AGENT_VERSION_SOURCES.map(async (source) => {
|
|
5543
|
+
const local = source.command ? await deps.probe(source.command).catch(() => ({ version: null, missing: false })) : { version: stableVersion(persistence.packageJson.dependencies["@anthropic-ai/claude-agent-sdk"]), missing: false };
|
|
5544
|
+
if (local.missing) return { id: source.id, installed: null, latest: null, status: "not-installed" };
|
|
5545
|
+
const latest = await deps.registryVersion(source.package).catch(() => null);
|
|
5546
|
+
const installed = local.version;
|
|
5547
|
+
const status = !installed || !latest ? "unknown" : newerVersion(installed, latest) ? "update-available" : "current";
|
|
5548
|
+
return { id: source.id, installed, latest, status };
|
|
5549
|
+
}));
|
|
5550
|
+
return { checkedAt: now, daemonPid: process.pid, agents };
|
|
5551
|
+
}
|
|
5552
|
+
function startAgentVersionChecks(publish, onError, detect = detectAgentVersions) {
|
|
5553
|
+
let stopped = false, pending = false;
|
|
5554
|
+
async function refresh() {
|
|
5555
|
+
if (stopped || pending) return;
|
|
5556
|
+
pending = true;
|
|
5557
|
+
try {
|
|
5558
|
+
const snapshot = await detect();
|
|
5559
|
+
if (!stopped) await publish(snapshot);
|
|
5560
|
+
} catch (error) {
|
|
5561
|
+
onError(error);
|
|
5562
|
+
} finally {
|
|
5563
|
+
pending = false;
|
|
5564
|
+
}
|
|
5565
|
+
}
|
|
5566
|
+
void refresh();
|
|
5567
|
+
const timer = setInterval(() => void refresh(), AGENT_CHECK_INTERVAL);
|
|
5568
|
+
timer.unref();
|
|
5569
|
+
return () => {
|
|
5570
|
+
stopped = true;
|
|
5571
|
+
clearInterval(timer);
|
|
5572
|
+
};
|
|
5573
|
+
}
|
|
5574
|
+
|
|
5322
5575
|
function sanitizeSpawnModel(value) {
|
|
5323
5576
|
if (typeof value !== "string") return null;
|
|
5324
5577
|
return /^[A-Za-z0-9][A-Za-z0-9._:/-]{0,255}(\[1m\])?$/i.test(value) ? value : null;
|
|
@@ -7750,7 +8003,7 @@ function parseJsonObject(text) {
|
|
|
7750
8003
|
return null;
|
|
7751
8004
|
}
|
|
7752
8005
|
}
|
|
7753
|
-
function resolveSdkClaudeBinary(platform = process.platform, arch = process.arch, resolver = (s) => node_module.createRequire((typeof document === 'undefined' ? require('u' + 'rl').pathToFileURL(__filename).href : (_documentCurrentScript && _documentCurrentScript.tagName.toUpperCase() === 'SCRIPT' && _documentCurrentScript.src || new URL('index-
|
|
8006
|
+
function resolveSdkClaudeBinary(platform = process.platform, arch = process.arch, resolver = (s) => node_module.createRequire((typeof document === 'undefined' ? require('u' + 'rl').pathToFileURL(__filename).href : (_documentCurrentScript && _documentCurrentScript.tagName.toUpperCase() === 'SCRIPT' && _documentCurrentScript.src || new URL('index-DNbKbe23.cjs', document.baseURI).href))).resolve(s)) {
|
|
7754
8007
|
const platformArch = `${platform}-${arch}`;
|
|
7755
8008
|
const candidates = [
|
|
7756
8009
|
`@anthropic-ai/claude-agent-sdk-${platformArch}/claude`,
|
|
@@ -10991,6 +11244,10 @@ async function startDaemon() {
|
|
|
10991
11244
|
persistence.logger.warn(`[DAEMON RUN] Ignoring invalid HAPPY_CLI_UPDATE_CHECK_INTERVAL; using ${api.DEFAULT_CLI_UPDATE_CHECK_INTERVAL_MS}ms`);
|
|
10992
11245
|
}
|
|
10993
11246
|
const cliUpdateInterval = setInterval(() => void refreshCliUpdate(), cliUpdateIntervalMs);
|
|
11247
|
+
const stopAgentVersionChecks = startAgentVersionChecks(
|
|
11248
|
+
(snapshot) => apiMachine.updateDaemonState((state) => ({ ...state, status: state?.status ?? "running", agentVersions: snapshot })),
|
|
11249
|
+
(error) => persistence.logger.debug("[DAEMON RUN] Agent version check failed", error)
|
|
11250
|
+
);
|
|
10994
11251
|
const heartbeatIntervalMs = parseInt(process.env.HAPPY_DAEMON_HEARTBEAT_INTERVAL || "60000");
|
|
10995
11252
|
const restartOnStaleVersionAndHeartbeat = setInterval(serialTask(async () => {
|
|
10996
11253
|
try {
|
|
@@ -11031,6 +11288,7 @@ async function startDaemon() {
|
|
|
11031
11288
|
teamWorker?.stop();
|
|
11032
11289
|
clearInterval(restartOnStaleVersionAndHeartbeat);
|
|
11033
11290
|
clearInterval(cliUpdateInterval);
|
|
11291
|
+
stopAgentVersionChecks();
|
|
11034
11292
|
claudeAuthService.stop();
|
|
11035
11293
|
apiMachine.shutdown();
|
|
11036
11294
|
await stopControlServer();
|
|
@@ -11092,6 +11350,7 @@ async function startDaemon() {
|
|
|
11092
11350
|
persistence.logger.debug("[DAEMON RUN] Health check interval cleared");
|
|
11093
11351
|
}
|
|
11094
11352
|
clearInterval(cliUpdateInterval);
|
|
11353
|
+
stopAgentVersionChecks();
|
|
11095
11354
|
await apiMachine.updateDaemonState((state) => ({
|
|
11096
11355
|
...state,
|
|
11097
11356
|
status: "shutting-down",
|
|
@@ -12181,7 +12440,7 @@ function registerSideQuestionHandler(rpc, deps) {
|
|
|
12181
12440
|
const retainMs = deps.retainMs ?? SIDE_QUESTION_RETAIN_MS;
|
|
12182
12441
|
const maxRunMs = deps.maxRunMs ?? SIDE_QUESTION_MAX_RUN_MS;
|
|
12183
12442
|
const run = deps.run ?? (async (input) => {
|
|
12184
|
-
const { query } = await Promise.resolve().then(function () { return require('./index-
|
|
12443
|
+
const { query } = await Promise.resolve().then(function () { return require('./index-DHI6Y1xW.cjs'); });
|
|
12185
12444
|
return runSideQuestion(query, input);
|
|
12186
12445
|
});
|
|
12187
12446
|
const slots = /* @__PURE__ */ new Map();
|
|
@@ -12283,7 +12542,7 @@ const MAX_TITLE_CHARS = 60;
|
|
|
12283
12542
|
const GENERATION_TIMEOUT_MS = 3e4;
|
|
12284
12543
|
function resolveClaudeBinary() {
|
|
12285
12544
|
try {
|
|
12286
|
-
const require$1 = node_module.createRequire((typeof document === 'undefined' ? require('u' + 'rl').pathToFileURL(__filename).href : (_documentCurrentScript && _documentCurrentScript.tagName.toUpperCase() === 'SCRIPT' && _documentCurrentScript.src || new URL('index-
|
|
12545
|
+
const require$1 = node_module.createRequire((typeof document === 'undefined' ? require('u' + 'rl').pathToFileURL(__filename).href : (_documentCurrentScript && _documentCurrentScript.tagName.toUpperCase() === 'SCRIPT' && _documentCurrentScript.src || new URL('index-DNbKbe23.cjs', document.baseURI).href)));
|
|
12287
12546
|
const utilsPath = path.resolve(path.join(api.projectPath(), "scripts", "claude_version_utils.cjs"));
|
|
12288
12547
|
const { getClaudeCliPath } = require$1(utilsPath);
|
|
12289
12548
|
const path$1 = getClaudeCliPath();
|
|
@@ -12744,7 +13003,7 @@ async function runClaude(credentials, options = {}) {
|
|
|
12744
13003
|
// a brand-new session cannot pick a PDF until after sending once.
|
|
12745
13004
|
attachmentKinds: [...CLAUDE_ATTACHMENT_KINDS],
|
|
12746
13005
|
queueCancellation: true,
|
|
12747
|
-
capabilities: ["claude-steer-v1", "claude-live-permission-v1", "claude-live-permission-v2", "claude-btw-v1"],
|
|
13006
|
+
capabilities: ["claude-steer-v1", "claude-live-permission-v1", "claude-live-permission-v2", "claude-btw-v1", "claude-runtime-controls-v1"],
|
|
12748
13007
|
// Effective mode this process enforces. Kept current by
|
|
12749
13008
|
// publishPermissionMode below; the web renders it instead of guessing.
|
|
12750
13009
|
permissionMode: mapToClaudeMode(initialPermissionMode ?? "default"),
|
|
@@ -14501,9 +14760,9 @@ function resolveLocalSignupBootstrap(configuredMode, configuredInviteCodes, gene
|
|
|
14501
14760
|
};
|
|
14502
14761
|
}
|
|
14503
14762
|
|
|
14504
|
-
const __filename$1 = node_url.fileURLToPath((typeof document === 'undefined' ? require('u' + 'rl').pathToFileURL(__filename).href : (_documentCurrentScript && _documentCurrentScript.tagName.toUpperCase() === 'SCRIPT' && _documentCurrentScript.src || new URL('index-
|
|
14763
|
+
const __filename$1 = node_url.fileURLToPath((typeof document === 'undefined' ? require('u' + 'rl').pathToFileURL(__filename).href : (_documentCurrentScript && _documentCurrentScript.tagName.toUpperCase() === 'SCRIPT' && _documentCurrentScript.src || new URL('index-DNbKbe23.cjs', document.baseURI).href)));
|
|
14505
14764
|
const __dirname$1 = path.dirname(__filename$1);
|
|
14506
|
-
const require_ = node_module.createRequire((typeof document === 'undefined' ? require('u' + 'rl').pathToFileURL(__filename).href : (_documentCurrentScript && _documentCurrentScript.tagName.toUpperCase() === 'SCRIPT' && _documentCurrentScript.src || new URL('index-
|
|
14765
|
+
const require_ = node_module.createRequire((typeof document === 'undefined' ? require('u' + 'rl').pathToFileURL(__filename).href : (_documentCurrentScript && _documentCurrentScript.tagName.toUpperCase() === 'SCRIPT' && _documentCurrentScript.src || new URL('index-DNbKbe23.cjs', document.baseURI).href)));
|
|
14507
14766
|
const PRISMA_QUERY_ENGINE_FILES = {
|
|
14508
14767
|
"arm64-darwin": "libquery_engine-darwin-arm64.dylib.node",
|
|
14509
14768
|
"x64-darwin": "libquery_engine-darwin.dylib.node",
|
|
@@ -14925,1269 +15184,1325 @@ async function ensureDaemonRunning() {
|
|
|
14925
15184
|
persistence.logger.debug(`Happy background service did not become ready within ${DAEMON_READY_TIMEOUT_MS}ms; continuing anyway`);
|
|
14926
15185
|
}
|
|
14927
15186
|
|
|
14928
|
-
function
|
|
14929
|
-
|
|
14930
|
-
const attachment = fileEvent.content.data.ev;
|
|
14931
|
-
const download = (async () => {
|
|
14932
|
-
try {
|
|
14933
|
-
const data = await session.downloadAndDecryptAttachment(attachment.ref);
|
|
14934
|
-
if (!data) throw new Error("Attachment decryption failed");
|
|
14935
|
-
return { data, mimeType: attachment.mimeType ?? "image/jpeg", name: attachment.name };
|
|
14936
|
-
} catch {
|
|
14937
|
-
session.sendSessionEvent({ type: "message", message: `Could not download attachment: ${attachment.name}. Please attach it again.` });
|
|
14938
|
-
return null;
|
|
14939
|
-
}
|
|
14940
|
-
})();
|
|
14941
|
-
session.trackAttachmentDownload(download);
|
|
14942
|
-
});
|
|
15187
|
+
function getStartedSubagents(state) {
|
|
15188
|
+
return state.startedSubagents ?? /* @__PURE__ */ new Set();
|
|
14943
15189
|
}
|
|
14944
|
-
|
|
14945
|
-
|
|
14946
|
-
|
|
14947
|
-
|
|
14948
|
-
|
|
14949
|
-
|
|
14950
|
-
|
|
14951
|
-
|
|
15190
|
+
function getActiveSubagents(state) {
|
|
15191
|
+
return state.activeSubagents ?? /* @__PURE__ */ new Set();
|
|
15192
|
+
}
|
|
15193
|
+
function getProviderSubagentToSessionSubagent(state) {
|
|
15194
|
+
return state.providerSubagentToSessionSubagent ?? /* @__PURE__ */ new Map();
|
|
15195
|
+
}
|
|
15196
|
+
function maybeEmitSubagentStart(subagent, opts, startedSubagents, activeSubagents, envelopes) {
|
|
15197
|
+
if (!subagent || startedSubagents.has(subagent)) {
|
|
15198
|
+
return;
|
|
14952
15199
|
}
|
|
14953
|
-
|
|
14954
|
-
|
|
14955
|
-
|
|
14956
|
-
|
|
14957
|
-
|
|
14958
|
-
|
|
14959
|
-
|
|
14960
|
-
|
|
15200
|
+
envelopes.push(api.createEnvelope("agent", { t: "start" }, { ...opts, subagent }));
|
|
15201
|
+
startedSubagents.add(subagent);
|
|
15202
|
+
activeSubagents.add(subagent);
|
|
15203
|
+
}
|
|
15204
|
+
function emitSubagentStops(opts, startedSubagents, activeSubagents) {
|
|
15205
|
+
const envelopes = [];
|
|
15206
|
+
for (const subagent of activeSubagents) {
|
|
15207
|
+
envelopes.push(api.createEnvelope("agent", { t: "stop" }, { ...opts, subagent }));
|
|
14961
15208
|
}
|
|
14962
|
-
|
|
14963
|
-
|
|
14964
|
-
|
|
14965
|
-
|
|
14966
|
-
|
|
14967
|
-
|
|
14968
|
-
|
|
14969
|
-
|
|
14970
|
-
|
|
14971
|
-
|
|
14972
|
-
|
|
14973
|
-
|
|
14974
|
-
|
|
14975
|
-
|
|
14976
|
-
|
|
14977
|
-
|
|
14978
|
-
const request = currentState.requests?.[response.id];
|
|
14979
|
-
if (!request) return currentState;
|
|
14980
|
-
const { [response.id]: _, ...remainingRequests } = currentState.requests || {};
|
|
14981
|
-
let res = {
|
|
14982
|
-
...currentState,
|
|
14983
|
-
requests: remainingRequests,
|
|
14984
|
-
completedRequests: {
|
|
14985
|
-
...currentState.completedRequests,
|
|
14986
|
-
[response.id]: {
|
|
14987
|
-
...request,
|
|
14988
|
-
completedAt: Date.now(),
|
|
14989
|
-
status: response.approved ? "approved" : "denied",
|
|
14990
|
-
decision: result.decision
|
|
14991
|
-
}
|
|
14992
|
-
}
|
|
14993
|
-
};
|
|
14994
|
-
return res;
|
|
14995
|
-
});
|
|
14996
|
-
persistence.logger.debug(`${this.getLogPrefix()} Permission ${response.approved ? "approved" : "denied"} for ${pending.toolName}`);
|
|
14997
|
-
}
|
|
14998
|
-
);
|
|
15209
|
+
activeSubagents.clear();
|
|
15210
|
+
startedSubagents.clear();
|
|
15211
|
+
return envelopes;
|
|
15212
|
+
}
|
|
15213
|
+
function buildEnvelopeOptions(currentTurnId, subagent) {
|
|
15214
|
+
return {
|
|
15215
|
+
...currentTurnId ? { turn: currentTurnId } : {},
|
|
15216
|
+
...subagent ? { subagent } : {}
|
|
15217
|
+
};
|
|
15218
|
+
}
|
|
15219
|
+
function pickProviderSubagent(message) {
|
|
15220
|
+
const candidates = [message.subagent, message.parent_call_id, message.parentCallId];
|
|
15221
|
+
for (const candidate of candidates) {
|
|
15222
|
+
if (typeof candidate === "string" && candidate.length > 0) {
|
|
15223
|
+
return candidate;
|
|
15224
|
+
}
|
|
14999
15225
|
}
|
|
15000
|
-
|
|
15001
|
-
|
|
15002
|
-
|
|
15003
|
-
|
|
15004
|
-
|
|
15005
|
-
|
|
15006
|
-
requests: {
|
|
15007
|
-
...currentState.requests,
|
|
15008
|
-
[toolCallId]: {
|
|
15009
|
-
tool: toolName,
|
|
15010
|
-
arguments: input,
|
|
15011
|
-
createdAt: Date.now()
|
|
15012
|
-
}
|
|
15013
|
-
}
|
|
15014
|
-
}));
|
|
15226
|
+
return void 0;
|
|
15227
|
+
}
|
|
15228
|
+
function resolveSessionSubagent(message, providerSubagentToSessionSubagent) {
|
|
15229
|
+
const providerSubagent = pickProviderSubagent(message);
|
|
15230
|
+
if (!providerSubagent) {
|
|
15231
|
+
return void 0;
|
|
15015
15232
|
}
|
|
15016
|
-
|
|
15017
|
-
|
|
15018
|
-
|
|
15019
|
-
* causing the approval response to send 'cancel' to the provider. This is used when the
|
|
15020
|
-
* user presses the abort/stop button — it unblocks any pending tool approval so the provider
|
|
15021
|
-
* can process the turn cancellation.
|
|
15022
|
-
*/
|
|
15023
|
-
abortAll() {
|
|
15024
|
-
const pendingSnapshot = Array.from(this.pendingRequests.entries());
|
|
15025
|
-
if (pendingSnapshot.length === 0) return;
|
|
15026
|
-
this.pendingRequests.clear();
|
|
15027
|
-
for (const [id, pending] of pendingSnapshot) {
|
|
15028
|
-
try {
|
|
15029
|
-
pending.resolve({ decision: "abort" });
|
|
15030
|
-
} catch (err) {
|
|
15031
|
-
persistence.logger.debug(`${this.getLogPrefix()} Error resolving aborted request ${id}:`, err);
|
|
15032
|
-
}
|
|
15033
|
-
}
|
|
15034
|
-
this.session.updateAgentState((currentState) => {
|
|
15035
|
-
const pendingRequests = currentState.requests || {};
|
|
15036
|
-
const completedRequests = { ...currentState.completedRequests };
|
|
15037
|
-
for (const [id, request] of Object.entries(pendingRequests)) {
|
|
15038
|
-
completedRequests[id] = {
|
|
15039
|
-
...request,
|
|
15040
|
-
completedAt: Date.now(),
|
|
15041
|
-
status: "canceled",
|
|
15042
|
-
reason: "Aborted by user"
|
|
15043
|
-
};
|
|
15044
|
-
}
|
|
15045
|
-
return {
|
|
15046
|
-
...currentState,
|
|
15047
|
-
requests: {},
|
|
15048
|
-
completedRequests
|
|
15049
|
-
};
|
|
15050
|
-
});
|
|
15051
|
-
persistence.logger.debug(`${this.getLogPrefix()} Aborted ${pendingSnapshot.length} pending permission(s)`);
|
|
15052
|
-
}
|
|
15053
|
-
/**
|
|
15054
|
-
* Reset state for new sessions.
|
|
15055
|
-
* This method is idempotent - safe to call multiple times.
|
|
15056
|
-
*/
|
|
15057
|
-
reset(reason = "Session reset") {
|
|
15058
|
-
if (this.isResetting) {
|
|
15059
|
-
persistence.logger.debug(`${this.getLogPrefix()} Reset already in progress, skipping`);
|
|
15060
|
-
return;
|
|
15061
|
-
}
|
|
15062
|
-
this.isResetting = true;
|
|
15063
|
-
try {
|
|
15064
|
-
const pendingSnapshot = Array.from(this.pendingRequests.entries());
|
|
15065
|
-
this.pendingRequests.clear();
|
|
15066
|
-
for (const [id, pending] of pendingSnapshot) {
|
|
15067
|
-
try {
|
|
15068
|
-
pending.reject(new Error("Session reset"));
|
|
15069
|
-
} catch (err) {
|
|
15070
|
-
persistence.logger.debug(`${this.getLogPrefix()} Error rejecting pending request ${id}:`, err);
|
|
15071
|
-
}
|
|
15072
|
-
}
|
|
15073
|
-
this.session.updateAgentState((currentState) => {
|
|
15074
|
-
const pendingRequests = currentState.requests || {};
|
|
15075
|
-
const completedRequests = { ...currentState.completedRequests };
|
|
15076
|
-
for (const [id, request] of Object.entries(pendingRequests)) {
|
|
15077
|
-
completedRequests[id] = {
|
|
15078
|
-
...request,
|
|
15079
|
-
completedAt: Date.now(),
|
|
15080
|
-
status: "canceled",
|
|
15081
|
-
reason
|
|
15082
|
-
};
|
|
15083
|
-
}
|
|
15084
|
-
return {
|
|
15085
|
-
...currentState,
|
|
15086
|
-
requests: {},
|
|
15087
|
-
completedRequests
|
|
15088
|
-
};
|
|
15089
|
-
});
|
|
15090
|
-
persistence.logger.debug(`${this.getLogPrefix()} Permission handler reset`);
|
|
15091
|
-
} finally {
|
|
15092
|
-
this.isResetting = false;
|
|
15093
|
-
}
|
|
15233
|
+
const existing = providerSubagentToSessionSubagent.get(providerSubagent);
|
|
15234
|
+
if (existing) {
|
|
15235
|
+
return existing;
|
|
15094
15236
|
}
|
|
15237
|
+
const created = cuid2.createId();
|
|
15238
|
+
providerSubagentToSessionSubagent.set(providerSubagent, created);
|
|
15239
|
+
return created;
|
|
15095
15240
|
}
|
|
15096
|
-
|
|
15097
|
-
|
|
15098
|
-
|
|
15099
|
-
|
|
15100
|
-
// and the MCP-qualified form for defense in depth.
|
|
15101
|
-
static ALWAYS_AUTO_APPROVE_NAMES = /* @__PURE__ */ new Set([
|
|
15102
|
-
"change_title",
|
|
15103
|
-
"mcp__happy__change_title"
|
|
15104
|
-
]);
|
|
15105
|
-
// Tool-call IDs that should auto-approve when they exactly match one of
|
|
15106
|
-
// these values or start with `<name>-` (e.g. `change_title-1765385846663`).
|
|
15107
|
-
// Substring matching was a bypass vector — any tool whose ID happened to
|
|
15108
|
-
// contain `change_title` as a substring would be silently approved.
|
|
15109
|
-
static ALWAYS_AUTO_APPROVE_ID_PREFIXES = [
|
|
15110
|
-
"change_title"
|
|
15111
|
-
];
|
|
15112
|
-
constructor(session) {
|
|
15113
|
-
super(session);
|
|
15241
|
+
function pickCallId(message) {
|
|
15242
|
+
const callId = message.call_id ?? message.callId;
|
|
15243
|
+
if (typeof callId === "string" && callId.length > 0) {
|
|
15244
|
+
return callId;
|
|
15114
15245
|
}
|
|
15115
|
-
|
|
15116
|
-
|
|
15246
|
+
return node_crypto.randomUUID();
|
|
15247
|
+
}
|
|
15248
|
+
function summarizeCommand(command) {
|
|
15249
|
+
if (typeof command === "string" && command.trim().length > 0) {
|
|
15250
|
+
return command;
|
|
15117
15251
|
}
|
|
15118
|
-
|
|
15119
|
-
|
|
15120
|
-
|
|
15121
|
-
}
|
|
15122
|
-
for (const prefix of CodexPermissionHandler.ALWAYS_AUTO_APPROVE_ID_PREFIXES) {
|
|
15123
|
-
if (toolCallId === prefix || toolCallId.startsWith(`${prefix}-`)) {
|
|
15124
|
-
return true;
|
|
15125
|
-
}
|
|
15126
|
-
}
|
|
15127
|
-
return false;
|
|
15252
|
+
if (Array.isArray(command)) {
|
|
15253
|
+
const cmd = command.map((v) => String(v)).join(" ").trim();
|
|
15254
|
+
return cmd.length > 0 ? cmd : null;
|
|
15128
15255
|
}
|
|
15129
|
-
|
|
15130
|
-
|
|
15131
|
-
|
|
15132
|
-
|
|
15133
|
-
|
|
15134
|
-
* @returns Promise resolving to permission result
|
|
15135
|
-
*/
|
|
15136
|
-
async handleToolCall(toolCallId, toolName, input) {
|
|
15137
|
-
if (this.shouldAutoApprove(toolName, toolCallId)) {
|
|
15138
|
-
persistence.logger.debug(`${this.getLogPrefix()} Auto-approving tool ${toolName} (${toolCallId})`);
|
|
15139
|
-
this.session.updateAgentState((currentState) => ({
|
|
15140
|
-
...currentState,
|
|
15141
|
-
completedRequests: {
|
|
15142
|
-
...currentState.completedRequests,
|
|
15143
|
-
[toolCallId]: {
|
|
15144
|
-
tool: toolName,
|
|
15145
|
-
arguments: input,
|
|
15146
|
-
createdAt: Date.now(),
|
|
15147
|
-
completedAt: Date.now(),
|
|
15148
|
-
status: "approved",
|
|
15149
|
-
decision: "approved"
|
|
15150
|
-
}
|
|
15151
|
-
}
|
|
15152
|
-
}));
|
|
15153
|
-
return { decision: "approved" };
|
|
15154
|
-
}
|
|
15155
|
-
return new Promise((resolve, reject) => {
|
|
15156
|
-
this.pendingRequests.set(toolCallId, {
|
|
15157
|
-
resolve,
|
|
15158
|
-
reject,
|
|
15159
|
-
toolName,
|
|
15160
|
-
input
|
|
15161
|
-
});
|
|
15162
|
-
this.addPendingRequestToState(toolCallId, toolName, input);
|
|
15163
|
-
persistence.logger.debug(`${this.getLogPrefix()} Permission request sent for tool: ${toolName} (${toolCallId})`);
|
|
15164
|
-
});
|
|
15256
|
+
return null;
|
|
15257
|
+
}
|
|
15258
|
+
function commandToTitle(command) {
|
|
15259
|
+
if (!command) {
|
|
15260
|
+
return "Run command";
|
|
15165
15261
|
}
|
|
15262
|
+
const short = command.length > 80 ? `${command.slice(0, 77)}...` : command;
|
|
15263
|
+
return `Run \`${short}\``;
|
|
15166
15264
|
}
|
|
15167
|
-
|
|
15168
|
-
|
|
15169
|
-
|
|
15170
|
-
|
|
15171
|
-
|
|
15172
|
-
|
|
15173
|
-
|
|
15174
|
-
|
|
15175
|
-
|
|
15176
|
-
|
|
15177
|
-
|
|
15178
|
-
constructor(onMessage) {
|
|
15179
|
-
this.onMessage = onMessage || null;
|
|
15180
|
-
this.reset();
|
|
15265
|
+
function turnTimestampMs(turn) {
|
|
15266
|
+
const seconds = turn.startedAt ?? turn.completedAt;
|
|
15267
|
+
return typeof seconds === "number" && Number.isFinite(seconds) ? seconds * 1e3 : Date.now();
|
|
15268
|
+
}
|
|
15269
|
+
function completedTimestampMs(turn) {
|
|
15270
|
+
const seconds = turn.completedAt ?? turn.startedAt;
|
|
15271
|
+
return typeof seconds === "number" && Number.isFinite(seconds) ? seconds * 1e3 : Date.now();
|
|
15272
|
+
}
|
|
15273
|
+
function textFromInputItems(items) {
|
|
15274
|
+
if (!Array.isArray(items)) {
|
|
15275
|
+
return null;
|
|
15181
15276
|
}
|
|
15182
|
-
|
|
15183
|
-
|
|
15184
|
-
|
|
15185
|
-
|
|
15186
|
-
|
|
15277
|
+
const text = items.filter((item) => Boolean(item) && typeof item === "object" && item.type === "text" && typeof item.text === "string").map((item) => item.text).join("\n").trim();
|
|
15278
|
+
return text.length > 0 ? text : null;
|
|
15279
|
+
}
|
|
15280
|
+
function reasoningText(item) {
|
|
15281
|
+
const summary = item.summary;
|
|
15282
|
+
const content = item.content;
|
|
15283
|
+
const parts = [
|
|
15284
|
+
...Array.isArray(summary) ? summary : [],
|
|
15285
|
+
...Array.isArray(content) ? content : []
|
|
15286
|
+
].filter((value) => typeof value === "string" && value.trim().length > 0);
|
|
15287
|
+
const text = parts.join("\n").trim();
|
|
15288
|
+
return text.length > 0 ? text : null;
|
|
15289
|
+
}
|
|
15290
|
+
function turnStatus(turn) {
|
|
15291
|
+
const status = typeof turn.status === "string" ? turn.status : null;
|
|
15292
|
+
if (status === "failed") {
|
|
15293
|
+
return "failed";
|
|
15187
15294
|
}
|
|
15188
|
-
|
|
15189
|
-
|
|
15190
|
-
*/
|
|
15191
|
-
handleSectionBreak() {
|
|
15192
|
-
this.finishCurrentToolCall("canceled");
|
|
15193
|
-
this.resetState();
|
|
15194
|
-
persistence.logger.debug(`${this.getLogPrefix()} Section break - reset state`);
|
|
15295
|
+
if (status === "cancelled" || status === "canceled" || status === "aborted" || status === "interrupted") {
|
|
15296
|
+
return "cancelled";
|
|
15195
15297
|
}
|
|
15196
|
-
|
|
15197
|
-
|
|
15198
|
-
|
|
15199
|
-
|
|
15200
|
-
|
|
15201
|
-
|
|
15202
|
-
|
|
15203
|
-
|
|
15204
|
-
|
|
15205
|
-
|
|
15206
|
-
|
|
15207
|
-
|
|
15208
|
-
|
|
15209
|
-
|
|
15210
|
-
|
|
15211
|
-
|
|
15212
|
-
|
|
15213
|
-
|
|
15214
|
-
|
|
15215
|
-
|
|
15216
|
-
|
|
15217
|
-
|
|
15218
|
-
|
|
15219
|
-
|
|
15220
|
-
|
|
15221
|
-
this.sendToolCallStart(title);
|
|
15222
|
-
}
|
|
15223
|
-
} else if (this.hasTitle) {
|
|
15224
|
-
const titleStartIndex = this.accumulator.indexOf("**");
|
|
15225
|
-
if (titleStartIndex !== -1) {
|
|
15226
|
-
this.contentBuffer = this.accumulator.substring(
|
|
15227
|
-
titleStartIndex + 2 + this.currentTitle.length + 2
|
|
15228
|
-
);
|
|
15229
|
-
}
|
|
15230
|
-
} else {
|
|
15231
|
-
this.contentBuffer = this.accumulator;
|
|
15232
|
-
}
|
|
15298
|
+
return "completed";
|
|
15299
|
+
}
|
|
15300
|
+
function emitHistoricalToolCall(envelopes, turn, item, name, title, args, output) {
|
|
15301
|
+
const time = turnTimestampMs(turn);
|
|
15302
|
+
const opts = { turn: turn.id, time, codexItemId: item.id };
|
|
15303
|
+
envelopes.push(api.createEnvelope("agent", {
|
|
15304
|
+
t: "tool-call-start",
|
|
15305
|
+
call: item.id,
|
|
15306
|
+
name,
|
|
15307
|
+
title,
|
|
15308
|
+
description: title,
|
|
15309
|
+
args
|
|
15310
|
+
}, {
|
|
15311
|
+
...opts,
|
|
15312
|
+
id: `${item.id}:start`
|
|
15313
|
+
}));
|
|
15314
|
+
if (output && output.trim().length > 0) {
|
|
15315
|
+
envelopes.push(api.createEnvelope("agent", {
|
|
15316
|
+
t: "text",
|
|
15317
|
+
text: output,
|
|
15318
|
+
thinking: true
|
|
15319
|
+
}, {
|
|
15320
|
+
...opts,
|
|
15321
|
+
id: `${item.id}:output`
|
|
15322
|
+
}));
|
|
15233
15323
|
}
|
|
15234
|
-
|
|
15235
|
-
|
|
15236
|
-
|
|
15237
|
-
|
|
15238
|
-
|
|
15239
|
-
|
|
15240
|
-
}
|
|
15241
|
-
|
|
15242
|
-
|
|
15243
|
-
|
|
15244
|
-
|
|
15245
|
-
|
|
15246
|
-
|
|
15247
|
-
|
|
15248
|
-
|
|
15249
|
-
|
|
15250
|
-
|
|
15251
|
-
|
|
15252
|
-
|
|
15324
|
+
if ("status" in item && (item.status === "inProgress" || item.status === "running")) return;
|
|
15325
|
+
envelopes.push(api.createEnvelope("agent", {
|
|
15326
|
+
t: "tool-call-end",
|
|
15327
|
+
call: item.id
|
|
15328
|
+
}, {
|
|
15329
|
+
...opts,
|
|
15330
|
+
id: `${item.id}:end`,
|
|
15331
|
+
time: completedTimestampMs(turn)
|
|
15332
|
+
}));
|
|
15333
|
+
}
|
|
15334
|
+
function mapCodexCollaborationItem(item, opts = {}, source = "history") {
|
|
15335
|
+
if (item.type === "subAgentActivity" && typeof item.agentThreadId === "string") {
|
|
15336
|
+
item = { ...item, type: "collabAgentToolCall", tool: item.kind, status: "completed", receiverThreadIds: [item.agentThreadId] };
|
|
15337
|
+
}
|
|
15338
|
+
if (item.type !== "collabAgentToolCall" || typeof item.id !== "string" || typeof item.tool !== "string") return [];
|
|
15339
|
+
const args = {
|
|
15340
|
+
operation: item.tool,
|
|
15341
|
+
...typeof item.prompt === "string" ? { prompt: item.prompt } : {},
|
|
15342
|
+
...typeof item.model === "string" ? { model: item.model } : {},
|
|
15343
|
+
receiverThreadIds: Array.isArray(item.receiverThreadIds) ? item.receiverThreadIds : [],
|
|
15344
|
+
agentsStates: item.agentsStates ?? {}
|
|
15345
|
+
};
|
|
15346
|
+
const startId = source === "live" ? `${item.id}:${item.status ?? "unknown"}:start` : `${item.id}:start`;
|
|
15347
|
+
const envelopes = [api.createEnvelope("agent", {
|
|
15348
|
+
t: "tool-call-start",
|
|
15349
|
+
call: item.id,
|
|
15350
|
+
name: "CodexCollaboration",
|
|
15351
|
+
title: `Codex \xB7 ${item.tool}`,
|
|
15352
|
+
description: `Codex \xB7 ${item.tool}`,
|
|
15353
|
+
args
|
|
15354
|
+
}, { ...opts, id: startId })];
|
|
15355
|
+
if (item.status === "completed" || item.status === "failed" || item.status === "interrupted") {
|
|
15356
|
+
envelopes.push(api.createEnvelope("agent", {
|
|
15357
|
+
t: "tool-call-end",
|
|
15358
|
+
call: item.id,
|
|
15359
|
+
result: { text: JSON.stringify(args, null, 2), isError: item.status !== "completed" }
|
|
15360
|
+
}, { ...opts, id: `${item.id}:end` }));
|
|
15253
15361
|
}
|
|
15254
|
-
|
|
15255
|
-
|
|
15256
|
-
|
|
15257
|
-
|
|
15258
|
-
|
|
15259
|
-
const
|
|
15260
|
-
|
|
15261
|
-
|
|
15262
|
-
|
|
15263
|
-
|
|
15264
|
-
|
|
15265
|
-
|
|
15266
|
-
|
|
15267
|
-
|
|
15268
|
-
|
|
15269
|
-
|
|
15270
|
-
|
|
15362
|
+
return envelopes;
|
|
15363
|
+
}
|
|
15364
|
+
function mapCodexThreadToSessionEnvelopes(thread) {
|
|
15365
|
+
const envelopes = [];
|
|
15366
|
+
for (const turn of thread.turns ?? []) {
|
|
15367
|
+
const startedAt = turnTimestampMs(turn);
|
|
15368
|
+
const completedAt = completedTimestampMs(turn);
|
|
15369
|
+
envelopes.push(api.createEnvelope("agent", { t: "turn-start" }, {
|
|
15370
|
+
id: `${turn.id}:start`,
|
|
15371
|
+
turn: turn.id,
|
|
15372
|
+
time: startedAt
|
|
15373
|
+
}));
|
|
15374
|
+
for (const item of turn.items ?? []) {
|
|
15375
|
+
switch (item.type) {
|
|
15376
|
+
case "subAgentActivity":
|
|
15377
|
+
case "collabAgentToolCall": {
|
|
15378
|
+
envelopes.push(...mapCodexCollaborationItem(item, { turn: turn.id, time: startedAt, codexItemId: item.id }));
|
|
15379
|
+
break;
|
|
15380
|
+
}
|
|
15381
|
+
case "userMessage": {
|
|
15382
|
+
const text = textFromInputItems(item.content);
|
|
15383
|
+
if (text) {
|
|
15384
|
+
envelopes.push(api.createEnvelope("user", { t: "text", text }, {
|
|
15385
|
+
id: item.id,
|
|
15386
|
+
time: startedAt,
|
|
15387
|
+
codexItemId: item.id
|
|
15388
|
+
}));
|
|
15389
|
+
}
|
|
15390
|
+
break;
|
|
15391
|
+
}
|
|
15392
|
+
case "agentMessage": {
|
|
15393
|
+
const text = typeof item.text === "string" ? item.text.trim() : "";
|
|
15394
|
+
if (text.length > 0) {
|
|
15395
|
+
envelopes.push(api.createEnvelope("agent", { t: "text", text }, {
|
|
15396
|
+
id: item.id,
|
|
15397
|
+
turn: turn.id,
|
|
15398
|
+
time: completedAt,
|
|
15399
|
+
codexItemId: item.id
|
|
15400
|
+
}));
|
|
15401
|
+
}
|
|
15402
|
+
break;
|
|
15403
|
+
}
|
|
15404
|
+
case "reasoning": {
|
|
15405
|
+
const text = reasoningText(item);
|
|
15406
|
+
if (text) {
|
|
15407
|
+
envelopes.push(api.createEnvelope("agent", { t: "text", text, thinking: true }, {
|
|
15408
|
+
id: item.id,
|
|
15409
|
+
turn: turn.id,
|
|
15410
|
+
time: startedAt,
|
|
15411
|
+
codexItemId: item.id
|
|
15412
|
+
}));
|
|
15413
|
+
}
|
|
15414
|
+
break;
|
|
15415
|
+
}
|
|
15416
|
+
case "commandExecution": {
|
|
15417
|
+
const command = typeof item.command === "string" ? item.command : "";
|
|
15418
|
+
emitHistoricalToolCall(
|
|
15419
|
+
envelopes,
|
|
15420
|
+
turn,
|
|
15421
|
+
item,
|
|
15422
|
+
"CodexBash",
|
|
15423
|
+
commandToTitle(command),
|
|
15424
|
+
{ command, cwd: item.cwd },
|
|
15425
|
+
typeof item.aggregatedOutput === "string" ? item.aggregatedOutput : null
|
|
15426
|
+
);
|
|
15427
|
+
break;
|
|
15428
|
+
}
|
|
15429
|
+
case "fileChange": {
|
|
15430
|
+
const title = "Apply patch";
|
|
15431
|
+
emitHistoricalToolCall(
|
|
15432
|
+
envelopes,
|
|
15433
|
+
turn,
|
|
15434
|
+
item,
|
|
15435
|
+
"CodexPatch",
|
|
15436
|
+
title,
|
|
15437
|
+
{ changes: item.changes, status: item.status },
|
|
15438
|
+
null
|
|
15439
|
+
);
|
|
15440
|
+
break;
|
|
15441
|
+
}
|
|
15442
|
+
case "mcpToolCall": {
|
|
15443
|
+
const title = `${item.server}.${item.tool}`;
|
|
15444
|
+
const output = item.error !== void 0 && item.error !== null ? String(item.error) : item.result !== void 0 && item.result !== null ? String(item.result) : null;
|
|
15445
|
+
emitHistoricalToolCall(
|
|
15446
|
+
envelopes,
|
|
15447
|
+
turn,
|
|
15448
|
+
item,
|
|
15449
|
+
"McpTool",
|
|
15450
|
+
title,
|
|
15451
|
+
{
|
|
15452
|
+
server: item.server,
|
|
15453
|
+
tool: item.tool,
|
|
15454
|
+
arguments: item.arguments
|
|
15455
|
+
},
|
|
15456
|
+
output
|
|
15457
|
+
);
|
|
15458
|
+
break;
|
|
15459
|
+
}
|
|
15271
15460
|
}
|
|
15272
15461
|
}
|
|
15273
|
-
|
|
15274
|
-
|
|
15275
|
-
|
|
15276
|
-
|
|
15277
|
-
}
|
|
15278
|
-
if (this.toolCallStarted && this.currentCallId) {
|
|
15279
|
-
const toolResult = {
|
|
15280
|
-
type: "tool-call-result",
|
|
15281
|
-
callId: this.currentCallId,
|
|
15282
|
-
output: {
|
|
15283
|
-
content,
|
|
15284
|
-
status: "completed"
|
|
15285
|
-
},
|
|
15286
|
-
id: node_crypto.randomUUID()
|
|
15287
|
-
};
|
|
15288
|
-
persistence.logger.debug(`${this.getLogPrefix()} Sending tool call result`);
|
|
15289
|
-
this.onMessage?.(toolResult);
|
|
15290
|
-
} else if (content.trim()) {
|
|
15291
|
-
const reasoningMessage = {
|
|
15292
|
-
type: "reasoning",
|
|
15293
|
-
message: content,
|
|
15294
|
-
id: node_crypto.randomUUID()
|
|
15295
|
-
};
|
|
15296
|
-
persistence.logger.debug(`${this.getLogPrefix()} Sending reasoning message`);
|
|
15297
|
-
this.onMessage?.(reasoningMessage);
|
|
15298
|
-
}
|
|
15299
|
-
this.resetState();
|
|
15300
|
-
return true;
|
|
15301
|
-
}
|
|
15302
|
-
/**
|
|
15303
|
-
* Abort the current reasoning section.
|
|
15304
|
-
*/
|
|
15305
|
-
abort() {
|
|
15306
|
-
persistence.logger.debug(`${this.getLogPrefix()} Abort called`);
|
|
15307
|
-
this.finishCurrentToolCall("canceled");
|
|
15308
|
-
this.resetState();
|
|
15309
|
-
}
|
|
15310
|
-
/**
|
|
15311
|
-
* Reset the processor state.
|
|
15312
|
-
*/
|
|
15313
|
-
reset() {
|
|
15314
|
-
this.finishCurrentToolCall("canceled");
|
|
15315
|
-
this.resetState();
|
|
15316
|
-
}
|
|
15317
|
-
/**
|
|
15318
|
-
* Finish current tool call if one is in progress.
|
|
15319
|
-
*/
|
|
15320
|
-
finishCurrentToolCall(status) {
|
|
15321
|
-
if (this.toolCallStarted && this.currentCallId) {
|
|
15322
|
-
const toolResult = {
|
|
15323
|
-
type: "tool-call-result",
|
|
15324
|
-
callId: this.currentCallId,
|
|
15325
|
-
output: {
|
|
15326
|
-
content: this.contentBuffer || "",
|
|
15327
|
-
status
|
|
15328
|
-
},
|
|
15329
|
-
id: node_crypto.randomUUID()
|
|
15330
|
-
};
|
|
15331
|
-
persistence.logger.debug(`${this.getLogPrefix()} Sending tool call result with status: ${status}`);
|
|
15332
|
-
this.onMessage?.(toolResult);
|
|
15333
|
-
}
|
|
15334
|
-
}
|
|
15335
|
-
/**
|
|
15336
|
-
* Reset internal state.
|
|
15337
|
-
*/
|
|
15338
|
-
resetState() {
|
|
15339
|
-
this.accumulator = "";
|
|
15340
|
-
this.inTitleCapture = false;
|
|
15341
|
-
this.titleBuffer = "";
|
|
15342
|
-
this.contentBuffer = "";
|
|
15343
|
-
this.hasTitle = false;
|
|
15344
|
-
this.currentCallId = null;
|
|
15345
|
-
this.toolCallStarted = false;
|
|
15346
|
-
this.currentTitle = null;
|
|
15462
|
+
envelopes.push(api.createEnvelope("agent", { t: "turn-end", status: turnStatus(turn) }, {
|
|
15463
|
+
id: `${turn.id}:end`,
|
|
15464
|
+
turn: turn.id,
|
|
15465
|
+
time: completedAt
|
|
15466
|
+
}));
|
|
15347
15467
|
}
|
|
15348
|
-
|
|
15349
|
-
|
|
15350
|
-
|
|
15351
|
-
|
|
15352
|
-
return
|
|
15468
|
+
return envelopes;
|
|
15469
|
+
}
|
|
15470
|
+
function patchDescription(changes) {
|
|
15471
|
+
if (!changes || typeof changes !== "object") {
|
|
15472
|
+
return "Applying patch";
|
|
15353
15473
|
}
|
|
15354
|
-
|
|
15355
|
-
|
|
15356
|
-
|
|
15357
|
-
hasStartedToolCall() {
|
|
15358
|
-
return this.toolCallStarted;
|
|
15474
|
+
const fileCount = Object.keys(changes).length;
|
|
15475
|
+
if (fileCount === 1) {
|
|
15476
|
+
return "Applying patch to 1 file";
|
|
15359
15477
|
}
|
|
15478
|
+
return `Applying patch to ${fileCount} files`;
|
|
15360
15479
|
}
|
|
15361
|
-
|
|
15362
|
-
|
|
15363
|
-
|
|
15364
|
-
return
|
|
15480
|
+
function pickTurnEndStatus(message, type) {
|
|
15481
|
+
const rawStatus = message.status;
|
|
15482
|
+
if (rawStatus === "completed" || rawStatus === "failed" || rawStatus === "cancelled") {
|
|
15483
|
+
return rawStatus;
|
|
15365
15484
|
}
|
|
15366
|
-
|
|
15367
|
-
return "
|
|
15485
|
+
if (rawStatus === "canceled") {
|
|
15486
|
+
return "cancelled";
|
|
15368
15487
|
}
|
|
15369
|
-
|
|
15370
|
-
|
|
15371
|
-
|
|
15372
|
-
|
|
15373
|
-
|
|
15488
|
+
if (type === "turn_aborted") {
|
|
15489
|
+
const reason = message.reason;
|
|
15490
|
+
const error = message.error;
|
|
15491
|
+
if (typeof reason === "string" && /(fail|error)/i.test(reason) || typeof error === "string" && error.length > 0 || error !== void 0 && error !== null && typeof error === "object") {
|
|
15492
|
+
return "failed";
|
|
15493
|
+
}
|
|
15494
|
+
return "cancelled";
|
|
15374
15495
|
}
|
|
15375
|
-
|
|
15376
|
-
|
|
15377
|
-
*/
|
|
15378
|
-
complete(fullText) {
|
|
15379
|
-
this.completeReasoning(fullText);
|
|
15496
|
+
if (message.error !== void 0 && message.error !== null) {
|
|
15497
|
+
return "failed";
|
|
15380
15498
|
}
|
|
15499
|
+
return "completed";
|
|
15381
15500
|
}
|
|
15382
|
-
|
|
15383
|
-
|
|
15384
|
-
|
|
15385
|
-
|
|
15386
|
-
|
|
15387
|
-
|
|
15501
|
+
function mapCodexMcpMessageToSessionEnvelopes(message, state) {
|
|
15502
|
+
const type = message.type;
|
|
15503
|
+
const startedSubagents = getStartedSubagents(state);
|
|
15504
|
+
const activeSubagents = getActiveSubagents(state);
|
|
15505
|
+
const providerSubagentToSessionSubagent = getProviderSubagentToSessionSubagent(state);
|
|
15506
|
+
if (type === "collab_agent_item") {
|
|
15507
|
+
return {
|
|
15508
|
+
currentTurnId: state.currentTurnId,
|
|
15509
|
+
startedSubagents,
|
|
15510
|
+
activeSubagents,
|
|
15511
|
+
providerSubagentToSessionSubagent,
|
|
15512
|
+
envelopes: mapCodexCollaborationItem(message.item, buildEnvelopeOptions(state.currentTurnId), "live")
|
|
15513
|
+
};
|
|
15388
15514
|
}
|
|
15389
|
-
|
|
15390
|
-
|
|
15391
|
-
|
|
15392
|
-
|
|
15393
|
-
|
|
15394
|
-
|
|
15395
|
-
|
|
15396
|
-
|
|
15397
|
-
|
|
15398
|
-
|
|
15399
|
-
|
|
15400
|
-
|
|
15401
|
-
|
|
15402
|
-
|
|
15403
|
-
|
|
15515
|
+
if (type === "task_started") {
|
|
15516
|
+
const turnId = cuid2.createId();
|
|
15517
|
+
const turnStart = api.createEnvelope("agent", { t: "turn-start" }, { turn: turnId });
|
|
15518
|
+
startedSubagents.clear();
|
|
15519
|
+
activeSubagents.clear();
|
|
15520
|
+
providerSubagentToSessionSubagent.clear();
|
|
15521
|
+
return {
|
|
15522
|
+
currentTurnId: turnId,
|
|
15523
|
+
startedSubagents,
|
|
15524
|
+
activeSubagents,
|
|
15525
|
+
providerSubagentToSessionSubagent,
|
|
15526
|
+
envelopes: [turnStart]
|
|
15527
|
+
};
|
|
15528
|
+
}
|
|
15529
|
+
if (type === "task_complete" || type === "turn_aborted") {
|
|
15530
|
+
if (!state.currentTurnId) {
|
|
15531
|
+
return {
|
|
15532
|
+
currentTurnId: null,
|
|
15533
|
+
startedSubagents,
|
|
15534
|
+
activeSubagents,
|
|
15535
|
+
providerSubagentToSessionSubagent,
|
|
15536
|
+
envelopes: []
|
|
15404
15537
|
};
|
|
15405
|
-
|
|
15406
|
-
|
|
15407
|
-
|
|
15408
|
-
|
|
15409
|
-
|
|
15410
|
-
|
|
15411
|
-
|
|
15412
|
-
|
|
15538
|
+
}
|
|
15539
|
+
const lifecycleOpts = { turn: state.currentTurnId };
|
|
15540
|
+
providerSubagentToSessionSubagent.clear();
|
|
15541
|
+
return {
|
|
15542
|
+
currentTurnId: null,
|
|
15543
|
+
startedSubagents,
|
|
15544
|
+
activeSubagents,
|
|
15545
|
+
providerSubagentToSessionSubagent,
|
|
15546
|
+
envelopes: [
|
|
15547
|
+
...emitSubagentStops(lifecycleOpts, startedSubagents, activeSubagents),
|
|
15548
|
+
api.createEnvelope("agent", {
|
|
15549
|
+
t: "turn-end",
|
|
15550
|
+
status: pickTurnEndStatus(message, type)
|
|
15551
|
+
}, lifecycleOpts)
|
|
15552
|
+
]
|
|
15553
|
+
};
|
|
15554
|
+
}
|
|
15555
|
+
if (type === "token_count") {
|
|
15556
|
+
return {
|
|
15557
|
+
currentTurnId: state.currentTurnId,
|
|
15558
|
+
startedSubagents,
|
|
15559
|
+
activeSubagents,
|
|
15560
|
+
providerSubagentToSessionSubagent,
|
|
15561
|
+
envelopes: []
|
|
15562
|
+
};
|
|
15563
|
+
}
|
|
15564
|
+
const subagent = resolveSessionSubagent(message, providerSubagentToSessionSubagent);
|
|
15565
|
+
const opts = buildEnvelopeOptions(state.currentTurnId, subagent);
|
|
15566
|
+
if (type === "agent_message") {
|
|
15567
|
+
if (typeof message.message !== "string") {
|
|
15568
|
+
return {
|
|
15569
|
+
currentTurnId: state.currentTurnId,
|
|
15570
|
+
startedSubagents,
|
|
15571
|
+
activeSubagents,
|
|
15572
|
+
providerSubagentToSessionSubagent,
|
|
15573
|
+
envelopes: []
|
|
15413
15574
|
};
|
|
15414
|
-
this.onMessage?.(toolResult);
|
|
15415
15575
|
}
|
|
15416
|
-
|
|
15417
|
-
|
|
15576
|
+
const envelopes = [];
|
|
15577
|
+
maybeEmitSubagentStart(subagent, opts, startedSubagents, activeSubagents, envelopes);
|
|
15578
|
+
envelopes.push(api.createEnvelope("agent", { t: "text", text: message.message }, opts));
|
|
15579
|
+
return {
|
|
15580
|
+
currentTurnId: state.currentTurnId,
|
|
15581
|
+
startedSubagents,
|
|
15582
|
+
activeSubagents,
|
|
15583
|
+
providerSubagentToSessionSubagent,
|
|
15584
|
+
envelopes
|
|
15585
|
+
};
|
|
15418
15586
|
}
|
|
15419
|
-
|
|
15420
|
-
|
|
15421
|
-
|
|
15422
|
-
|
|
15423
|
-
|
|
15424
|
-
|
|
15587
|
+
if (type === "agent_reasoning" || type === "agent_reasoning_delta") {
|
|
15588
|
+
const text = typeof message.text === "string" ? message.text : typeof message.delta === "string" ? message.delta : null;
|
|
15589
|
+
if (!text) {
|
|
15590
|
+
return {
|
|
15591
|
+
currentTurnId: state.currentTurnId,
|
|
15592
|
+
startedSubagents,
|
|
15593
|
+
activeSubagents,
|
|
15594
|
+
providerSubagentToSessionSubagent,
|
|
15595
|
+
envelopes: []
|
|
15596
|
+
};
|
|
15597
|
+
}
|
|
15598
|
+
const envelopes = [];
|
|
15599
|
+
maybeEmitSubagentStart(subagent, opts, startedSubagents, activeSubagents, envelopes);
|
|
15600
|
+
envelopes.push(api.createEnvelope("agent", { t: "text", text, thinking: true }, opts));
|
|
15601
|
+
return {
|
|
15602
|
+
currentTurnId: state.currentTurnId,
|
|
15603
|
+
startedSubagents,
|
|
15604
|
+
activeSubagents,
|
|
15605
|
+
providerSubagentToSessionSubagent,
|
|
15606
|
+
envelopes
|
|
15607
|
+
};
|
|
15425
15608
|
}
|
|
15426
|
-
|
|
15427
|
-
|
|
15428
|
-
|
|
15429
|
-
|
|
15430
|
-
|
|
15609
|
+
if (type === "exec_command_begin") {
|
|
15610
|
+
const call = pickCallId(message);
|
|
15611
|
+
const { call_id: _callIdSnake, callId: _callIdCamel, type: _type, ...args } = message;
|
|
15612
|
+
const command = summarizeCommand(args.command);
|
|
15613
|
+
const description = typeof args.description === "string" ? args.description : command ?? "Execute command";
|
|
15614
|
+
const envelopes = [];
|
|
15615
|
+
maybeEmitSubagentStart(subagent, opts, startedSubagents, activeSubagents, envelopes);
|
|
15616
|
+
envelopes.push(
|
|
15617
|
+
api.createEnvelope("agent", {
|
|
15618
|
+
t: "tool-call-start",
|
|
15619
|
+
call,
|
|
15620
|
+
name: "CodexBash",
|
|
15621
|
+
title: commandToTitle(command),
|
|
15622
|
+
description,
|
|
15623
|
+
args
|
|
15624
|
+
}, opts)
|
|
15625
|
+
);
|
|
15626
|
+
return {
|
|
15627
|
+
currentTurnId: state.currentTurnId,
|
|
15628
|
+
startedSubagents,
|
|
15629
|
+
activeSubagents,
|
|
15630
|
+
providerSubagentToSessionSubagent,
|
|
15631
|
+
envelopes
|
|
15632
|
+
};
|
|
15431
15633
|
}
|
|
15432
|
-
|
|
15433
|
-
|
|
15434
|
-
|
|
15435
|
-
|
|
15436
|
-
|
|
15634
|
+
if (type === "exec_command_end") {
|
|
15635
|
+
const call = pickCallId(message);
|
|
15636
|
+
const envelopes = [];
|
|
15637
|
+
maybeEmitSubagentStart(subagent, opts, startedSubagents, activeSubagents, envelopes);
|
|
15638
|
+
envelopes.push(api.createEnvelope("agent", { t: "tool-call-end", call }, opts));
|
|
15639
|
+
return {
|
|
15640
|
+
currentTurnId: state.currentTurnId,
|
|
15641
|
+
startedSubagents,
|
|
15642
|
+
activeSubagents,
|
|
15643
|
+
providerSubagentToSessionSubagent,
|
|
15644
|
+
envelopes
|
|
15645
|
+
};
|
|
15646
|
+
}
|
|
15647
|
+
if (type === "patch_apply_begin") {
|
|
15648
|
+
const call = pickCallId(message);
|
|
15649
|
+
const autoApproved = message.auto_approved;
|
|
15650
|
+
const changes = message.changes;
|
|
15651
|
+
const envelopes = [];
|
|
15652
|
+
maybeEmitSubagentStart(subagent, opts, startedSubagents, activeSubagents, envelopes);
|
|
15653
|
+
envelopes.push(
|
|
15654
|
+
api.createEnvelope("agent", {
|
|
15655
|
+
t: "tool-call-start",
|
|
15656
|
+
call,
|
|
15657
|
+
name: "CodexPatch",
|
|
15658
|
+
title: "Apply patch",
|
|
15659
|
+
description: patchDescription(changes),
|
|
15660
|
+
args: {
|
|
15661
|
+
auto_approved: autoApproved,
|
|
15662
|
+
changes
|
|
15663
|
+
}
|
|
15664
|
+
}, opts)
|
|
15665
|
+
);
|
|
15666
|
+
return {
|
|
15667
|
+
currentTurnId: state.currentTurnId,
|
|
15668
|
+
startedSubagents,
|
|
15669
|
+
activeSubagents,
|
|
15670
|
+
providerSubagentToSessionSubagent,
|
|
15671
|
+
envelopes
|
|
15672
|
+
};
|
|
15673
|
+
}
|
|
15674
|
+
if (type === "patch_apply_end") {
|
|
15675
|
+
const call = pickCallId(message);
|
|
15676
|
+
const envelopes = [];
|
|
15677
|
+
maybeEmitSubagentStart(subagent, opts, startedSubagents, activeSubagents, envelopes);
|
|
15678
|
+
envelopes.push(api.createEnvelope("agent", { t: "tool-call-end", call }, opts));
|
|
15679
|
+
return {
|
|
15680
|
+
currentTurnId: state.currentTurnId,
|
|
15681
|
+
startedSubagents,
|
|
15682
|
+
activeSubagents,
|
|
15683
|
+
providerSubagentToSessionSubagent,
|
|
15684
|
+
envelopes
|
|
15685
|
+
};
|
|
15686
|
+
}
|
|
15687
|
+
return {
|
|
15688
|
+
currentTurnId: state.currentTurnId,
|
|
15689
|
+
startedSubagents,
|
|
15690
|
+
activeSubagents,
|
|
15691
|
+
providerSubagentToSessionSubagent,
|
|
15692
|
+
envelopes: []
|
|
15693
|
+
};
|
|
15694
|
+
}
|
|
15695
|
+
function mapCodexProcessorMessageToSessionEnvelopes(message, state) {
|
|
15696
|
+
const toolLikeMessage = message;
|
|
15697
|
+
const opts = buildEnvelopeOptions(state.currentTurnId);
|
|
15698
|
+
if (message.type === "reasoning") {
|
|
15699
|
+
return [api.createEnvelope("agent", {
|
|
15700
|
+
t: "text",
|
|
15701
|
+
text: message.message,
|
|
15702
|
+
thinking: true
|
|
15703
|
+
}, opts)];
|
|
15704
|
+
}
|
|
15705
|
+
if (message.type === "tool-call") {
|
|
15706
|
+
const title = typeof toolLikeMessage.input?.title === "string" ? toolLikeMessage.input.title : `${toolLikeMessage.name || "Tool"} call`;
|
|
15707
|
+
return [api.createEnvelope("agent", {
|
|
15708
|
+
t: "tool-call-start",
|
|
15709
|
+
call: toolLikeMessage.callId,
|
|
15710
|
+
name: toolLikeMessage.name || "unknown",
|
|
15711
|
+
title,
|
|
15712
|
+
description: title,
|
|
15713
|
+
args: toolLikeMessage.input && typeof toolLikeMessage.input === "object" ? toolLikeMessage.input : {}
|
|
15714
|
+
}, opts)];
|
|
15715
|
+
}
|
|
15716
|
+
if (message.type === "tool-call-result") {
|
|
15717
|
+
const envelopes = [];
|
|
15718
|
+
const content = toolLikeMessage.output?.content;
|
|
15719
|
+
if (typeof content === "string" && content.trim().length > 0) {
|
|
15720
|
+
envelopes.push(api.createEnvelope("agent", {
|
|
15721
|
+
t: "text",
|
|
15722
|
+
text: content,
|
|
15723
|
+
thinking: true
|
|
15724
|
+
}, opts));
|
|
15725
|
+
}
|
|
15726
|
+
envelopes.push(api.createEnvelope("agent", {
|
|
15727
|
+
t: "tool-call-end",
|
|
15728
|
+
call: toolLikeMessage.callId
|
|
15729
|
+
}, opts));
|
|
15730
|
+
return envelopes;
|
|
15437
15731
|
}
|
|
15732
|
+
return [];
|
|
15438
15733
|
}
|
|
15439
15734
|
|
|
15440
|
-
|
|
15441
|
-
|
|
15442
|
-
const
|
|
15443
|
-
const
|
|
15444
|
-
const
|
|
15445
|
-
|
|
15446
|
-
const
|
|
15447
|
-
|
|
15448
|
-
|
|
15449
|
-
|
|
15450
|
-
|
|
15451
|
-
|
|
15452
|
-
|
|
15453
|
-
|
|
15454
|
-
|
|
15455
|
-
|
|
15456
|
-
|
|
15735
|
+
async function readChildThread(client, childId) {
|
|
15736
|
+
if (!client.threadId || typeof childId !== "string" || !childId) throw new Error("Invalid child thread");
|
|
15737
|
+
const parentId = client.threadId;
|
|
15738
|
+
const { thread: parent } = await client.readThread({ threadId: parentId, includeTurns: true });
|
|
15739
|
+
const belongs = parent.id === parentId && parent.turns?.some((turn) => turn.items.some((item) => item.type === "collabAgentToolCall" && Array.isArray(item.receiverThreadIds) && item.receiverThreadIds.includes(childId) || item.type === "subAgentActivity" && item.agentThreadId === childId));
|
|
15740
|
+
if (!belongs) throw new Error("Thread is not a child of this session");
|
|
15741
|
+
const { thread } = await client.readThread({ threadId: childId, includeTurns: true });
|
|
15742
|
+
if (thread.id !== childId) throw new Error("Child thread mismatch");
|
|
15743
|
+
return { envelopes: mapCodexThreadToSessionEnvelopes(thread) };
|
|
15744
|
+
}
|
|
15745
|
+
|
|
15746
|
+
function registerAgentAttachmentDownloads(session) {
|
|
15747
|
+
session.onFileEvent((fileEvent) => {
|
|
15748
|
+
const attachment = fileEvent.content.data.ev;
|
|
15749
|
+
const download = (async () => {
|
|
15750
|
+
try {
|
|
15751
|
+
const data = await session.downloadAndDecryptAttachment(attachment.ref);
|
|
15752
|
+
if (!data) throw new Error("Attachment decryption failed");
|
|
15753
|
+
return { data, mimeType: attachment.mimeType ?? "image/jpeg", name: attachment.name };
|
|
15754
|
+
} catch {
|
|
15755
|
+
session.sendSessionEvent({ type: "message", message: `Could not download attachment: ${attachment.name}. Please attach it again.` });
|
|
15756
|
+
return null;
|
|
15457
15757
|
}
|
|
15458
|
-
};
|
|
15459
|
-
|
|
15460
|
-
|
|
15461
|
-
|
|
15462
|
-
|
|
15463
|
-
|
|
15464
|
-
|
|
15465
|
-
|
|
15466
|
-
|
|
15467
|
-
|
|
15468
|
-
|
|
15469
|
-
|
|
15470
|
-
|
|
15471
|
-
|
|
15472
|
-
|
|
15473
|
-
|
|
15474
|
-
|
|
15475
|
-
|
|
15476
|
-
|
|
15477
|
-
|
|
15478
|
-
|
|
15479
|
-
|
|
15480
|
-
|
|
15481
|
-
|
|
15482
|
-
|
|
15483
|
-
|
|
15484
|
-
|
|
15485
|
-
|
|
15758
|
+
})();
|
|
15759
|
+
session.trackAttachmentDownload(download);
|
|
15760
|
+
});
|
|
15761
|
+
}
|
|
15762
|
+
|
|
15763
|
+
class BasePermissionHandler {
|
|
15764
|
+
pendingRequests = /* @__PURE__ */ new Map();
|
|
15765
|
+
session;
|
|
15766
|
+
isResetting = false;
|
|
15767
|
+
constructor(session) {
|
|
15768
|
+
this.session = session;
|
|
15769
|
+
this.setupRpcHandler();
|
|
15770
|
+
}
|
|
15771
|
+
/**
|
|
15772
|
+
* Update the session reference (used after offline reconnection swaps sessions).
|
|
15773
|
+
* This is critical for avoiding stale session references after onSessionSwap.
|
|
15774
|
+
*/
|
|
15775
|
+
updateSession(newSession) {
|
|
15776
|
+
persistence.logger.debug(`${this.getLogPrefix()} Session reference updated`);
|
|
15777
|
+
this.session = newSession;
|
|
15778
|
+
this.setupRpcHandler();
|
|
15779
|
+
}
|
|
15780
|
+
/**
|
|
15781
|
+
* Setup RPC handler for permission responses.
|
|
15782
|
+
*/
|
|
15783
|
+
setupRpcHandler() {
|
|
15784
|
+
this.session.rpcHandlerManager.registerHandler(
|
|
15785
|
+
"permission",
|
|
15786
|
+
async (response) => {
|
|
15787
|
+
const pending = this.pendingRequests.get(response.id);
|
|
15788
|
+
if (!pending) {
|
|
15789
|
+
persistence.logger.debug(`${this.getLogPrefix()} Permission request not found or already resolved`);
|
|
15790
|
+
return;
|
|
15791
|
+
}
|
|
15792
|
+
this.pendingRequests.delete(response.id);
|
|
15793
|
+
const result = response.approved ? { decision: response.decision === "approved_for_session" ? "approved_for_session" : "approved" } : { decision: response.decision === "denied" ? "denied" : "abort" };
|
|
15794
|
+
pending.resolve(result);
|
|
15795
|
+
this.session.updateAgentState((currentState) => {
|
|
15796
|
+
const request = currentState.requests?.[response.id];
|
|
15797
|
+
if (!request) return currentState;
|
|
15798
|
+
const { [response.id]: _, ...remainingRequests } = currentState.requests || {};
|
|
15799
|
+
let res = {
|
|
15800
|
+
...currentState,
|
|
15801
|
+
requests: remainingRequests,
|
|
15802
|
+
completedRequests: {
|
|
15803
|
+
...currentState.completedRequests,
|
|
15804
|
+
[response.id]: {
|
|
15805
|
+
...request,
|
|
15806
|
+
completedAt: Date.now(),
|
|
15807
|
+
status: response.approved ? "approved" : "denied",
|
|
15808
|
+
decision: result.decision
|
|
15809
|
+
}
|
|
15810
|
+
}
|
|
15811
|
+
};
|
|
15812
|
+
return res;
|
|
15813
|
+
});
|
|
15814
|
+
persistence.logger.debug(`${this.getLogPrefix()} Permission ${response.approved ? "approved" : "denied"} for ${pending.toolName}`);
|
|
15486
15815
|
}
|
|
15487
|
-
|
|
15488
|
-
|
|
15489
|
-
|
|
15490
|
-
|
|
15491
|
-
|
|
15492
|
-
|
|
15493
|
-
|
|
15494
|
-
|
|
15495
|
-
|
|
15496
|
-
|
|
15497
|
-
|
|
15498
|
-
|
|
15499
|
-
|
|
15500
|
-
|
|
15501
|
-
|
|
15502
|
-
return "yellow";
|
|
15503
|
-
case "result":
|
|
15504
|
-
return "green";
|
|
15505
|
-
case "status":
|
|
15506
|
-
return "gray";
|
|
15507
|
-
default:
|
|
15508
|
-
return "white";
|
|
15509
|
-
}
|
|
15510
|
-
};
|
|
15511
|
-
const formatMessage = (msg) => {
|
|
15512
|
-
const lines = msg.content.split("\n");
|
|
15513
|
-
const maxLineLength = terminalWidth - 10;
|
|
15514
|
-
return lines.map((line) => {
|
|
15515
|
-
if (line.length <= maxLineLength) return line;
|
|
15516
|
-
const chunks = [];
|
|
15517
|
-
for (let i = 0; i < line.length; i += maxLineLength) {
|
|
15518
|
-
chunks.push(line.slice(i, i + maxLineLength));
|
|
15816
|
+
);
|
|
15817
|
+
}
|
|
15818
|
+
/**
|
|
15819
|
+
* Add a pending request to the agent state.
|
|
15820
|
+
*/
|
|
15821
|
+
addPendingRequestToState(toolCallId, toolName, input) {
|
|
15822
|
+
this.session.updateAgentState((currentState) => ({
|
|
15823
|
+
...currentState,
|
|
15824
|
+
requests: {
|
|
15825
|
+
...currentState.requests,
|
|
15826
|
+
[toolCallId]: {
|
|
15827
|
+
tool: toolName,
|
|
15828
|
+
arguments: input,
|
|
15829
|
+
createdAt: Date.now()
|
|
15830
|
+
}
|
|
15519
15831
|
}
|
|
15520
|
-
|
|
15521
|
-
|
|
15522
|
-
|
|
15523
|
-
|
|
15524
|
-
|
|
15525
|
-
|
|
15526
|
-
|
|
15527
|
-
|
|
15528
|
-
|
|
15529
|
-
|
|
15530
|
-
|
|
15531
|
-
|
|
15532
|
-
|
|
15533
|
-
|
|
15534
|
-
|
|
15535
|
-
|
|
15536
|
-
|
|
15537
|
-
|
|
15538
|
-
))
|
|
15539
|
-
), /* @__PURE__ */ React.createElement(
|
|
15540
|
-
ink.Box,
|
|
15541
|
-
{
|
|
15542
|
-
width: terminalWidth,
|
|
15543
|
-
borderStyle: "round",
|
|
15544
|
-
borderColor: actionInProgress ? "gray" : confirmationMode ? "red" : "green",
|
|
15545
|
-
paddingX: 2,
|
|
15546
|
-
justifyContent: "center",
|
|
15547
|
-
alignItems: "center",
|
|
15548
|
-
flexDirection: "column"
|
|
15549
|
-
},
|
|
15550
|
-
/* @__PURE__ */ React.createElement(ink.Box, { flexDirection: "column", alignItems: "center" }, actionInProgress ? /* @__PURE__ */ React.createElement(ink.Text, { color: "gray", bold: true }, "Exiting agent...") : confirmationMode ? /* @__PURE__ */ React.createElement(ink.Text, { color: "red", bold: true }, "\u26A0\uFE0F Press Ctrl-C again to exit the agent") : /* @__PURE__ */ React.createElement(React.Fragment, null, /* @__PURE__ */ React.createElement(ink.Text, { color: "green", bold: true }, "\u{1F916} Codex Agent Running \u2022 Ctrl-C to exit")), process.env.DEBUG && logPath && /* @__PURE__ */ React.createElement(ink.Text, { color: "gray", dimColor: true }, "Debug logs: ", logPath))
|
|
15551
|
-
));
|
|
15552
|
-
};
|
|
15553
|
-
|
|
15554
|
-
function createOfflineSessionStub(sessionTag) {
|
|
15555
|
-
return {
|
|
15556
|
-
sessionId: `offline-${sessionTag}`,
|
|
15557
|
-
sendCodexMessage: () => {
|
|
15558
|
-
},
|
|
15559
|
-
sendAgentMessage: () => {
|
|
15560
|
-
},
|
|
15561
|
-
sendAgentUsageSnapshot: () => false,
|
|
15562
|
-
sendClaudeSessionMessage: () => {
|
|
15563
|
-
},
|
|
15564
|
-
keepAlive: () => {
|
|
15565
|
-
},
|
|
15566
|
-
sendSessionEvent: () => {
|
|
15567
|
-
},
|
|
15568
|
-
sendSessionDeath: () => {
|
|
15569
|
-
},
|
|
15570
|
-
updateLifecycleState: () => {
|
|
15571
|
-
},
|
|
15572
|
-
requestControlTransfer: async () => {
|
|
15573
|
-
},
|
|
15574
|
-
flush: async () => {
|
|
15575
|
-
},
|
|
15576
|
-
close: async () => {
|
|
15577
|
-
},
|
|
15578
|
-
updateMetadata: () => {
|
|
15579
|
-
},
|
|
15580
|
-
updateAgentState: () => {
|
|
15581
|
-
},
|
|
15582
|
-
onUserMessage: () => {
|
|
15583
|
-
},
|
|
15584
|
-
onFileEvent: () => {
|
|
15585
|
-
},
|
|
15586
|
-
trackAttachmentDownload: () => {
|
|
15587
|
-
},
|
|
15588
|
-
drainAttachmentsForUserMessage: async () => [],
|
|
15589
|
-
rpcHandlerManager: {
|
|
15590
|
-
registerHandler: () => {
|
|
15832
|
+
}));
|
|
15833
|
+
}
|
|
15834
|
+
/**
|
|
15835
|
+
* Abort all pending permission requests.
|
|
15836
|
+
* Unlike reset(), this resolves (not rejects) pending promises with { decision: 'abort' },
|
|
15837
|
+
* causing the approval response to send 'cancel' to the provider. This is used when the
|
|
15838
|
+
* user presses the abort/stop button — it unblocks any pending tool approval so the provider
|
|
15839
|
+
* can process the turn cancellation.
|
|
15840
|
+
*/
|
|
15841
|
+
abortAll() {
|
|
15842
|
+
const pendingSnapshot = Array.from(this.pendingRequests.entries());
|
|
15843
|
+
if (pendingSnapshot.length === 0) return;
|
|
15844
|
+
this.pendingRequests.clear();
|
|
15845
|
+
for (const [id, pending] of pendingSnapshot) {
|
|
15846
|
+
try {
|
|
15847
|
+
pending.resolve({ decision: "abort" });
|
|
15848
|
+
} catch (err) {
|
|
15849
|
+
persistence.logger.debug(`${this.getLogPrefix()} Error resolving aborted request ${id}:`, err);
|
|
15591
15850
|
}
|
|
15592
15851
|
}
|
|
15593
|
-
|
|
15594
|
-
}
|
|
15595
|
-
|
|
15596
|
-
|
|
15597
|
-
|
|
15598
|
-
|
|
15599
|
-
|
|
15600
|
-
|
|
15601
|
-
|
|
15602
|
-
|
|
15603
|
-
serverUrl: persistence.configuration.serverUrl,
|
|
15604
|
-
onReconnected: async () => {
|
|
15605
|
-
const resp = await api$1.getOrCreateSession({ tag: sessionTag, metadata, state });
|
|
15606
|
-
if (!resp) throw new Error("Server unavailable");
|
|
15607
|
-
const realSession = api$1.sessionSyncClient(resp);
|
|
15608
|
-
onSessionSwap(realSession);
|
|
15609
|
-
return realSession;
|
|
15610
|
-
},
|
|
15611
|
-
onNotify: (msg) => {
|
|
15612
|
-
console.log(msg);
|
|
15852
|
+
this.session.updateAgentState((currentState) => {
|
|
15853
|
+
const pendingRequests = currentState.requests || {};
|
|
15854
|
+
const completedRequests = { ...currentState.completedRequests };
|
|
15855
|
+
for (const [id, request] of Object.entries(pendingRequests)) {
|
|
15856
|
+
completedRequests[id] = {
|
|
15857
|
+
...request,
|
|
15858
|
+
completedAt: Date.now(),
|
|
15859
|
+
status: "canceled",
|
|
15860
|
+
reason: "Aborted by user"
|
|
15861
|
+
};
|
|
15613
15862
|
}
|
|
15863
|
+
return {
|
|
15864
|
+
...currentState,
|
|
15865
|
+
requests: {},
|
|
15866
|
+
completedRequests
|
|
15867
|
+
};
|
|
15614
15868
|
});
|
|
15615
|
-
|
|
15616
|
-
} else {
|
|
15617
|
-
session = api$1.sessionSyncClient(response, opts.sessionClientOptions);
|
|
15618
|
-
return { session, reconnectionHandle: null, isOffline: false };
|
|
15619
|
-
}
|
|
15620
|
-
}
|
|
15621
|
-
|
|
15622
|
-
function resolveCodexExecutionPolicy(permissionMode, sandboxManagedByHappy) {
|
|
15623
|
-
if (sandboxManagedByHappy) {
|
|
15624
|
-
return {
|
|
15625
|
-
approvalPolicy: "never",
|
|
15626
|
-
sandbox: "danger-full-access"
|
|
15627
|
-
};
|
|
15869
|
+
persistence.logger.debug(`${this.getLogPrefix()} Aborted ${pendingSnapshot.length} pending permission(s)`);
|
|
15628
15870
|
}
|
|
15629
|
-
|
|
15630
|
-
|
|
15631
|
-
|
|
15632
|
-
|
|
15633
|
-
|
|
15634
|
-
|
|
15635
|
-
|
|
15636
|
-
|
|
15637
|
-
// Never ask, read-only enforced by sandbox
|
|
15638
|
-
case "safe-yolo":
|
|
15639
|
-
return "on-request";
|
|
15640
|
-
// Workspace auto-run; request approval for escalation (0.153 removed on-failure)
|
|
15641
|
-
case "yolo":
|
|
15642
|
-
return "never";
|
|
15643
|
-
// Full YOLO: never interrupt for approvals
|
|
15644
|
-
// Defensive fallback for Claude-specific modes (backward compatibility)
|
|
15645
|
-
case "bypassPermissions":
|
|
15646
|
-
return "never";
|
|
15647
|
-
// Full access: map to yolo behavior
|
|
15648
|
-
case "acceptEdits":
|
|
15649
|
-
return "on-request";
|
|
15650
|
-
// Let model decide (closest to auto-approve edits)
|
|
15651
|
-
case "plan":
|
|
15652
|
-
return "untrusted";
|
|
15653
|
-
// Conservative: ask for non-trusted
|
|
15654
|
-
default:
|
|
15655
|
-
return "untrusted";
|
|
15871
|
+
/**
|
|
15872
|
+
* Reset state for new sessions.
|
|
15873
|
+
* This method is idempotent - safe to call multiple times.
|
|
15874
|
+
*/
|
|
15875
|
+
reset(reason = "Session reset") {
|
|
15876
|
+
if (this.isResetting) {
|
|
15877
|
+
persistence.logger.debug(`${this.getLogPrefix()} Reset already in progress, skipping`);
|
|
15878
|
+
return;
|
|
15656
15879
|
}
|
|
15657
|
-
|
|
15658
|
-
|
|
15659
|
-
|
|
15660
|
-
|
|
15661
|
-
|
|
15662
|
-
|
|
15663
|
-
|
|
15664
|
-
|
|
15665
|
-
|
|
15666
|
-
|
|
15667
|
-
|
|
15668
|
-
|
|
15669
|
-
|
|
15670
|
-
|
|
15671
|
-
|
|
15672
|
-
|
|
15673
|
-
|
|
15674
|
-
|
|
15675
|
-
|
|
15676
|
-
|
|
15677
|
-
|
|
15678
|
-
|
|
15679
|
-
|
|
15680
|
-
|
|
15681
|
-
|
|
15682
|
-
|
|
15683
|
-
|
|
15684
|
-
|
|
15880
|
+
this.isResetting = true;
|
|
15881
|
+
try {
|
|
15882
|
+
const pendingSnapshot = Array.from(this.pendingRequests.entries());
|
|
15883
|
+
this.pendingRequests.clear();
|
|
15884
|
+
for (const [id, pending] of pendingSnapshot) {
|
|
15885
|
+
try {
|
|
15886
|
+
pending.reject(new Error("Session reset"));
|
|
15887
|
+
} catch (err) {
|
|
15888
|
+
persistence.logger.debug(`${this.getLogPrefix()} Error rejecting pending request ${id}:`, err);
|
|
15889
|
+
}
|
|
15890
|
+
}
|
|
15891
|
+
this.session.updateAgentState((currentState) => {
|
|
15892
|
+
const pendingRequests = currentState.requests || {};
|
|
15893
|
+
const completedRequests = { ...currentState.completedRequests };
|
|
15894
|
+
for (const [id, request] of Object.entries(pendingRequests)) {
|
|
15895
|
+
completedRequests[id] = {
|
|
15896
|
+
...request,
|
|
15897
|
+
completedAt: Date.now(),
|
|
15898
|
+
status: "canceled",
|
|
15899
|
+
reason
|
|
15900
|
+
};
|
|
15901
|
+
}
|
|
15902
|
+
return {
|
|
15903
|
+
...currentState,
|
|
15904
|
+
requests: {},
|
|
15905
|
+
completedRequests
|
|
15906
|
+
};
|
|
15907
|
+
});
|
|
15908
|
+
persistence.logger.debug(`${this.getLogPrefix()} Permission handler reset`);
|
|
15909
|
+
} finally {
|
|
15910
|
+
this.isResetting = false;
|
|
15685
15911
|
}
|
|
15686
|
-
}
|
|
15687
|
-
return { approvalPolicy, sandbox };
|
|
15912
|
+
}
|
|
15688
15913
|
}
|
|
15689
15914
|
|
|
15690
|
-
|
|
15691
|
-
|
|
15692
|
-
|
|
15693
|
-
|
|
15694
|
-
|
|
15695
|
-
|
|
15696
|
-
|
|
15697
|
-
|
|
15698
|
-
|
|
15699
|
-
|
|
15700
|
-
|
|
15701
|
-
|
|
15915
|
+
class CodexPermissionHandler extends BasePermissionHandler {
|
|
15916
|
+
// Exact tool names that should always be auto-approved. Include the bare
|
|
15917
|
+
// form (used by Codex elicitation messages like `tool "change_title"`)
|
|
15918
|
+
// and the MCP-qualified form for defense in depth.
|
|
15919
|
+
static ALWAYS_AUTO_APPROVE_NAMES = /* @__PURE__ */ new Set([
|
|
15920
|
+
"change_title",
|
|
15921
|
+
"mcp__happy__change_title"
|
|
15922
|
+
]);
|
|
15923
|
+
// Tool-call IDs that should auto-approve when they exactly match one of
|
|
15924
|
+
// these values or start with `<name>-` (e.g. `change_title-1765385846663`).
|
|
15925
|
+
// Substring matching was a bypass vector — any tool whose ID happened to
|
|
15926
|
+
// contain `change_title` as a substring would be silently approved.
|
|
15927
|
+
static ALWAYS_AUTO_APPROVE_ID_PREFIXES = [
|
|
15928
|
+
"change_title"
|
|
15929
|
+
];
|
|
15930
|
+
constructor(session) {
|
|
15931
|
+
super(session);
|
|
15702
15932
|
}
|
|
15703
|
-
|
|
15704
|
-
|
|
15705
|
-
activeSubagents.add(subagent);
|
|
15706
|
-
}
|
|
15707
|
-
function emitSubagentStops(opts, startedSubagents, activeSubagents) {
|
|
15708
|
-
const envelopes = [];
|
|
15709
|
-
for (const subagent of activeSubagents) {
|
|
15710
|
-
envelopes.push(api.createEnvelope("agent", { t: "stop" }, { ...opts, subagent }));
|
|
15933
|
+
getLogPrefix() {
|
|
15934
|
+
return "[Codex]";
|
|
15711
15935
|
}
|
|
15712
|
-
|
|
15713
|
-
|
|
15714
|
-
|
|
15715
|
-
}
|
|
15716
|
-
function buildEnvelopeOptions(currentTurnId, subagent) {
|
|
15717
|
-
return {
|
|
15718
|
-
...currentTurnId ? { turn: currentTurnId } : {},
|
|
15719
|
-
...subagent ? { subagent } : {}
|
|
15720
|
-
};
|
|
15721
|
-
}
|
|
15722
|
-
function pickProviderSubagent(message) {
|
|
15723
|
-
const candidates = [message.subagent, message.parent_call_id, message.parentCallId];
|
|
15724
|
-
for (const candidate of candidates) {
|
|
15725
|
-
if (typeof candidate === "string" && candidate.length > 0) {
|
|
15726
|
-
return candidate;
|
|
15936
|
+
shouldAutoApprove(toolName, toolCallId) {
|
|
15937
|
+
if (CodexPermissionHandler.ALWAYS_AUTO_APPROVE_NAMES.has(toolName)) {
|
|
15938
|
+
return true;
|
|
15727
15939
|
}
|
|
15940
|
+
for (const prefix of CodexPermissionHandler.ALWAYS_AUTO_APPROVE_ID_PREFIXES) {
|
|
15941
|
+
if (toolCallId === prefix || toolCallId.startsWith(`${prefix}-`)) {
|
|
15942
|
+
return true;
|
|
15943
|
+
}
|
|
15944
|
+
}
|
|
15945
|
+
return false;
|
|
15728
15946
|
}
|
|
15729
|
-
|
|
15730
|
-
|
|
15731
|
-
|
|
15732
|
-
|
|
15733
|
-
|
|
15734
|
-
|
|
15735
|
-
|
|
15736
|
-
|
|
15737
|
-
|
|
15738
|
-
|
|
15947
|
+
/**
|
|
15948
|
+
* Handle a tool permission request
|
|
15949
|
+
* @param toolCallId - The unique ID of the tool call
|
|
15950
|
+
* @param toolName - The name of the tool being called
|
|
15951
|
+
* @param input - The input parameters for the tool
|
|
15952
|
+
* @returns Promise resolving to permission result
|
|
15953
|
+
*/
|
|
15954
|
+
async handleToolCall(toolCallId, toolName, input) {
|
|
15955
|
+
if (this.shouldAutoApprove(toolName, toolCallId)) {
|
|
15956
|
+
persistence.logger.debug(`${this.getLogPrefix()} Auto-approving tool ${toolName} (${toolCallId})`);
|
|
15957
|
+
this.session.updateAgentState((currentState) => ({
|
|
15958
|
+
...currentState,
|
|
15959
|
+
completedRequests: {
|
|
15960
|
+
...currentState.completedRequests,
|
|
15961
|
+
[toolCallId]: {
|
|
15962
|
+
tool: toolName,
|
|
15963
|
+
arguments: input,
|
|
15964
|
+
createdAt: Date.now(),
|
|
15965
|
+
completedAt: Date.now(),
|
|
15966
|
+
status: "approved",
|
|
15967
|
+
decision: "approved"
|
|
15968
|
+
}
|
|
15969
|
+
}
|
|
15970
|
+
}));
|
|
15971
|
+
return { decision: "approved" };
|
|
15972
|
+
}
|
|
15973
|
+
return new Promise((resolve, reject) => {
|
|
15974
|
+
this.pendingRequests.set(toolCallId, {
|
|
15975
|
+
resolve,
|
|
15976
|
+
reject,
|
|
15977
|
+
toolName,
|
|
15978
|
+
input
|
|
15979
|
+
});
|
|
15980
|
+
this.addPendingRequestToState(toolCallId, toolName, input);
|
|
15981
|
+
persistence.logger.debug(`${this.getLogPrefix()} Permission request sent for tool: ${toolName} (${toolCallId})`);
|
|
15982
|
+
});
|
|
15739
15983
|
}
|
|
15740
|
-
const created = cuid2.createId();
|
|
15741
|
-
providerSubagentToSessionSubagent.set(providerSubagent, created);
|
|
15742
|
-
return created;
|
|
15743
15984
|
}
|
|
15744
|
-
|
|
15745
|
-
|
|
15746
|
-
|
|
15747
|
-
|
|
15985
|
+
|
|
15986
|
+
class BaseReasoningProcessor {
|
|
15987
|
+
accumulator = "";
|
|
15988
|
+
inTitleCapture = false;
|
|
15989
|
+
titleBuffer = "";
|
|
15990
|
+
contentBuffer = "";
|
|
15991
|
+
hasTitle = false;
|
|
15992
|
+
currentCallId = null;
|
|
15993
|
+
toolCallStarted = false;
|
|
15994
|
+
currentTitle = null;
|
|
15995
|
+
onMessage = null;
|
|
15996
|
+
constructor(onMessage) {
|
|
15997
|
+
this.onMessage = onMessage || null;
|
|
15998
|
+
this.reset();
|
|
15748
15999
|
}
|
|
15749
|
-
|
|
15750
|
-
|
|
15751
|
-
|
|
15752
|
-
|
|
15753
|
-
|
|
16000
|
+
/**
|
|
16001
|
+
* Set the message callback for sending messages directly.
|
|
16002
|
+
*/
|
|
16003
|
+
setMessageCallback(callback) {
|
|
16004
|
+
this.onMessage = callback;
|
|
15754
16005
|
}
|
|
15755
|
-
|
|
15756
|
-
|
|
15757
|
-
|
|
16006
|
+
/**
|
|
16007
|
+
* Process a reasoning section break - indicates a new reasoning section is starting.
|
|
16008
|
+
*/
|
|
16009
|
+
handleSectionBreak() {
|
|
16010
|
+
this.finishCurrentToolCall("canceled");
|
|
16011
|
+
this.resetState();
|
|
16012
|
+
persistence.logger.debug(`${this.getLogPrefix()} Section break - reset state`);
|
|
15758
16013
|
}
|
|
15759
|
-
|
|
15760
|
-
|
|
15761
|
-
|
|
15762
|
-
|
|
15763
|
-
|
|
16014
|
+
/**
|
|
16015
|
+
* Process a reasoning delta/chunk and accumulate content.
|
|
16016
|
+
*/
|
|
16017
|
+
processInput(input) {
|
|
16018
|
+
this.accumulator += input;
|
|
16019
|
+
if (!this.inTitleCapture && !this.hasTitle && !this.contentBuffer) {
|
|
16020
|
+
if (this.accumulator.startsWith("**")) {
|
|
16021
|
+
this.inTitleCapture = true;
|
|
16022
|
+
this.titleBuffer = this.accumulator.substring(2);
|
|
16023
|
+
persistence.logger.debug(`${this.getLogPrefix()} Started title capture`);
|
|
16024
|
+
} else if (this.accumulator.length > 0) {
|
|
16025
|
+
this.contentBuffer = this.accumulator;
|
|
16026
|
+
}
|
|
16027
|
+
} else if (this.inTitleCapture) {
|
|
16028
|
+
this.titleBuffer = this.accumulator.substring(2);
|
|
16029
|
+
const titleEndIndex = this.titleBuffer.indexOf("**");
|
|
16030
|
+
if (titleEndIndex !== -1) {
|
|
16031
|
+
const title = this.titleBuffer.substring(0, titleEndIndex);
|
|
16032
|
+
const afterTitle = this.titleBuffer.substring(titleEndIndex + 2);
|
|
16033
|
+
this.hasTitle = true;
|
|
16034
|
+
this.inTitleCapture = false;
|
|
16035
|
+
this.currentTitle = title;
|
|
16036
|
+
this.contentBuffer = afterTitle;
|
|
16037
|
+
this.currentCallId = node_crypto.randomUUID();
|
|
16038
|
+
persistence.logger.debug(`${this.getLogPrefix()} Title captured: "${title}"`);
|
|
16039
|
+
this.sendToolCallStart(title);
|
|
16040
|
+
}
|
|
16041
|
+
} else if (this.hasTitle) {
|
|
16042
|
+
const titleStartIndex = this.accumulator.indexOf("**");
|
|
16043
|
+
if (titleStartIndex !== -1) {
|
|
16044
|
+
this.contentBuffer = this.accumulator.substring(
|
|
16045
|
+
titleStartIndex + 2 + this.currentTitle.length + 2
|
|
16046
|
+
);
|
|
16047
|
+
}
|
|
16048
|
+
} else {
|
|
16049
|
+
this.contentBuffer = this.accumulator;
|
|
16050
|
+
}
|
|
15764
16051
|
}
|
|
15765
|
-
|
|
15766
|
-
|
|
15767
|
-
|
|
15768
|
-
|
|
15769
|
-
|
|
15770
|
-
|
|
15771
|
-
}
|
|
15772
|
-
|
|
15773
|
-
|
|
15774
|
-
|
|
15775
|
-
|
|
15776
|
-
|
|
15777
|
-
|
|
15778
|
-
|
|
16052
|
+
/**
|
|
16053
|
+
* Send the tool call start message.
|
|
16054
|
+
*/
|
|
16055
|
+
sendToolCallStart(title) {
|
|
16056
|
+
if (!this.currentCallId || this.toolCallStarted) {
|
|
16057
|
+
return;
|
|
16058
|
+
}
|
|
16059
|
+
const toolCall = {
|
|
16060
|
+
type: "tool-call",
|
|
16061
|
+
name: this.getToolName(),
|
|
16062
|
+
callId: this.currentCallId,
|
|
16063
|
+
input: {
|
|
16064
|
+
title
|
|
16065
|
+
},
|
|
16066
|
+
id: node_crypto.randomUUID()
|
|
16067
|
+
};
|
|
16068
|
+
persistence.logger.debug(`${this.getLogPrefix()} Sending tool call start for: "${title}"`);
|
|
16069
|
+
this.onMessage?.(toolCall);
|
|
16070
|
+
this.toolCallStarted = true;
|
|
15779
16071
|
}
|
|
15780
|
-
|
|
15781
|
-
|
|
15782
|
-
|
|
15783
|
-
|
|
15784
|
-
|
|
15785
|
-
|
|
15786
|
-
|
|
15787
|
-
|
|
15788
|
-
|
|
15789
|
-
|
|
15790
|
-
|
|
15791
|
-
|
|
15792
|
-
|
|
15793
|
-
|
|
15794
|
-
|
|
15795
|
-
|
|
15796
|
-
|
|
16072
|
+
/**
|
|
16073
|
+
* Complete the reasoning section.
|
|
16074
|
+
* Returns true if reasoning was completed, false if there was nothing to complete.
|
|
16075
|
+
*/
|
|
16076
|
+
completeReasoning(fullText) {
|
|
16077
|
+
const text = fullText ?? this.accumulator;
|
|
16078
|
+
if (!text.trim() && !this.toolCallStarted) {
|
|
16079
|
+
persistence.logger.debug(`${this.getLogPrefix()} Complete called but no content accumulated, skipping`);
|
|
16080
|
+
return false;
|
|
16081
|
+
}
|
|
16082
|
+
let title;
|
|
16083
|
+
let content = text;
|
|
16084
|
+
if (text.startsWith("**")) {
|
|
16085
|
+
const titleEndIndex = text.indexOf("**", 2);
|
|
16086
|
+
if (titleEndIndex !== -1) {
|
|
16087
|
+
title = text.substring(2, titleEndIndex);
|
|
16088
|
+
content = text.substring(titleEndIndex + 2).trim();
|
|
16089
|
+
}
|
|
16090
|
+
}
|
|
16091
|
+
persistence.logger.debug(`${this.getLogPrefix()} Complete reasoning - Title: "${title}", Has content: ${content.length > 0}`);
|
|
16092
|
+
if (title && !this.toolCallStarted) {
|
|
16093
|
+
this.currentCallId = this.currentCallId || node_crypto.randomUUID();
|
|
16094
|
+
this.sendToolCallStart(title);
|
|
16095
|
+
}
|
|
16096
|
+
if (this.toolCallStarted && this.currentCallId) {
|
|
16097
|
+
const toolResult = {
|
|
16098
|
+
type: "tool-call-result",
|
|
16099
|
+
callId: this.currentCallId,
|
|
16100
|
+
output: {
|
|
16101
|
+
content,
|
|
16102
|
+
status: "completed"
|
|
16103
|
+
},
|
|
16104
|
+
id: node_crypto.randomUUID()
|
|
16105
|
+
};
|
|
16106
|
+
persistence.logger.debug(`${this.getLogPrefix()} Sending tool call result`);
|
|
16107
|
+
this.onMessage?.(toolResult);
|
|
16108
|
+
} else if (content.trim()) {
|
|
16109
|
+
const reasoningMessage = {
|
|
16110
|
+
type: "reasoning",
|
|
16111
|
+
message: content,
|
|
16112
|
+
id: node_crypto.randomUUID()
|
|
16113
|
+
};
|
|
16114
|
+
persistence.logger.debug(`${this.getLogPrefix()} Sending reasoning message`);
|
|
16115
|
+
this.onMessage?.(reasoningMessage);
|
|
16116
|
+
}
|
|
16117
|
+
this.resetState();
|
|
16118
|
+
return true;
|
|
15797
16119
|
}
|
|
15798
|
-
|
|
15799
|
-
|
|
16120
|
+
/**
|
|
16121
|
+
* Abort the current reasoning section.
|
|
16122
|
+
*/
|
|
16123
|
+
abort() {
|
|
16124
|
+
persistence.logger.debug(`${this.getLogPrefix()} Abort called`);
|
|
16125
|
+
this.finishCurrentToolCall("canceled");
|
|
16126
|
+
this.resetState();
|
|
15800
16127
|
}
|
|
15801
|
-
|
|
15802
|
-
|
|
15803
|
-
|
|
15804
|
-
|
|
15805
|
-
|
|
15806
|
-
|
|
15807
|
-
t: "tool-call-start",
|
|
15808
|
-
call: item.id,
|
|
15809
|
-
name,
|
|
15810
|
-
title,
|
|
15811
|
-
description: title,
|
|
15812
|
-
args
|
|
15813
|
-
}, {
|
|
15814
|
-
...opts,
|
|
15815
|
-
id: `${item.id}:start`
|
|
15816
|
-
}));
|
|
15817
|
-
if (output && output.trim().length > 0) {
|
|
15818
|
-
envelopes.push(api.createEnvelope("agent", {
|
|
15819
|
-
t: "text",
|
|
15820
|
-
text: output,
|
|
15821
|
-
thinking: true
|
|
15822
|
-
}, {
|
|
15823
|
-
...opts,
|
|
15824
|
-
id: `${item.id}:output`
|
|
15825
|
-
}));
|
|
16128
|
+
/**
|
|
16129
|
+
* Reset the processor state.
|
|
16130
|
+
*/
|
|
16131
|
+
reset() {
|
|
16132
|
+
this.finishCurrentToolCall("canceled");
|
|
16133
|
+
this.resetState();
|
|
15826
16134
|
}
|
|
15827
|
-
|
|
15828
|
-
|
|
15829
|
-
|
|
15830
|
-
|
|
15831
|
-
|
|
15832
|
-
|
|
15833
|
-
|
|
15834
|
-
|
|
15835
|
-
|
|
15836
|
-
|
|
15837
|
-
|
|
15838
|
-
|
|
15839
|
-
|
|
15840
|
-
|
|
15841
|
-
|
|
15842
|
-
|
|
15843
|
-
turn: turn.id,
|
|
15844
|
-
time: startedAt
|
|
15845
|
-
}));
|
|
15846
|
-
for (const item of turn.items ?? []) {
|
|
15847
|
-
switch (item.type) {
|
|
15848
|
-
case "userMessage": {
|
|
15849
|
-
const text = textFromInputItems(item.content);
|
|
15850
|
-
if (text) {
|
|
15851
|
-
envelopes.push(api.createEnvelope("user", { t: "text", text }, {
|
|
15852
|
-
id: item.id,
|
|
15853
|
-
time: startedAt,
|
|
15854
|
-
codexItemId: item.id
|
|
15855
|
-
}));
|
|
15856
|
-
}
|
|
15857
|
-
break;
|
|
15858
|
-
}
|
|
15859
|
-
case "agentMessage": {
|
|
15860
|
-
const text = typeof item.text === "string" ? item.text.trim() : "";
|
|
15861
|
-
if (text.length > 0) {
|
|
15862
|
-
envelopes.push(api.createEnvelope("agent", { t: "text", text }, {
|
|
15863
|
-
id: item.id,
|
|
15864
|
-
turn: turn.id,
|
|
15865
|
-
time: completedAt,
|
|
15866
|
-
codexItemId: item.id
|
|
15867
|
-
}));
|
|
15868
|
-
}
|
|
15869
|
-
break;
|
|
15870
|
-
}
|
|
15871
|
-
case "reasoning": {
|
|
15872
|
-
const text = reasoningText(item);
|
|
15873
|
-
if (text) {
|
|
15874
|
-
envelopes.push(api.createEnvelope("agent", { t: "text", text, thinking: true }, {
|
|
15875
|
-
id: item.id,
|
|
15876
|
-
turn: turn.id,
|
|
15877
|
-
time: startedAt,
|
|
15878
|
-
codexItemId: item.id
|
|
15879
|
-
}));
|
|
15880
|
-
}
|
|
15881
|
-
break;
|
|
15882
|
-
}
|
|
15883
|
-
case "commandExecution": {
|
|
15884
|
-
const command = typeof item.command === "string" ? item.command : "";
|
|
15885
|
-
emitHistoricalToolCall(
|
|
15886
|
-
envelopes,
|
|
15887
|
-
turn,
|
|
15888
|
-
item,
|
|
15889
|
-
"CodexBash",
|
|
15890
|
-
commandToTitle(command),
|
|
15891
|
-
{ command, cwd: item.cwd },
|
|
15892
|
-
typeof item.aggregatedOutput === "string" ? item.aggregatedOutput : null
|
|
15893
|
-
);
|
|
15894
|
-
break;
|
|
15895
|
-
}
|
|
15896
|
-
case "fileChange": {
|
|
15897
|
-
const title = "Apply patch";
|
|
15898
|
-
emitHistoricalToolCall(
|
|
15899
|
-
envelopes,
|
|
15900
|
-
turn,
|
|
15901
|
-
item,
|
|
15902
|
-
"CodexPatch",
|
|
15903
|
-
title,
|
|
15904
|
-
{ changes: item.changes, status: item.status },
|
|
15905
|
-
null
|
|
15906
|
-
);
|
|
15907
|
-
break;
|
|
15908
|
-
}
|
|
15909
|
-
case "mcpToolCall": {
|
|
15910
|
-
const title = `${item.server}.${item.tool}`;
|
|
15911
|
-
const output = item.error !== void 0 && item.error !== null ? String(item.error) : item.result !== void 0 && item.result !== null ? String(item.result) : null;
|
|
15912
|
-
emitHistoricalToolCall(
|
|
15913
|
-
envelopes,
|
|
15914
|
-
turn,
|
|
15915
|
-
item,
|
|
15916
|
-
"McpTool",
|
|
15917
|
-
title,
|
|
15918
|
-
{
|
|
15919
|
-
server: item.server,
|
|
15920
|
-
tool: item.tool,
|
|
15921
|
-
arguments: item.arguments
|
|
15922
|
-
},
|
|
15923
|
-
output
|
|
15924
|
-
);
|
|
15925
|
-
break;
|
|
15926
|
-
}
|
|
15927
|
-
}
|
|
16135
|
+
/**
|
|
16136
|
+
* Finish current tool call if one is in progress.
|
|
16137
|
+
*/
|
|
16138
|
+
finishCurrentToolCall(status) {
|
|
16139
|
+
if (this.toolCallStarted && this.currentCallId) {
|
|
16140
|
+
const toolResult = {
|
|
16141
|
+
type: "tool-call-result",
|
|
16142
|
+
callId: this.currentCallId,
|
|
16143
|
+
output: {
|
|
16144
|
+
content: this.contentBuffer || "",
|
|
16145
|
+
status
|
|
16146
|
+
},
|
|
16147
|
+
id: node_crypto.randomUUID()
|
|
16148
|
+
};
|
|
16149
|
+
persistence.logger.debug(`${this.getLogPrefix()} Sending tool call result with status: ${status}`);
|
|
16150
|
+
this.onMessage?.(toolResult);
|
|
15928
16151
|
}
|
|
15929
|
-
envelopes.push(api.createEnvelope("agent", { t: "turn-end", status: turnStatus(turn) }, {
|
|
15930
|
-
id: `${turn.id}:end`,
|
|
15931
|
-
turn: turn.id,
|
|
15932
|
-
time: completedAt
|
|
15933
|
-
}));
|
|
15934
16152
|
}
|
|
15935
|
-
|
|
15936
|
-
|
|
15937
|
-
|
|
15938
|
-
|
|
15939
|
-
|
|
16153
|
+
/**
|
|
16154
|
+
* Reset internal state.
|
|
16155
|
+
*/
|
|
16156
|
+
resetState() {
|
|
16157
|
+
this.accumulator = "";
|
|
16158
|
+
this.inTitleCapture = false;
|
|
16159
|
+
this.titleBuffer = "";
|
|
16160
|
+
this.contentBuffer = "";
|
|
16161
|
+
this.hasTitle = false;
|
|
16162
|
+
this.currentCallId = null;
|
|
16163
|
+
this.toolCallStarted = false;
|
|
16164
|
+
this.currentTitle = null;
|
|
15940
16165
|
}
|
|
15941
|
-
|
|
15942
|
-
|
|
15943
|
-
|
|
16166
|
+
/**
|
|
16167
|
+
* Get the current call ID for tool result matching.
|
|
16168
|
+
*/
|
|
16169
|
+
getCurrentCallId() {
|
|
16170
|
+
return this.currentCallId;
|
|
16171
|
+
}
|
|
16172
|
+
/**
|
|
16173
|
+
* Check if a tool call has been started.
|
|
16174
|
+
*/
|
|
16175
|
+
hasStartedToolCall() {
|
|
16176
|
+
return this.toolCallStarted;
|
|
15944
16177
|
}
|
|
15945
|
-
return `Applying patch to ${fileCount} files`;
|
|
15946
16178
|
}
|
|
15947
|
-
|
|
15948
|
-
|
|
15949
|
-
|
|
15950
|
-
return
|
|
16179
|
+
|
|
16180
|
+
class ReasoningProcessor extends BaseReasoningProcessor {
|
|
16181
|
+
getToolName() {
|
|
16182
|
+
return "CodexReasoning";
|
|
15951
16183
|
}
|
|
15952
|
-
|
|
15953
|
-
return "
|
|
16184
|
+
getLogPrefix() {
|
|
16185
|
+
return "[ReasoningProcessor]";
|
|
15954
16186
|
}
|
|
15955
|
-
|
|
15956
|
-
|
|
15957
|
-
|
|
15958
|
-
|
|
15959
|
-
|
|
15960
|
-
}
|
|
15961
|
-
return "cancelled";
|
|
16187
|
+
/**
|
|
16188
|
+
* Process a reasoning delta and accumulate content.
|
|
16189
|
+
*/
|
|
16190
|
+
processDelta(delta) {
|
|
16191
|
+
this.processInput(delta);
|
|
15962
16192
|
}
|
|
15963
|
-
|
|
15964
|
-
|
|
16193
|
+
/**
|
|
16194
|
+
* Complete the reasoning section with final text.
|
|
16195
|
+
*/
|
|
16196
|
+
complete(fullText) {
|
|
16197
|
+
this.completeReasoning(fullText);
|
|
15965
16198
|
}
|
|
15966
|
-
return "completed";
|
|
15967
16199
|
}
|
|
15968
|
-
|
|
15969
|
-
|
|
15970
|
-
|
|
15971
|
-
|
|
15972
|
-
|
|
15973
|
-
|
|
15974
|
-
const turnId = cuid2.createId();
|
|
15975
|
-
const turnStart = api.createEnvelope("agent", { t: "turn-start" }, { turn: turnId });
|
|
15976
|
-
startedSubagents.clear();
|
|
15977
|
-
activeSubagents.clear();
|
|
15978
|
-
providerSubagentToSessionSubagent.clear();
|
|
15979
|
-
return {
|
|
15980
|
-
currentTurnId: turnId,
|
|
15981
|
-
startedSubagents,
|
|
15982
|
-
activeSubagents,
|
|
15983
|
-
providerSubagentToSessionSubagent,
|
|
15984
|
-
envelopes: [turnStart]
|
|
15985
|
-
};
|
|
15986
|
-
}
|
|
15987
|
-
if (type === "task_complete" || type === "turn_aborted") {
|
|
15988
|
-
if (!state.currentTurnId) {
|
|
15989
|
-
return {
|
|
15990
|
-
currentTurnId: null,
|
|
15991
|
-
startedSubagents,
|
|
15992
|
-
activeSubagents,
|
|
15993
|
-
providerSubagentToSessionSubagent,
|
|
15994
|
-
envelopes: []
|
|
15995
|
-
};
|
|
15996
|
-
}
|
|
15997
|
-
const lifecycleOpts = { turn: state.currentTurnId };
|
|
15998
|
-
providerSubagentToSessionSubagent.clear();
|
|
15999
|
-
return {
|
|
16000
|
-
currentTurnId: null,
|
|
16001
|
-
startedSubagents,
|
|
16002
|
-
activeSubagents,
|
|
16003
|
-
providerSubagentToSessionSubagent,
|
|
16004
|
-
envelopes: [
|
|
16005
|
-
...emitSubagentStops(lifecycleOpts, startedSubagents, activeSubagents),
|
|
16006
|
-
api.createEnvelope("agent", {
|
|
16007
|
-
t: "turn-end",
|
|
16008
|
-
status: pickTurnEndStatus(message, type)
|
|
16009
|
-
}, lifecycleOpts)
|
|
16010
|
-
]
|
|
16011
|
-
};
|
|
16012
|
-
}
|
|
16013
|
-
if (type === "token_count") {
|
|
16014
|
-
return {
|
|
16015
|
-
currentTurnId: state.currentTurnId,
|
|
16016
|
-
startedSubagents,
|
|
16017
|
-
activeSubagents,
|
|
16018
|
-
providerSubagentToSessionSubagent,
|
|
16019
|
-
envelopes: []
|
|
16020
|
-
};
|
|
16200
|
+
|
|
16201
|
+
class DiffProcessor {
|
|
16202
|
+
previousDiff = null;
|
|
16203
|
+
onMessage = null;
|
|
16204
|
+
constructor(onMessage) {
|
|
16205
|
+
this.onMessage = onMessage || null;
|
|
16021
16206
|
}
|
|
16022
|
-
|
|
16023
|
-
|
|
16024
|
-
|
|
16025
|
-
|
|
16026
|
-
|
|
16027
|
-
|
|
16028
|
-
|
|
16029
|
-
|
|
16030
|
-
|
|
16031
|
-
|
|
16207
|
+
/**
|
|
16208
|
+
* Process a turn_diff message and check if the unified_diff has changed
|
|
16209
|
+
*/
|
|
16210
|
+
processDiff(unifiedDiff) {
|
|
16211
|
+
if (this.previousDiff !== unifiedDiff) {
|
|
16212
|
+
persistence.logger.debug("[DiffProcessor] Unified diff changed, sending CodexDiff tool call");
|
|
16213
|
+
const callId = node_crypto.randomUUID();
|
|
16214
|
+
const toolCall = {
|
|
16215
|
+
type: "tool-call",
|
|
16216
|
+
name: "CodexDiff",
|
|
16217
|
+
callId,
|
|
16218
|
+
input: {
|
|
16219
|
+
unified_diff: unifiedDiff
|
|
16220
|
+
},
|
|
16221
|
+
id: node_crypto.randomUUID()
|
|
16032
16222
|
};
|
|
16033
|
-
|
|
16034
|
-
|
|
16035
|
-
|
|
16036
|
-
|
|
16037
|
-
|
|
16038
|
-
|
|
16039
|
-
|
|
16040
|
-
|
|
16041
|
-
providerSubagentToSessionSubagent,
|
|
16042
|
-
envelopes
|
|
16043
|
-
};
|
|
16044
|
-
}
|
|
16045
|
-
if (type === "agent_reasoning" || type === "agent_reasoning_delta") {
|
|
16046
|
-
const text = typeof message.text === "string" ? message.text : typeof message.delta === "string" ? message.delta : null;
|
|
16047
|
-
if (!text) {
|
|
16048
|
-
return {
|
|
16049
|
-
currentTurnId: state.currentTurnId,
|
|
16050
|
-
startedSubagents,
|
|
16051
|
-
activeSubagents,
|
|
16052
|
-
providerSubagentToSessionSubagent,
|
|
16053
|
-
envelopes: []
|
|
16223
|
+
this.onMessage?.(toolCall);
|
|
16224
|
+
const toolResult = {
|
|
16225
|
+
type: "tool-call-result",
|
|
16226
|
+
callId,
|
|
16227
|
+
output: {
|
|
16228
|
+
status: "completed"
|
|
16229
|
+
},
|
|
16230
|
+
id: node_crypto.randomUUID()
|
|
16054
16231
|
};
|
|
16232
|
+
this.onMessage?.(toolResult);
|
|
16055
16233
|
}
|
|
16056
|
-
|
|
16057
|
-
|
|
16058
|
-
envelopes.push(api.createEnvelope("agent", { t: "text", text, thinking: true }, opts));
|
|
16059
|
-
return {
|
|
16060
|
-
currentTurnId: state.currentTurnId,
|
|
16061
|
-
startedSubagents,
|
|
16062
|
-
activeSubagents,
|
|
16063
|
-
providerSubagentToSessionSubagent,
|
|
16064
|
-
envelopes
|
|
16065
|
-
};
|
|
16234
|
+
this.previousDiff = unifiedDiff;
|
|
16235
|
+
persistence.logger.debug("[DiffProcessor] Updated stored diff");
|
|
16066
16236
|
}
|
|
16067
|
-
|
|
16068
|
-
|
|
16069
|
-
|
|
16070
|
-
|
|
16071
|
-
|
|
16072
|
-
|
|
16073
|
-
maybeEmitSubagentStart(subagent, opts, startedSubagents, activeSubagents, envelopes);
|
|
16074
|
-
envelopes.push(
|
|
16075
|
-
api.createEnvelope("agent", {
|
|
16076
|
-
t: "tool-call-start",
|
|
16077
|
-
call,
|
|
16078
|
-
name: "CodexBash",
|
|
16079
|
-
title: commandToTitle(command),
|
|
16080
|
-
description,
|
|
16081
|
-
args
|
|
16082
|
-
}, opts)
|
|
16083
|
-
);
|
|
16084
|
-
return {
|
|
16085
|
-
currentTurnId: state.currentTurnId,
|
|
16086
|
-
startedSubagents,
|
|
16087
|
-
activeSubagents,
|
|
16088
|
-
providerSubagentToSessionSubagent,
|
|
16089
|
-
envelopes
|
|
16090
|
-
};
|
|
16237
|
+
/**
|
|
16238
|
+
* Reset the processor state (called on task_complete or turn_aborted)
|
|
16239
|
+
*/
|
|
16240
|
+
reset() {
|
|
16241
|
+
persistence.logger.debug("[DiffProcessor] Resetting diff state");
|
|
16242
|
+
this.previousDiff = null;
|
|
16091
16243
|
}
|
|
16092
|
-
|
|
16093
|
-
|
|
16094
|
-
|
|
16095
|
-
|
|
16096
|
-
|
|
16097
|
-
return {
|
|
16098
|
-
currentTurnId: state.currentTurnId,
|
|
16099
|
-
startedSubagents,
|
|
16100
|
-
activeSubagents,
|
|
16101
|
-
providerSubagentToSessionSubagent,
|
|
16102
|
-
envelopes
|
|
16103
|
-
};
|
|
16244
|
+
/**
|
|
16245
|
+
* Set the message callback for sending messages directly
|
|
16246
|
+
*/
|
|
16247
|
+
setMessageCallback(callback) {
|
|
16248
|
+
this.onMessage = callback;
|
|
16104
16249
|
}
|
|
16105
|
-
|
|
16106
|
-
|
|
16107
|
-
|
|
16108
|
-
|
|
16109
|
-
|
|
16110
|
-
maybeEmitSubagentStart(subagent, opts, startedSubagents, activeSubagents, envelopes);
|
|
16111
|
-
envelopes.push(
|
|
16112
|
-
api.createEnvelope("agent", {
|
|
16113
|
-
t: "tool-call-start",
|
|
16114
|
-
call,
|
|
16115
|
-
name: "CodexPatch",
|
|
16116
|
-
title: "Apply patch",
|
|
16117
|
-
description: patchDescription(changes),
|
|
16118
|
-
args: {
|
|
16119
|
-
auto_approved: autoApproved,
|
|
16120
|
-
changes
|
|
16121
|
-
}
|
|
16122
|
-
}, opts)
|
|
16123
|
-
);
|
|
16124
|
-
return {
|
|
16125
|
-
currentTurnId: state.currentTurnId,
|
|
16126
|
-
startedSubagents,
|
|
16127
|
-
activeSubagents,
|
|
16128
|
-
providerSubagentToSessionSubagent,
|
|
16129
|
-
envelopes
|
|
16130
|
-
};
|
|
16250
|
+
/**
|
|
16251
|
+
* Get the current diff value
|
|
16252
|
+
*/
|
|
16253
|
+
getCurrentDiff() {
|
|
16254
|
+
return this.previousDiff;
|
|
16131
16255
|
}
|
|
16132
|
-
|
|
16133
|
-
|
|
16134
|
-
|
|
16135
|
-
|
|
16136
|
-
|
|
16137
|
-
|
|
16138
|
-
|
|
16139
|
-
|
|
16140
|
-
|
|
16141
|
-
|
|
16142
|
-
|
|
16256
|
+
}
|
|
16257
|
+
|
|
16258
|
+
const CodexDisplay = ({ messageBuffer, logPath, onExit }) => {
|
|
16259
|
+
const [messages, setMessages] = React.useState([]);
|
|
16260
|
+
const [confirmationMode, setConfirmationMode] = React.useState(false);
|
|
16261
|
+
const [actionInProgress, setActionInProgress] = React.useState(false);
|
|
16262
|
+
const confirmationTimeoutRef = React.useRef(null);
|
|
16263
|
+
const { stdout } = ink.useStdout();
|
|
16264
|
+
const terminalWidth = stdout.columns || 80;
|
|
16265
|
+
const terminalHeight = stdout.rows || 24;
|
|
16266
|
+
React.useEffect(() => {
|
|
16267
|
+
setMessages(messageBuffer.getMessages());
|
|
16268
|
+
const unsubscribe = messageBuffer.onUpdate((newMessages) => {
|
|
16269
|
+
setMessages(newMessages);
|
|
16270
|
+
});
|
|
16271
|
+
return () => {
|
|
16272
|
+
unsubscribe();
|
|
16273
|
+
if (confirmationTimeoutRef.current) {
|
|
16274
|
+
clearTimeout(confirmationTimeoutRef.current);
|
|
16275
|
+
}
|
|
16143
16276
|
};
|
|
16144
|
-
}
|
|
16277
|
+
}, [messageBuffer]);
|
|
16278
|
+
const resetConfirmation = React.useCallback(() => {
|
|
16279
|
+
setConfirmationMode(false);
|
|
16280
|
+
if (confirmationTimeoutRef.current) {
|
|
16281
|
+
clearTimeout(confirmationTimeoutRef.current);
|
|
16282
|
+
confirmationTimeoutRef.current = null;
|
|
16283
|
+
}
|
|
16284
|
+
}, []);
|
|
16285
|
+
const setConfirmationWithTimeout = React.useCallback(() => {
|
|
16286
|
+
setConfirmationMode(true);
|
|
16287
|
+
if (confirmationTimeoutRef.current) {
|
|
16288
|
+
clearTimeout(confirmationTimeoutRef.current);
|
|
16289
|
+
}
|
|
16290
|
+
confirmationTimeoutRef.current = setTimeout(() => {
|
|
16291
|
+
resetConfirmation();
|
|
16292
|
+
}, 15e3);
|
|
16293
|
+
}, [resetConfirmation]);
|
|
16294
|
+
ink.useInput(React.useCallback(async (input, key) => {
|
|
16295
|
+
if (actionInProgress) return;
|
|
16296
|
+
if (key.ctrl && input === "c") {
|
|
16297
|
+
if (confirmationMode) {
|
|
16298
|
+
resetConfirmation();
|
|
16299
|
+
setActionInProgress(true);
|
|
16300
|
+
await new Promise((resolve) => setTimeout(resolve, 100));
|
|
16301
|
+
onExit?.();
|
|
16302
|
+
} else {
|
|
16303
|
+
setConfirmationWithTimeout();
|
|
16304
|
+
}
|
|
16305
|
+
return;
|
|
16306
|
+
}
|
|
16307
|
+
if (confirmationMode) {
|
|
16308
|
+
resetConfirmation();
|
|
16309
|
+
}
|
|
16310
|
+
}, [confirmationMode, actionInProgress, onExit, setConfirmationWithTimeout, resetConfirmation]));
|
|
16311
|
+
const getMessageColor = (type) => {
|
|
16312
|
+
switch (type) {
|
|
16313
|
+
case "user":
|
|
16314
|
+
return "magenta";
|
|
16315
|
+
case "assistant":
|
|
16316
|
+
return "cyan";
|
|
16317
|
+
case "system":
|
|
16318
|
+
return "blue";
|
|
16319
|
+
case "tool":
|
|
16320
|
+
return "yellow";
|
|
16321
|
+
case "result":
|
|
16322
|
+
return "green";
|
|
16323
|
+
case "status":
|
|
16324
|
+
return "gray";
|
|
16325
|
+
default:
|
|
16326
|
+
return "white";
|
|
16327
|
+
}
|
|
16328
|
+
};
|
|
16329
|
+
const formatMessage = (msg) => {
|
|
16330
|
+
const lines = msg.content.split("\n");
|
|
16331
|
+
const maxLineLength = terminalWidth - 10;
|
|
16332
|
+
return lines.map((line) => {
|
|
16333
|
+
if (line.length <= maxLineLength) return line;
|
|
16334
|
+
const chunks = [];
|
|
16335
|
+
for (let i = 0; i < line.length; i += maxLineLength) {
|
|
16336
|
+
chunks.push(line.slice(i, i + maxLineLength));
|
|
16337
|
+
}
|
|
16338
|
+
return chunks.join("\n");
|
|
16339
|
+
}).join("\n");
|
|
16340
|
+
};
|
|
16341
|
+
return /* @__PURE__ */ React.createElement(ink.Box, { flexDirection: "column", width: terminalWidth, height: terminalHeight }, /* @__PURE__ */ React.createElement(
|
|
16342
|
+
ink.Box,
|
|
16343
|
+
{
|
|
16344
|
+
flexDirection: "column",
|
|
16345
|
+
width: terminalWidth,
|
|
16346
|
+
height: terminalHeight - 4,
|
|
16347
|
+
borderStyle: "round",
|
|
16348
|
+
borderColor: "gray",
|
|
16349
|
+
paddingX: 1,
|
|
16350
|
+
overflow: "hidden"
|
|
16351
|
+
},
|
|
16352
|
+
/* @__PURE__ */ React.createElement(ink.Box, { flexDirection: "column", marginBottom: 1 }, /* @__PURE__ */ React.createElement(ink.Text, { color: "gray", bold: true }, "\u{1F916} Codex Agent Messages"), /* @__PURE__ */ React.createElement(ink.Text, { color: "gray", dimColor: true }, "\u2500".repeat(Math.min(terminalWidth - 4, 60)))),
|
|
16353
|
+
/* @__PURE__ */ React.createElement(ink.Box, { flexDirection: "column", height: terminalHeight - 10, overflow: "hidden" }, messages.length === 0 ? /* @__PURE__ */ React.createElement(ink.Text, { color: "gray", dimColor: true }, "Waiting for messages...") : (
|
|
16354
|
+
// Show only the last messages that fit in the available space
|
|
16355
|
+
messages.slice(-Math.max(1, terminalHeight - 10)).map((msg) => /* @__PURE__ */ React.createElement(ink.Box, { key: msg.id, flexDirection: "column", marginBottom: 1 }, /* @__PURE__ */ React.createElement(ink.Text, { color: getMessageColor(msg.type), dimColor: true }, formatMessage(msg))))
|
|
16356
|
+
))
|
|
16357
|
+
), /* @__PURE__ */ React.createElement(
|
|
16358
|
+
ink.Box,
|
|
16359
|
+
{
|
|
16360
|
+
width: terminalWidth,
|
|
16361
|
+
borderStyle: "round",
|
|
16362
|
+
borderColor: actionInProgress ? "gray" : confirmationMode ? "red" : "green",
|
|
16363
|
+
paddingX: 2,
|
|
16364
|
+
justifyContent: "center",
|
|
16365
|
+
alignItems: "center",
|
|
16366
|
+
flexDirection: "column"
|
|
16367
|
+
},
|
|
16368
|
+
/* @__PURE__ */ React.createElement(ink.Box, { flexDirection: "column", alignItems: "center" }, actionInProgress ? /* @__PURE__ */ React.createElement(ink.Text, { color: "gray", bold: true }, "Exiting agent...") : confirmationMode ? /* @__PURE__ */ React.createElement(ink.Text, { color: "red", bold: true }, "\u26A0\uFE0F Press Ctrl-C again to exit the agent") : /* @__PURE__ */ React.createElement(React.Fragment, null, /* @__PURE__ */ React.createElement(ink.Text, { color: "green", bold: true }, "\u{1F916} Codex Agent Running \u2022 Ctrl-C to exit")), process.env.DEBUG && logPath && /* @__PURE__ */ React.createElement(ink.Text, { color: "gray", dimColor: true }, "Debug logs: ", logPath))
|
|
16369
|
+
));
|
|
16370
|
+
};
|
|
16371
|
+
|
|
16372
|
+
function createOfflineSessionStub(sessionTag) {
|
|
16145
16373
|
return {
|
|
16146
|
-
|
|
16147
|
-
|
|
16148
|
-
|
|
16149
|
-
|
|
16150
|
-
|
|
16374
|
+
sessionId: `offline-${sessionTag}`,
|
|
16375
|
+
sendCodexMessage: () => {
|
|
16376
|
+
},
|
|
16377
|
+
sendAgentMessage: () => {
|
|
16378
|
+
},
|
|
16379
|
+
sendAgentUsageSnapshot: () => false,
|
|
16380
|
+
sendClaudeSessionMessage: () => {
|
|
16381
|
+
},
|
|
16382
|
+
keepAlive: () => {
|
|
16383
|
+
},
|
|
16384
|
+
sendSessionEvent: () => {
|
|
16385
|
+
},
|
|
16386
|
+
sendSessionDeath: () => {
|
|
16387
|
+
},
|
|
16388
|
+
updateLifecycleState: () => {
|
|
16389
|
+
},
|
|
16390
|
+
requestControlTransfer: async () => {
|
|
16391
|
+
},
|
|
16392
|
+
flush: async () => {
|
|
16393
|
+
},
|
|
16394
|
+
close: async () => {
|
|
16395
|
+
},
|
|
16396
|
+
updateMetadata: () => {
|
|
16397
|
+
},
|
|
16398
|
+
updateAgentState: () => {
|
|
16399
|
+
},
|
|
16400
|
+
onUserMessage: () => {
|
|
16401
|
+
},
|
|
16402
|
+
onFileEvent: () => {
|
|
16403
|
+
},
|
|
16404
|
+
trackAttachmentDownload: () => {
|
|
16405
|
+
},
|
|
16406
|
+
drainAttachmentsForUserMessage: async () => [],
|
|
16407
|
+
rpcHandlerManager: {
|
|
16408
|
+
registerHandler: () => {
|
|
16409
|
+
}
|
|
16410
|
+
}
|
|
16151
16411
|
};
|
|
16152
16412
|
}
|
|
16153
|
-
|
|
16154
|
-
|
|
16155
|
-
const
|
|
16156
|
-
|
|
16157
|
-
|
|
16158
|
-
|
|
16159
|
-
|
|
16160
|
-
|
|
16161
|
-
|
|
16413
|
+
|
|
16414
|
+
function setupOfflineReconnection(opts) {
|
|
16415
|
+
const { api: api$1, sessionTag, metadata, state, response, onSessionSwap } = opts;
|
|
16416
|
+
let session;
|
|
16417
|
+
let reconnectionHandle = null;
|
|
16418
|
+
if (!response) {
|
|
16419
|
+
session = createOfflineSessionStub(sessionTag);
|
|
16420
|
+
reconnectionHandle = api.startOfflineReconnection({
|
|
16421
|
+
serverUrl: persistence.configuration.serverUrl,
|
|
16422
|
+
onReconnected: async () => {
|
|
16423
|
+
const resp = await api$1.getOrCreateSession({ tag: sessionTag, metadata, state });
|
|
16424
|
+
if (!resp) throw new Error("Server unavailable");
|
|
16425
|
+
const realSession = api$1.sessionSyncClient(resp);
|
|
16426
|
+
onSessionSwap(realSession);
|
|
16427
|
+
return realSession;
|
|
16428
|
+
},
|
|
16429
|
+
onNotify: (msg) => {
|
|
16430
|
+
console.log(msg);
|
|
16431
|
+
}
|
|
16432
|
+
});
|
|
16433
|
+
return { session, reconnectionHandle, isOffline: true };
|
|
16434
|
+
} else {
|
|
16435
|
+
session = api$1.sessionSyncClient(response, opts.sessionClientOptions);
|
|
16436
|
+
return { session, reconnectionHandle: null, isOffline: false };
|
|
16162
16437
|
}
|
|
16163
|
-
|
|
16164
|
-
|
|
16165
|
-
|
|
16166
|
-
|
|
16167
|
-
|
|
16168
|
-
|
|
16169
|
-
|
|
16170
|
-
|
|
16171
|
-
args: toolLikeMessage.input && typeof toolLikeMessage.input === "object" ? toolLikeMessage.input : {}
|
|
16172
|
-
}, opts)];
|
|
16438
|
+
}
|
|
16439
|
+
|
|
16440
|
+
function resolveCodexExecutionPolicy(permissionMode, sandboxManagedByHappy) {
|
|
16441
|
+
if (sandboxManagedByHappy) {
|
|
16442
|
+
return {
|
|
16443
|
+
approvalPolicy: "never",
|
|
16444
|
+
sandbox: "danger-full-access"
|
|
16445
|
+
};
|
|
16173
16446
|
}
|
|
16174
|
-
|
|
16175
|
-
|
|
16176
|
-
|
|
16177
|
-
|
|
16178
|
-
|
|
16179
|
-
|
|
16180
|
-
|
|
16181
|
-
|
|
16182
|
-
|
|
16447
|
+
const approvalPolicy = (() => {
|
|
16448
|
+
switch (permissionMode) {
|
|
16449
|
+
// Codex native modes
|
|
16450
|
+
case "default":
|
|
16451
|
+
return "untrusted";
|
|
16452
|
+
// Ask for non-trusted commands
|
|
16453
|
+
case "read-only":
|
|
16454
|
+
return "never";
|
|
16455
|
+
// Never ask, read-only enforced by sandbox
|
|
16456
|
+
case "safe-yolo":
|
|
16457
|
+
return "on-request";
|
|
16458
|
+
// Workspace auto-run; request approval for escalation (0.153 removed on-failure)
|
|
16459
|
+
case "yolo":
|
|
16460
|
+
return "never";
|
|
16461
|
+
// Full YOLO: never interrupt for approvals
|
|
16462
|
+
// Defensive fallback for Claude-specific modes (backward compatibility)
|
|
16463
|
+
case "bypassPermissions":
|
|
16464
|
+
return "never";
|
|
16465
|
+
// Full access: map to yolo behavior
|
|
16466
|
+
case "acceptEdits":
|
|
16467
|
+
return "on-request";
|
|
16468
|
+
// Let model decide (closest to auto-approve edits)
|
|
16469
|
+
case "plan":
|
|
16470
|
+
return "untrusted";
|
|
16471
|
+
// Conservative: ask for non-trusted
|
|
16472
|
+
default:
|
|
16473
|
+
return "untrusted";
|
|
16183
16474
|
}
|
|
16184
|
-
|
|
16185
|
-
|
|
16186
|
-
|
|
16187
|
-
|
|
16188
|
-
|
|
16189
|
-
|
|
16190
|
-
|
|
16475
|
+
})();
|
|
16476
|
+
const sandbox = (() => {
|
|
16477
|
+
switch (permissionMode) {
|
|
16478
|
+
// Codex native modes
|
|
16479
|
+
case "default":
|
|
16480
|
+
return "workspace-write";
|
|
16481
|
+
// Can write in workspace
|
|
16482
|
+
case "read-only":
|
|
16483
|
+
return "read-only";
|
|
16484
|
+
// Read-only filesystem
|
|
16485
|
+
case "safe-yolo":
|
|
16486
|
+
return "workspace-write";
|
|
16487
|
+
// Can write in workspace
|
|
16488
|
+
case "yolo":
|
|
16489
|
+
return "danger-full-access";
|
|
16490
|
+
// Full system access
|
|
16491
|
+
// Defensive fallback for Claude-specific modes
|
|
16492
|
+
case "bypassPermissions":
|
|
16493
|
+
return "danger-full-access";
|
|
16494
|
+
// Full access: map to yolo
|
|
16495
|
+
case "acceptEdits":
|
|
16496
|
+
return "workspace-write";
|
|
16497
|
+
// Can edit files in workspace
|
|
16498
|
+
case "plan":
|
|
16499
|
+
return "workspace-write";
|
|
16500
|
+
// Can write for planning
|
|
16501
|
+
default:
|
|
16502
|
+
return "workspace-write";
|
|
16503
|
+
}
|
|
16504
|
+
})();
|
|
16505
|
+
return { approvalPolicy, sandbox };
|
|
16191
16506
|
}
|
|
16192
16507
|
|
|
16193
16508
|
async function resumeExistingThread(opts) {
|
|
@@ -16659,6 +16974,13 @@ async function runCodex(opts) {
|
|
|
16659
16974
|
process.exit(1);
|
|
16660
16975
|
}
|
|
16661
16976
|
};
|
|
16977
|
+
session.rpcHandlerManager.registerHandler("codex-child-read", async (args) => {
|
|
16978
|
+
try {
|
|
16979
|
+
return await readChildThread(client, args?.threadId);
|
|
16980
|
+
} catch (error) {
|
|
16981
|
+
return { error: error instanceof Error ? error.message : "Child read failed" };
|
|
16982
|
+
}
|
|
16983
|
+
});
|
|
16662
16984
|
session.rpcHandlerManager.registerHandler("abort", handleAbort);
|
|
16663
16985
|
const disposeTermination = registerKillSessionHandler(session.rpcHandlerManager, handleKillSession, session, { processSignals: true });
|
|
16664
16986
|
const messageBuffer = new MessageBuffer();
|
|
@@ -17199,7 +17521,7 @@ Conversation history is preserved on the server, but in-flight tool calls are in
|
|
|
17199
17521
|
process.exit(0);
|
|
17200
17522
|
} else if (subcommand === "install-terminal-hooks") {
|
|
17201
17523
|
try {
|
|
17202
|
-
const { installTerminalHooks, parseTerminalHooksArgs, TERMINAL_HOOKS_HELP } = await Promise.resolve().then(function () { return require('./installTerminalHooks-
|
|
17524
|
+
const { installTerminalHooks, parseTerminalHooksArgs, TERMINAL_HOOKS_HELP } = await Promise.resolve().then(function () { return require('./installTerminalHooks-gmWKACNb.cjs'); });
|
|
17203
17525
|
const command = parseTerminalHooksArgs(args.slice(1));
|
|
17204
17526
|
if (command.action === "help") {
|
|
17205
17527
|
console.log(TERMINAL_HOOKS_HELP);
|
|
@@ -17216,7 +17538,7 @@ Conversation history is preserved on the server, but in-flight tool calls are in
|
|
|
17216
17538
|
}
|
|
17217
17539
|
} else if (subcommand === "spawn") {
|
|
17218
17540
|
try {
|
|
17219
|
-
const { handleSpawnCommand } = await Promise.resolve().then(function () { return require('./spawn-
|
|
17541
|
+
const { handleSpawnCommand } = await Promise.resolve().then(function () { return require('./spawn-DVJtNwWN.cjs'); });
|
|
17220
17542
|
await handleSpawnCommand(args.slice(1));
|
|
17221
17543
|
} catch (error) {
|
|
17222
17544
|
console.error(chalk.red("Error:"), error instanceof Error ? error.message : "Unknown error");
|
|
@@ -17228,7 +17550,7 @@ Conversation history is preserved on the server, but in-flight tool calls are in
|
|
|
17228
17550
|
return;
|
|
17229
17551
|
} else if (subcommand === "sessions") {
|
|
17230
17552
|
try {
|
|
17231
|
-
const { handleSessionsCommand } = await Promise.resolve().then(function () { return require('./sessions-
|
|
17553
|
+
const { handleSessionsCommand } = await Promise.resolve().then(function () { return require('./sessions-Cx_3cvN6.cjs'); });
|
|
17232
17554
|
await handleSessionsCommand(args.slice(1));
|
|
17233
17555
|
} catch (error) {
|
|
17234
17556
|
console.error(chalk.red("Error:"), error instanceof Error ? error.message : "Unknown error");
|
|
@@ -17240,7 +17562,7 @@ Conversation history is preserved on the server, but in-flight tool calls are in
|
|
|
17240
17562
|
return;
|
|
17241
17563
|
} else if (subcommand === "send") {
|
|
17242
17564
|
try {
|
|
17243
|
-
const { handleSendCommand } = await Promise.resolve().then(function () { return require('./send-
|
|
17565
|
+
const { handleSendCommand } = await Promise.resolve().then(function () { return require('./send-WlJ4r3U2.cjs'); });
|
|
17244
17566
|
await handleSendCommand(args.slice(1));
|
|
17245
17567
|
} catch (error) {
|
|
17246
17568
|
console.error(chalk.red("Error:"), error instanceof Error ? error.message : "Unknown error");
|
|
@@ -17346,9 +17668,9 @@ Conversation history is preserved on the server, but in-flight tool calls are in
|
|
|
17346
17668
|
if (geminiSubcommand === "project" && args[2] === "set" && args[3]) {
|
|
17347
17669
|
const projectId = args[3];
|
|
17348
17670
|
try {
|
|
17349
|
-
const { saveGoogleCloudProjectToConfig } = await Promise.resolve().then(function () { return require('./config-
|
|
17350
|
-
const { readCredentialsForConfiguredRelay: readCredentialsForConfiguredRelay2 } = await Promise.resolve().then(function () { return require('./limits-
|
|
17351
|
-
const { ApiClient: ApiClient2 } = await Promise.resolve().then(function () { return require('./types-
|
|
17671
|
+
const { saveGoogleCloudProjectToConfig } = await Promise.resolve().then(function () { return require('./config-BO0ZHyoB.cjs'); });
|
|
17672
|
+
const { readCredentialsForConfiguredRelay: readCredentialsForConfiguredRelay2 } = await Promise.resolve().then(function () { return require('./limits-K17AgMHD.cjs'); }).then(function (n) { return n.persistence; });
|
|
17673
|
+
const { ApiClient: ApiClient2 } = await Promise.resolve().then(function () { return require('./types-DjAHWb4J.cjs'); }).then(function (n) { return n.api; });
|
|
17352
17674
|
let userEmail = void 0;
|
|
17353
17675
|
try {
|
|
17354
17676
|
const credentials = await readCredentialsForConfiguredRelay2();
|
|
@@ -17379,7 +17701,7 @@ Conversation history is preserved on the server, but in-flight tool calls are in
|
|
|
17379
17701
|
}
|
|
17380
17702
|
if (geminiSubcommand === "project" && args[2] === "get") {
|
|
17381
17703
|
try {
|
|
17382
|
-
const { readGeminiLocalConfig } = await Promise.resolve().then(function () { return require('./config-
|
|
17704
|
+
const { readGeminiLocalConfig } = await Promise.resolve().then(function () { return require('./config-BO0ZHyoB.cjs'); });
|
|
17383
17705
|
const config = readGeminiLocalConfig();
|
|
17384
17706
|
if (config.googleCloudProject) {
|
|
17385
17707
|
console.log(`Current Google Cloud Project: ${config.googleCloudProject}`);
|
|
@@ -17419,7 +17741,7 @@ Conversation history is preserved on the server, but in-flight tool calls are in
|
|
|
17419
17741
|
process.exit(0);
|
|
17420
17742
|
}
|
|
17421
17743
|
try {
|
|
17422
|
-
const { runGemini } = await Promise.resolve().then(function () { return require('./runGemini-
|
|
17744
|
+
const { runGemini } = await Promise.resolve().then(function () { return require('./runGemini-n0wD2Z9R.cjs'); });
|
|
17423
17745
|
let startedBy = void 0;
|
|
17424
17746
|
for (let i = 1; i < args.length; i++) {
|
|
17425
17747
|
if (args[i] === "--started-by") {
|
|
@@ -17449,7 +17771,7 @@ Conversation history is preserved on the server, but in-flight tool calls are in
|
|
|
17449
17771
|
}
|
|
17450
17772
|
};
|
|
17451
17773
|
try {
|
|
17452
|
-
const { runAcp, resolveAcpAgentConfig } = await Promise.resolve().then(function () { return require('./index-
|
|
17774
|
+
const { runAcp, resolveAcpAgentConfig } = await Promise.resolve().then(function () { return require('./index-BEpZjXs4.cjs'); });
|
|
17453
17775
|
const parsed = parsePiRunnerArgs(args.slice(1));
|
|
17454
17776
|
const resolved = resolveAcpAgentConfig(["pi", ...parsed.passthrough]);
|
|
17455
17777
|
const { credentials } = await authAndSetupMachineIfNeeded();
|
|
@@ -17477,7 +17799,7 @@ Conversation history is preserved on the server, but in-flight tool calls are in
|
|
|
17477
17799
|
return;
|
|
17478
17800
|
} else if (subcommand === "acp") {
|
|
17479
17801
|
try {
|
|
17480
|
-
const { runAcp, resolveAcpAgentConfig } = await Promise.resolve().then(function () { return require('./index-
|
|
17802
|
+
const { runAcp, resolveAcpAgentConfig } = await Promise.resolve().then(function () { return require('./index-BEpZjXs4.cjs'); });
|
|
17481
17803
|
let startedBy = void 0;
|
|
17482
17804
|
let verbose = false;
|
|
17483
17805
|
const acpArgs = [];
|
|
@@ -17517,7 +17839,7 @@ Conversation history is preserved on the server, but in-flight tool calls are in
|
|
|
17517
17839
|
return;
|
|
17518
17840
|
} else if (subcommand === "openclaw") {
|
|
17519
17841
|
try {
|
|
17520
|
-
const { runOpenClaw } = await Promise.resolve().then(function () { return require('./runOpenClaw-
|
|
17842
|
+
const { runOpenClaw } = await Promise.resolve().then(function () { return require('./runOpenClaw-fYx1XweW.cjs'); });
|
|
17521
17843
|
let startedBy = void 0;
|
|
17522
17844
|
let verbose = false;
|
|
17523
17845
|
let gatewayUrl;
|
|
@@ -17568,7 +17890,7 @@ Conversation history is preserved on the server, but in-flight tool calls are in
|
|
|
17568
17890
|
return;
|
|
17569
17891
|
} else if (subcommand === "todo") {
|
|
17570
17892
|
try {
|
|
17571
|
-
const { handleTodoCommand } = await Promise.resolve().then(function () { return require('./todo-
|
|
17893
|
+
const { handleTodoCommand } = await Promise.resolve().then(function () { return require('./todo-DHY20tpD.cjs'); });
|
|
17572
17894
|
await handleTodoCommand(args.slice(1));
|
|
17573
17895
|
} catch (error) {
|
|
17574
17896
|
console.error(JSON.stringify({ error: error instanceof Error ? error.message : "Todo command failed" }));
|
|
@@ -17577,7 +17899,7 @@ Conversation history is preserved on the server, but in-flight tool calls are in
|
|
|
17577
17899
|
return;
|
|
17578
17900
|
} else if (subcommand === "teams") {
|
|
17579
17901
|
try {
|
|
17580
|
-
const { handleTeamsCommand } = await Promise.resolve().then(function () { return require('./teams-
|
|
17902
|
+
const { handleTeamsCommand } = await Promise.resolve().then(function () { return require('./teams-BbYi0fWG.cjs'); });
|
|
17581
17903
|
await handleTeamsCommand(args.slice(1));
|
|
17582
17904
|
} catch (error) {
|
|
17583
17905
|
console.error(error instanceof Error ? error.message : "Teams command failed");
|
|
@@ -17586,7 +17908,7 @@ Conversation history is preserved on the server, but in-flight tool calls are in
|
|
|
17586
17908
|
return;
|
|
17587
17909
|
} else if (subcommand === "mcp" && args.length === 1) {
|
|
17588
17910
|
try {
|
|
17589
|
-
const { handleMcpCommand } = await Promise.resolve().then(function () { return require('./mcp-
|
|
17911
|
+
const { handleMcpCommand } = await Promise.resolve().then(function () { return require('./mcp-CK1NCZm0.cjs'); });
|
|
17590
17912
|
await handleMcpCommand();
|
|
17591
17913
|
} catch (error) {
|
|
17592
17914
|
process.stderr.write(`[very-happy mcp] Fatal: ${error instanceof Error ? error.message : String(error)}
|