very-happy-cli 0.2.133 → 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-DgG8o4jd.cjs → AcpBackend-C0Bwx6bc.cjs} +3 -3
- package/dist/{AcpBackend-BQm7dNza.mjs → AcpBackend-CkDpu1n_.mjs} +3 -3
- package/dist/{AcpSessionManager-C7unPEZO.mjs → AcpSessionManager-DB_mfFaH.mjs} +1 -1
- package/dist/{AcpSessionManager-DDFEmhQp.cjs → AcpSessionManager-DqvUp-UU.cjs} +1 -1
- package/dist/{agentGuidance-BaplwDcV.mjs → agentGuidance-7MByWxKj.mjs} +1 -1
- package/dist/{agentGuidance-BItqIZTf.cjs → agentGuidance-DlZM_YPV.cjs} +1 -1
- package/dist/codex/happyMcpStdioBridge.cjs +2 -2
- package/dist/codex/happyMcpStdioBridge.mjs +2 -2
- package/dist/{config-uLywzv5t.cjs → config-BO0ZHyoB.cjs} +4 -4
- package/dist/{config-BZ8xEnOv.mjs → config-DzvbcL_x.mjs} +4 -4
- package/dist/{index-Daga0ztv.cjs → index-BEpZjXs4.cjs} +15 -9
- package/dist/{index-ClCeQ1FW.mjs → index-C33JB4xB.mjs} +16 -10
- package/dist/{index-D8i2EViA.mjs → index-CpEdOGpe.mjs} +4 -4
- package/dist/{index-CdH3ecC5.cjs → index-DHI6Y1xW.cjs} +4 -4
- package/dist/{index-6Xm0CgN_.cjs → index-DNbKbe23.cjs} +1536 -1202
- package/dist/{index-EsR8ayIg.mjs → index-gefLe1Bk.mjs} +1534 -1200
- package/dist/index.cjs +4 -4
- package/dist/index.mjs +4 -4
- package/dist/{installTerminalHooks-NH4kiB2E.mjs → installTerminalHooks-BWoHGCew.mjs} +4 -4
- package/dist/{installTerminalHooks-CKG0MYVK.cjs → installTerminalHooks-gmWKACNb.cjs} +4 -4
- package/dist/lib.cjs +2 -2
- package/dist/lib.d.cts +20 -60
- package/dist/lib.d.mts +20 -60
- package/dist/lib.mjs +2 -2
- package/dist/{limits-Du7S6jqA.mjs → limits-CPTgiQ9A.mjs} +8 -8
- package/dist/{limits-XRNzIlVm.cjs → limits-K17AgMHD.cjs} +8 -8
- package/dist/{mcp-CAMCuudA.cjs → mcp-CK1NCZm0.cjs} +4 -4
- package/dist/{mcp-D8zhjyZa.mjs → mcp-DhuxpwTB.mjs} +4 -4
- package/dist/{runGemini-Db4rX54F.mjs → runGemini-BVJE7LZl.mjs} +6 -6
- package/dist/{runGemini-BIVHp0ST.cjs → runGemini-n0wD2Z9R.cjs} +6 -6
- package/dist/{runOpenClaw-D2MceXPO.mjs → runOpenClaw-CJaIYpB7.mjs} +5 -5
- package/dist/{runOpenClaw-a0f2pZZp.cjs → runOpenClaw-fYx1XweW.cjs} +5 -5
- package/dist/{send-DKbumEcg.cjs → send-WlJ4r3U2.cjs} +4 -4
- package/dist/{send-1Wjb0lIh.mjs → send-fWHOFJV9.mjs} +4 -4
- package/dist/{sessions-DXCCRDb5.mjs → sessions-5fJxQ2xj.mjs} +4 -4
- package/dist/{sessions-SIFOOlGp.cjs → sessions-Cx_3cvN6.cjs} +4 -4
- package/dist/{spawn-Bj3W6HR4.mjs → spawn-CF1ZV-YH.mjs} +4 -4
- package/dist/{spawn-C-XpSPLX.cjs → spawn-DVJtNwWN.cjs} +4 -4
- package/dist/{teams-ChFzXAqr.cjs → teams-BbYi0fWG.cjs} +4 -4
- package/dist/{teams-CqhFQLVC.mjs → teams-gzvKrMfn.mjs} +4 -4
- package/dist/{todo-B0gbQHH8.mjs → todo-BAK2DVLV.mjs} +3 -3
- package/dist/{todo-o0clp-_I.cjs → todo-DHY20tpD.cjs} +3 -3
- package/dist/{types-6DrEgHVx.mjs → types-BEXGahmj.mjs} +128 -35
- package/dist/{types-CcjVmS2i.cjs → types-DjAHWb4J.cjs} +129 -35
- package/package.json +8 -8
|
@@ -1,13 +1,13 @@
|
|
|
1
1
|
import{createRequire as _pkgrollCR}from"node:module";const require=_pkgrollCR(import.meta.url);import chalk from 'chalk';
|
|
2
2
|
import os, { homedir, userInfo, tmpdir } from 'node:os';
|
|
3
|
-
import { randomUUID, randomBytes, createHash as createHash$1, timingSafeEqual } from 'node:crypto';
|
|
4
|
-
import { j as getProjectPath, g as BUILTIN_TODO_DISCOVERY, p as projectPath, k as initializeSandbox, w as wrapCommand, d as contentLogMetadata, I as InvalidateSync, R as RawJSONLinesSchema, h as delay, l as AsyncLock, S as STREAM_DELTA_MAX_CHARS, M as MAX_CHAT_ATTACHMENT_SOURCE_BYTES, m as commandOnPath, n as deriveLocalCliUpdateSummary, o as
|
|
5
|
-
import { z as readDaemonState, l as logger, c as configuration, A as clearDaemonState, B as ensurePrivateDirectory, D as hardenPrivateFile, p as packageJson, g as readSettings, E as readCredentials, s as credentialRelayProblem, i as encodeBase64, F as readSettingsOutcome, G as updateSettings, H as encodeBase64Url, m as decodeBase64, I as writeCredentialsLegacy, J as writeCredentialsDataKey, d as readCredentialsForConfiguredRelay, j as encrypt, r as readPersistedSessions, w as writePrivateFileSync, K as decryptWithDataKey, L as decryptLegacy, M as persistSession, k as decrypt, f as ensurePrivateDirectorySync, N as acquireDaemonLock, O as deletePersistedSessions, P as writeDaemonState, Q as writeSettings, R as releaseDaemonLock, C as CLIPBOARD_TOOL_NAME, a as CLIPBOARD_TOOL_TITLE, b as CLIPBOARD_TOOL_DESCRIPTION, e as CLIPBOARD_MAX_BYTES, S as clearCredentials, T as clearMachineId, U as SandboxConfigSchema, V as getLatestDaemonLog } from './limits-
|
|
3
|
+
import { randomUUID, randomInt, randomBytes, createHash as createHash$1, timingSafeEqual } from 'node:crypto';
|
|
4
|
+
import { j as getProjectPath, g as BUILTIN_TODO_DISCOVERY, p as projectPath, k as initializeSandbox, w as wrapCommand, d as contentLogMetadata, I as InvalidateSync, R as RawJSONLinesSchema, h as delay, l as AsyncLock, S as STREAM_DELTA_MAX_CHARS, M as MAX_CHAT_ATTACHMENT_SOURCE_BYTES, m as commandOnPath, n as deriveLocalCliUpdateSummary, o as AGENT_VERSION_SOURCES, q as isClaudeSessionId, r as getLocalHappyAgentCredentialPath, t as readLocalHappyAgentCredentials, u as parseExactVersion, v as compareExactVersions, x as extractCompleteLines, y as decideBackfill, z as parseTerminalHookPayload, C as tmuxArgs, D as scrubTmuxClientEnv, E as decideMirrorBinding, F as MIRROR_BACKFILL_LINES_DEFAULT, G as mirrorLineKey, H as mirrorLocalId, J as detectCLIAvailability, K as detectResumeSupport, L as summarizeSpawnSessionForLog, N as shellescape, A as ApiClient, O as fetchCliUpdateState, P as resolveCliUpdateCheckInterval, Q as DEFAULT_CLI_UPDATE_CHECK_INTERVAL_MS, i as isValidSessionId, T as listVhTerminals, U as isValidTerminalId, V as readVhTerminal, W as sendToVhTerminal, X as ContextUsageSchema, Y as TITLE_PROMPT_PREFIX, Z as BOARD_ANALYZER_PROMPT_PREFIX, f as connectionState, _ as startOfflineReconnection, c as createEnvelope, $ as CodexAppServerClient } from './types-BEXGahmj.mjs';
|
|
5
|
+
import { z as readDaemonState, l as logger, c as configuration, A as clearDaemonState, B as ensurePrivateDirectory, D as hardenPrivateFile, p as packageJson, g as readSettings, E as readCredentials, s as credentialRelayProblem, i as encodeBase64, F as readSettingsOutcome, G as updateSettings, H as encodeBase64Url, m as decodeBase64, I as writeCredentialsLegacy, J as writeCredentialsDataKey, d as readCredentialsForConfiguredRelay, j as encrypt, r as readPersistedSessions, w as writePrivateFileSync, K as decryptWithDataKey, L as decryptLegacy, M as persistSession, k as decrypt, f as ensurePrivateDirectorySync, N as acquireDaemonLock, O as deletePersistedSessions, P as writeDaemonState, Q as writeSettings, R as releaseDaemonLock, C as CLIPBOARD_TOOL_NAME, a as CLIPBOARD_TOOL_TITLE, b as CLIPBOARD_TOOL_DESCRIPTION, e as CLIPBOARD_MAX_BYTES, S as clearCredentials, T as clearMachineId, U as SandboxConfigSchema, V as getLatestDaemonLog } from './limits-CPTgiQ9A.mjs';
|
|
6
6
|
import spawn$1, { spawn } from 'cross-spawn';
|
|
7
7
|
import path, { join, resolve, basename, isAbsolute, dirname, sep, delimiter, normalize } from 'node:path';
|
|
8
8
|
import { createInterface } from 'node:readline';
|
|
9
9
|
import { existsSync, readFileSync, readdirSync, statSync, mkdirSync, unlinkSync, renameSync, writeFileSync, accessSync, constants, openSync, fsyncSync, closeSync, rmSync as rmSync$1, chmodSync as chmodSync$1 } from 'node:fs';
|
|
10
|
-
import { f as trimIdent, A as AGENT_GUIDANCE, t as teamScopePath, T as TeamConnectionPreflightError, e as createTeamsClient, P as PREVIEW_TOOL_NAME, R as REPORT_PROGRESS_TOOL_NAME, g as TEAM_TOOL_NAMES, r as registerTeamsTools, a as PREVIEW_TOOL_TITLE, b as PREVIEW_TOOL_DESCRIPTION, h as REPORT_PROGRESS_TOOL_TITLE, i as REPORT_PROGRESS_TOOL_DESCRIPTION } from './agentGuidance-
|
|
10
|
+
import { f as trimIdent, A as AGENT_GUIDANCE, t as teamScopePath, T as TeamConnectionPreflightError, e as createTeamsClient, P as PREVIEW_TOOL_NAME, R as REPORT_PROGRESS_TOOL_NAME, g as TEAM_TOOL_NAMES, r as registerTeamsTools, a as PREVIEW_TOOL_TITLE, b as PREVIEW_TOOL_DESCRIPTION, h as REPORT_PROGRESS_TOOL_TITLE, i as REPORT_PROGRESS_TOOL_DESCRIPTION } from './agentGuidance-7MByWxKj.mjs';
|
|
11
11
|
import { readFile, writeFile, rename, unlink, mkdir, symlink, rm, readlink, lstat, stat, open as open$1, appendFile } from 'node:fs/promises';
|
|
12
12
|
import fs, { watch, access } from 'fs/promises';
|
|
13
13
|
import { useStdout, useInput, Box, Text, render } from 'ink';
|
|
@@ -20,7 +20,7 @@ import tweetnacl from 'tweetnacl';
|
|
|
20
20
|
import os$1, { homedir as homedir$1 } from 'os';
|
|
21
21
|
import { spawn as spawn$2, execSync as execSync$1, exec as exec$1 } from 'child_process';
|
|
22
22
|
import { createId } from '@paralleldrive/cuid2';
|
|
23
|
-
import { execSync, spawnSync, spawn as spawn$3,
|
|
23
|
+
import { execSync, spawnSync, execFile, spawn as spawn$3, execFileSync } from 'node:child_process';
|
|
24
24
|
import { existsSync as existsSync$1, statSync as statSync$1, mkdtempSync, rmSync, writeFileSync as writeFileSync$1, chmodSync, unlinkSync as unlinkSync$1 } from 'fs';
|
|
25
25
|
import { join as join$1 } from 'path';
|
|
26
26
|
import '@anthropic-ai/sandbox-runtime';
|
|
@@ -1331,6 +1331,152 @@ async function claudeLocalLauncher(session) {
|
|
|
1331
1331
|
return exitReason || { type: "exit", code: 0 };
|
|
1332
1332
|
}
|
|
1333
1333
|
|
|
1334
|
+
const text = (value) => typeof value === "string" && value.length > 0 && value.length <= 1024 && !value.includes("\0") ? value : null;
|
|
1335
|
+
const publicMcpStatus = (servers) => servers.map(({ name, status, serverInfo, scope, tools }) => ({ name, status, serverInfo, scope, tools: tools?.map(({ name: name2 }) => ({ name: name2 })) }));
|
|
1336
|
+
const fingerprint = (result) => JSON.stringify([result.canRewind, [...result.filesChanged ?? []].sort(), result.insertions, result.deletions]);
|
|
1337
|
+
function isRuntimeCheckpointReplay(message) {
|
|
1338
|
+
const m = message;
|
|
1339
|
+
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"));
|
|
1340
|
+
}
|
|
1341
|
+
function createRuntimeControls(isThinking) {
|
|
1342
|
+
let query = null, generation = randomInt(0, 2 ** 40), activityRevision = 0;
|
|
1343
|
+
const operations = /* @__PURE__ */ new Map();
|
|
1344
|
+
const confirmations = /* @__PURE__ */ new Map();
|
|
1345
|
+
const tasks = /* @__PURE__ */ new Map();
|
|
1346
|
+
const checkpoints = /* @__PURE__ */ new Map();
|
|
1347
|
+
let pending = false;
|
|
1348
|
+
const setQuery = (next) => {
|
|
1349
|
+
for (const operation of operations.values()) if (operation.status === "running") {
|
|
1350
|
+
operation.status = "failed";
|
|
1351
|
+
operation.error = "Claude query ended before this operation completed";
|
|
1352
|
+
}
|
|
1353
|
+
query = next;
|
|
1354
|
+
generation++;
|
|
1355
|
+
pending = false;
|
|
1356
|
+
confirmations.clear();
|
|
1357
|
+
tasks.clear();
|
|
1358
|
+
checkpoints.clear();
|
|
1359
|
+
};
|
|
1360
|
+
function observe(message) {
|
|
1361
|
+
const m = message;
|
|
1362
|
+
if (m.type === "user" || m.type === "assistant") {
|
|
1363
|
+
activityRevision++;
|
|
1364
|
+
confirmations.clear();
|
|
1365
|
+
}
|
|
1366
|
+
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(" ") : "";
|
|
1367
|
+
if (isRuntimeCheckpointReplay(message) && text(m.uuid) && content) {
|
|
1368
|
+
checkpoints.set(m.uuid, { id: m.uuid, title: content.slice(0, 120) });
|
|
1369
|
+
if (checkpoints.size > 100) checkpoints.delete(checkpoints.keys().next().value);
|
|
1370
|
+
}
|
|
1371
|
+
if (m.type === "system" && text(m.task_id) && ["task_started", "task_updated", "task_progress", "task_notification"].includes(m.subtype)) {
|
|
1372
|
+
const previous = tasks.get(m.task_id);
|
|
1373
|
+
if (m.subtype !== "task_notification" && ["completed", "failed", "stopped", "cancelled"].includes(String(previous?.status))) return;
|
|
1374
|
+
tasks.set(m.task_id, {
|
|
1375
|
+
...previous,
|
|
1376
|
+
id: m.task_id,
|
|
1377
|
+
...text(m.tool_use_id) ? { toolUseId: m.tool_use_id } : {},
|
|
1378
|
+
...text(m.description) ? { description: m.description } : {},
|
|
1379
|
+
...text(m.task_type) ? { type: m.task_type } : {},
|
|
1380
|
+
status: m.subtype === "task_notification" ? m.status ?? "completed" : "running"
|
|
1381
|
+
});
|
|
1382
|
+
if (tasks.size > 100) tasks.delete(tasks.keys().next().value);
|
|
1383
|
+
}
|
|
1384
|
+
}
|
|
1385
|
+
function request(input) {
|
|
1386
|
+
const r = input && typeof input === "object" ? input : {};
|
|
1387
|
+
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) };
|
|
1388
|
+
if (r.action === "operation") {
|
|
1389
|
+
const op2 = operations.get(String(r.operationId));
|
|
1390
|
+
return op2 ? { ...op2 } : { error: "Operation not found" };
|
|
1391
|
+
}
|
|
1392
|
+
const q = query;
|
|
1393
|
+
if (!q) return { error: "No active Claude SDK query" };
|
|
1394
|
+
if (pending || !q.canControl()) return { error: "Claude is waiting for an interaction or another control operation; retry after it finishes" };
|
|
1395
|
+
const action = String(r.action), server = text(r.serverName), task = text(r.taskId), target = text(r.userMessageId);
|
|
1396
|
+
const runGeneration = generation, runRevision = activityRevision;
|
|
1397
|
+
let execute;
|
|
1398
|
+
switch (action) {
|
|
1399
|
+
case "reload-skills":
|
|
1400
|
+
execute = () => q.reloadSkills();
|
|
1401
|
+
break;
|
|
1402
|
+
case "reload-plugins":
|
|
1403
|
+
execute = async () => {
|
|
1404
|
+
const result = await q.reloadPlugins();
|
|
1405
|
+
return { ...result, mcpServers: publicMcpStatus(result.mcpServers ?? []) };
|
|
1406
|
+
};
|
|
1407
|
+
break;
|
|
1408
|
+
case "mcp-status":
|
|
1409
|
+
execute = async () => publicMcpStatus(await q.mcpServerStatus());
|
|
1410
|
+
break;
|
|
1411
|
+
case "mcp-reconnect":
|
|
1412
|
+
if (!server) return { error: "Invalid server name" };
|
|
1413
|
+
execute = () => q.reconnectMcpServer(server);
|
|
1414
|
+
break;
|
|
1415
|
+
case "mcp-toggle":
|
|
1416
|
+
if (!server || typeof r.enabled !== "boolean") return { error: "Invalid server or enabled flag" };
|
|
1417
|
+
execute = () => q.toggleMcpServer(server, r.enabled);
|
|
1418
|
+
break;
|
|
1419
|
+
case "stop-task":
|
|
1420
|
+
if (!task || !tasks.has(task)) return { error: "Unknown task in this query" };
|
|
1421
|
+
execute = () => q.stopTask(task);
|
|
1422
|
+
break;
|
|
1423
|
+
case "background-tasks":
|
|
1424
|
+
if (r.toolUseId !== void 0 && !text(r.toolUseId)) return { error: "Invalid tool use ID" };
|
|
1425
|
+
execute = async () => ({ backgrounded: await q.backgroundTasks(r.toolUseId) });
|
|
1426
|
+
break;
|
|
1427
|
+
case "rewind-preview":
|
|
1428
|
+
if (isThinking() || !target || !checkpoints.has(target)) return { error: "Rewind requires an idle query and a known user checkpoint" };
|
|
1429
|
+
execute = async () => {
|
|
1430
|
+
const result = await q.rewindFiles(target, { dryRun: true });
|
|
1431
|
+
if (!result.canRewind) return result;
|
|
1432
|
+
if (query !== q || generation !== runGeneration || activityRevision !== runRevision || isThinking() || !q.canControl()) throw Error("Query changed; preview again");
|
|
1433
|
+
const token = randomUUID();
|
|
1434
|
+
confirmations.set(token, { generation, revision: activityRevision, userMessageId: target, fingerprint: fingerprint(result), expires: Date.now() + 3e5 });
|
|
1435
|
+
return { ...result, confirmationToken: token };
|
|
1436
|
+
};
|
|
1437
|
+
break;
|
|
1438
|
+
case "rewind-apply": {
|
|
1439
|
+
const confirmation = confirmations.get(String(r.confirmationToken));
|
|
1440
|
+
if (isThinking() || !confirmation || confirmation.generation !== generation || confirmation.expires < Date.now()) return { error: "Preview expired or query is running; preview again" };
|
|
1441
|
+
confirmations.delete(String(r.confirmationToken));
|
|
1442
|
+
execute = async () => {
|
|
1443
|
+
const fresh = await q.rewindFiles(confirmation.userMessageId, { dryRun: true });
|
|
1444
|
+
if (query !== q || generation !== runGeneration || activityRevision !== confirmation.revision || isThinking() || !q.canControl() || fingerprint(fresh) !== confirmation.fingerprint) throw Error("Files or query changed; preview again");
|
|
1445
|
+
return q.rewindFiles(confirmation.userMessageId, { dryRun: false });
|
|
1446
|
+
};
|
|
1447
|
+
break;
|
|
1448
|
+
}
|
|
1449
|
+
default:
|
|
1450
|
+
return { error: "Unknown Claude control action" };
|
|
1451
|
+
}
|
|
1452
|
+
pending = true;
|
|
1453
|
+
const op = { id: randomUUID(), queryGeneration: runGeneration, action, status: "running" };
|
|
1454
|
+
operations.set(op.id, op);
|
|
1455
|
+
if (operations.size > 50) for (const [id, old] of operations) {
|
|
1456
|
+
if (old.status !== "running") {
|
|
1457
|
+
operations.delete(id);
|
|
1458
|
+
break;
|
|
1459
|
+
}
|
|
1460
|
+
}
|
|
1461
|
+
void Promise.resolve().then(() => {
|
|
1462
|
+
if (query !== q || generation !== runGeneration || !q.canControl()) throw Error("Claude query changed or is waiting for an interaction");
|
|
1463
|
+
return execute();
|
|
1464
|
+
}).then((result) => {
|
|
1465
|
+
if (generation !== runGeneration || op.status !== "running") return;
|
|
1466
|
+
op.status = "completed";
|
|
1467
|
+
op.result = result ?? null;
|
|
1468
|
+
}, (error) => {
|
|
1469
|
+
if (generation !== runGeneration || op.status !== "running") return;
|
|
1470
|
+
op.status = "failed";
|
|
1471
|
+
op.error = error instanceof Error ? error.message : "Claude control failed";
|
|
1472
|
+
}).finally(() => {
|
|
1473
|
+
if (generation === runGeneration) pending = false;
|
|
1474
|
+
});
|
|
1475
|
+
return { operationId: op.id };
|
|
1476
|
+
}
|
|
1477
|
+
return { setQuery, observe, request };
|
|
1478
|
+
}
|
|
1479
|
+
|
|
1334
1480
|
class MessageBuffer {
|
|
1335
1481
|
messages = [];
|
|
1336
1482
|
listeners = [];
|
|
@@ -1600,6 +1746,9 @@ function query(params) {
|
|
|
1600
1746
|
tools: opts?.tools,
|
|
1601
1747
|
persistSession: opts?.persistSession,
|
|
1602
1748
|
includePartialMessages: opts?.includePartialMessages,
|
|
1749
|
+
forwardSubagentText: true,
|
|
1750
|
+
enableFileCheckpointing: true,
|
|
1751
|
+
extraArgs: { "replay-user-messages": null },
|
|
1603
1752
|
onElicitation: opts?.onElicitation,
|
|
1604
1753
|
onUserDialog: opts?.onUserDialog,
|
|
1605
1754
|
supportedDialogKinds: opts?.onUserDialog ? opts.supportedDialogKinds : void 0
|
|
@@ -2042,6 +2191,20 @@ async function claudeRemote(opts) {
|
|
|
2042
2191
|
content: initial.message
|
|
2043
2192
|
}
|
|
2044
2193
|
});
|
|
2194
|
+
let callbackDepth = 0;
|
|
2195
|
+
const guardCallback = (callback) => (async (...args) => {
|
|
2196
|
+
callbackDepth++;
|
|
2197
|
+
try {
|
|
2198
|
+
return await callback(...args);
|
|
2199
|
+
} finally {
|
|
2200
|
+
setImmediate(() => {
|
|
2201
|
+
callbackDepth--;
|
|
2202
|
+
});
|
|
2203
|
+
}
|
|
2204
|
+
});
|
|
2205
|
+
if (sdkOptions.canCallTool) sdkOptions.canCallTool = guardCallback(sdkOptions.canCallTool);
|
|
2206
|
+
if (sdkOptions.onElicitation) sdkOptions.onElicitation = guardCallback(sdkOptions.onElicitation);
|
|
2207
|
+
if (sdkOptions.onUserDialog) sdkOptions.onUserDialog = guardCallback(sdkOptions.onUserDialog);
|
|
2045
2208
|
const response = query({
|
|
2046
2209
|
prompt: messages,
|
|
2047
2210
|
options: sdkOptions
|
|
@@ -2062,6 +2225,15 @@ async function claudeRemote(opts) {
|
|
|
2062
2225
|
}
|
|
2063
2226
|
if (opts.onQueryReady) {
|
|
2064
2227
|
opts.onQueryReady({
|
|
2228
|
+
canControl: () => callbackDepth === 0,
|
|
2229
|
+
reloadSkills: () => response.reloadSkills(),
|
|
2230
|
+
reloadPlugins: () => response.reloadPlugins(),
|
|
2231
|
+
mcpServerStatus: () => response.mcpServerStatus(),
|
|
2232
|
+
reconnectMcpServer: (name) => response.reconnectMcpServer(name),
|
|
2233
|
+
toggleMcpServer: (name, enabled) => response.toggleMcpServer(name, enabled),
|
|
2234
|
+
stopTask: (id) => response.stopTask(id),
|
|
2235
|
+
backgroundTasks: (id) => response.backgroundTasks(id),
|
|
2236
|
+
rewindFiles: (id, options) => response.rewindFiles(id, options),
|
|
2065
2237
|
setPermissionMode: (mode2) => response.setPermissionMode(mode2),
|
|
2066
2238
|
setModel: (model) => response.setModel(modelTarget(model)),
|
|
2067
2239
|
interrupt: async () => {
|
|
@@ -2705,7 +2877,7 @@ class PermissionHandler {
|
|
|
2705
2877
|
} else if (pending.kind === "elicitation") {
|
|
2706
2878
|
pending.resolve(message.approved ? { action: "accept", content: elicitationContent(message.updatedInput) } : { action: message.decision === "abort" ? "cancel" : "decline" });
|
|
2707
2879
|
} else {
|
|
2708
|
-
pending.resolve(message.approved ? { behavior: "completed", result:
|
|
2880
|
+
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" });
|
|
2709
2881
|
}
|
|
2710
2882
|
this.recordCompletedRequest(id, effectiveResponse);
|
|
2711
2883
|
this.scheduleDeferredPermissionModeUpdate();
|
|
@@ -3167,6 +3339,7 @@ class SDKToLogConverter {
|
|
|
3167
3339
|
}
|
|
3168
3340
|
}
|
|
3169
3341
|
|
|
3342
|
+
const transcriptSystemSubtypes = /* @__PURE__ */ new Set(["task_started", "task_updated", "task_progress", "task_notification"]);
|
|
3170
3343
|
class OutgoingMessageQueue {
|
|
3171
3344
|
constructor(sendFunction) {
|
|
3172
3345
|
this.sendFunction = sendFunction;
|
|
@@ -3248,7 +3421,7 @@ class OutgoingMessageQueue {
|
|
|
3248
3421
|
break;
|
|
3249
3422
|
}
|
|
3250
3423
|
if (!item.sent) {
|
|
3251
|
-
if (item.logMessage.type !== "system") {
|
|
3424
|
+
if (item.logMessage.type !== "system" || transcriptSystemSubtypes.has(item.logMessage.subtype)) {
|
|
3252
3425
|
this.sendFunction(item.logMessage);
|
|
3253
3426
|
}
|
|
3254
3427
|
item.sent = true;
|
|
@@ -3876,6 +4049,8 @@ async function claudeRemoteLauncher(session, onPermissionModeChange, onEffective
|
|
|
3876
4049
|
let abortController = null;
|
|
3877
4050
|
let abortFuture = null;
|
|
3878
4051
|
const turnSteering = createTurnSteeringController();
|
|
4052
|
+
const runtimeControls = createRuntimeControls(() => session.thinking);
|
|
4053
|
+
session.client.rpcHandlerManager.registerHandler("claude-runtime-control", async (input) => runtimeControls.request(input));
|
|
3879
4054
|
async function abort() {
|
|
3880
4055
|
if (abortController && !abortController.signal.aborted) {
|
|
3881
4056
|
abortController.abort();
|
|
@@ -3936,6 +4111,8 @@ async function claudeRemoteLauncher(session, onPermissionModeChange, onEffective
|
|
|
3936
4111
|
let ongoingToolCalls = /* @__PURE__ */ new Map();
|
|
3937
4112
|
let notifiedQuestionToolCalls = /* @__PURE__ */ new Set();
|
|
3938
4113
|
function onMessage(message) {
|
|
4114
|
+
runtimeControls.observe(message);
|
|
4115
|
+
if (isRuntimeCheckpointReplay(message)) return;
|
|
3939
4116
|
if (message.type === "user" && isClaudeInterruptSentinelContent(message.message.content)) {
|
|
3940
4117
|
sdkToLogConverter.convert(message);
|
|
3941
4118
|
return;
|
|
@@ -4158,6 +4335,7 @@ async function claudeRemoteLauncher(session, onPermissionModeChange, onEffective
|
|
|
4158
4335
|
if (metadata.permissionMode) onEffectivePermissionMode?.(metadata.permissionMode);
|
|
4159
4336
|
},
|
|
4160
4337
|
onQueryReady: (q) => {
|
|
4338
|
+
runtimeControls.setQuery(q);
|
|
4161
4339
|
turnSteering.setInterrupt(q.interrupt);
|
|
4162
4340
|
session.setSteerHandler(async (input) => {
|
|
4163
4341
|
if (!modeGate.matches(input.mode)) return false;
|
|
@@ -4247,6 +4425,7 @@ async function claudeRemoteLauncher(session, onPermissionModeChange, onEffective
|
|
|
4247
4425
|
continue;
|
|
4248
4426
|
}
|
|
4249
4427
|
} finally {
|
|
4428
|
+
runtimeControls.setQuery(null);
|
|
4250
4429
|
turnSteering.reset();
|
|
4251
4430
|
session.setSteerHandler(null);
|
|
4252
4431
|
livePermissionModeHandler = null;
|
|
@@ -5297,6 +5476,80 @@ ${typeLabels[type] || type}:`));
|
|
|
5297
5476
|
console.log(chalk.green("\n\u2705 Doctor diagnosis complete!\n"));
|
|
5298
5477
|
}
|
|
5299
5478
|
|
|
5479
|
+
const AGENT_CHECK_INTERVAL = 6 * 60 * 60 * 1e3;
|
|
5480
|
+
function stableVersion(value) {
|
|
5481
|
+
const match = value.trim().match(/(?:^|\s|v)(\d+\.\d+\.\d+)([-+][\w.-]+)?(?=\s|$)/);
|
|
5482
|
+
return match && !match[2] ? match[1] : null;
|
|
5483
|
+
}
|
|
5484
|
+
function newerVersion(current, latest) {
|
|
5485
|
+
const a = current.split(".").map(Number), b = latest.split(".").map(Number);
|
|
5486
|
+
for (let i = 0; i < 3; i++) {
|
|
5487
|
+
if (b[i] !== a[i]) return b[i] > a[i];
|
|
5488
|
+
}
|
|
5489
|
+
return false;
|
|
5490
|
+
}
|
|
5491
|
+
const runVersionCommand = (command, args, shell) => new Promise((resolve, reject) => {
|
|
5492
|
+
execFile(
|
|
5493
|
+
command,
|
|
5494
|
+
args,
|
|
5495
|
+
{ timeout: 5e3, maxBuffer: 32 * 1024, windowsHide: true, shell },
|
|
5496
|
+
(error, stdout) => error ? reject(error) : resolve(stdout)
|
|
5497
|
+
);
|
|
5498
|
+
});
|
|
5499
|
+
async function probeAgentVersion(command, platform = process.platform, run = runVersionCommand) {
|
|
5500
|
+
if (platform === "win32") {
|
|
5501
|
+
try {
|
|
5502
|
+
await run("where.exe", [command], false);
|
|
5503
|
+
} catch (error) {
|
|
5504
|
+
return { version: null, missing: error.code === 1 };
|
|
5505
|
+
}
|
|
5506
|
+
}
|
|
5507
|
+
try {
|
|
5508
|
+
return { version: stableVersion(await run(command, ["--version"], platform === "win32")), missing: false };
|
|
5509
|
+
} catch (error) {
|
|
5510
|
+
return { version: null, missing: error.code === "ENOENT" };
|
|
5511
|
+
}
|
|
5512
|
+
}
|
|
5513
|
+
async function registryVersion(name) {
|
|
5514
|
+
const response = await fetch(`https://registry.npmjs.org/${encodeURIComponent(name)}/latest`, { signal: AbortSignal.timeout(5e3) });
|
|
5515
|
+
if (!response.ok) throw new Error("Registry unavailable");
|
|
5516
|
+
const data = await response.json();
|
|
5517
|
+
return typeof data.version === "string" ? stableVersion(data.version) : null;
|
|
5518
|
+
}
|
|
5519
|
+
async function detectAgentVersions(deps = { probe: probeAgentVersion, registryVersion }, now = Date.now()) {
|
|
5520
|
+
const agents = await Promise.all(AGENT_VERSION_SOURCES.map(async (source) => {
|
|
5521
|
+
const local = source.command ? await deps.probe(source.command).catch(() => ({ version: null, missing: false })) : { version: stableVersion(packageJson.dependencies["@anthropic-ai/claude-agent-sdk"]), missing: false };
|
|
5522
|
+
if (local.missing) return { id: source.id, installed: null, latest: null, status: "not-installed" };
|
|
5523
|
+
const latest = await deps.registryVersion(source.package).catch(() => null);
|
|
5524
|
+
const installed = local.version;
|
|
5525
|
+
const status = !installed || !latest ? "unknown" : newerVersion(installed, latest) ? "update-available" : "current";
|
|
5526
|
+
return { id: source.id, installed, latest, status };
|
|
5527
|
+
}));
|
|
5528
|
+
return { checkedAt: now, daemonPid: process.pid, agents };
|
|
5529
|
+
}
|
|
5530
|
+
function startAgentVersionChecks(publish, onError, detect = detectAgentVersions) {
|
|
5531
|
+
let stopped = false, pending = false;
|
|
5532
|
+
async function refresh() {
|
|
5533
|
+
if (stopped || pending) return;
|
|
5534
|
+
pending = true;
|
|
5535
|
+
try {
|
|
5536
|
+
const snapshot = await detect();
|
|
5537
|
+
if (!stopped) await publish(snapshot);
|
|
5538
|
+
} catch (error) {
|
|
5539
|
+
onError(error);
|
|
5540
|
+
} finally {
|
|
5541
|
+
pending = false;
|
|
5542
|
+
}
|
|
5543
|
+
}
|
|
5544
|
+
void refresh();
|
|
5545
|
+
const timer = setInterval(() => void refresh(), AGENT_CHECK_INTERVAL);
|
|
5546
|
+
timer.unref();
|
|
5547
|
+
return () => {
|
|
5548
|
+
stopped = true;
|
|
5549
|
+
clearInterval(timer);
|
|
5550
|
+
};
|
|
5551
|
+
}
|
|
5552
|
+
|
|
5300
5553
|
function sanitizeSpawnModel(value) {
|
|
5301
5554
|
if (typeof value !== "string") return null;
|
|
5302
5555
|
return /^[A-Za-z0-9][A-Za-z0-9._:/-]{0,255}(\[1m\])?$/i.test(value) ? value : null;
|
|
@@ -10969,6 +11222,10 @@ async function startDaemon() {
|
|
|
10969
11222
|
logger.warn(`[DAEMON RUN] Ignoring invalid HAPPY_CLI_UPDATE_CHECK_INTERVAL; using ${DEFAULT_CLI_UPDATE_CHECK_INTERVAL_MS}ms`);
|
|
10970
11223
|
}
|
|
10971
11224
|
const cliUpdateInterval = setInterval(() => void refreshCliUpdate(), cliUpdateIntervalMs);
|
|
11225
|
+
const stopAgentVersionChecks = startAgentVersionChecks(
|
|
11226
|
+
(snapshot) => apiMachine.updateDaemonState((state) => ({ ...state, status: state?.status ?? "running", agentVersions: snapshot })),
|
|
11227
|
+
(error) => logger.debug("[DAEMON RUN] Agent version check failed", error)
|
|
11228
|
+
);
|
|
10972
11229
|
const heartbeatIntervalMs = parseInt(process.env.HAPPY_DAEMON_HEARTBEAT_INTERVAL || "60000");
|
|
10973
11230
|
const restartOnStaleVersionAndHeartbeat = setInterval(serialTask(async () => {
|
|
10974
11231
|
try {
|
|
@@ -11009,6 +11266,7 @@ async function startDaemon() {
|
|
|
11009
11266
|
teamWorker?.stop();
|
|
11010
11267
|
clearInterval(restartOnStaleVersionAndHeartbeat);
|
|
11011
11268
|
clearInterval(cliUpdateInterval);
|
|
11269
|
+
stopAgentVersionChecks();
|
|
11012
11270
|
claudeAuthService.stop();
|
|
11013
11271
|
apiMachine.shutdown();
|
|
11014
11272
|
await stopControlServer();
|
|
@@ -11070,6 +11328,7 @@ async function startDaemon() {
|
|
|
11070
11328
|
logger.debug("[DAEMON RUN] Health check interval cleared");
|
|
11071
11329
|
}
|
|
11072
11330
|
clearInterval(cliUpdateInterval);
|
|
11331
|
+
stopAgentVersionChecks();
|
|
11073
11332
|
await apiMachine.updateDaemonState((state) => ({
|
|
11074
11333
|
...state,
|
|
11075
11334
|
status: "shutting-down",
|
|
@@ -12018,7 +12277,7 @@ function cleanupHookSettingsFile(filepath) {
|
|
|
12018
12277
|
}
|
|
12019
12278
|
}
|
|
12020
12279
|
|
|
12021
|
-
function registerKillSessionHandler(rpcHandlerManager, killThisHappy, archiveEvents) {
|
|
12280
|
+
function registerKillSessionHandler(rpcHandlerManager, killThisHappy, archiveEvents, options) {
|
|
12022
12281
|
let terminationStarted = false;
|
|
12023
12282
|
const terminateOnce = () => {
|
|
12024
12283
|
if (terminationStarted) return;
|
|
@@ -12026,6 +12285,10 @@ function registerKillSessionHandler(rpcHandlerManager, killThisHappy, archiveEve
|
|
|
12026
12285
|
void killThisHappy();
|
|
12027
12286
|
};
|
|
12028
12287
|
archiveEvents.on("archived", terminateOnce);
|
|
12288
|
+
if (options?.processSignals) {
|
|
12289
|
+
process.on("SIGTERM", terminateOnce);
|
|
12290
|
+
process.on("SIGINT", terminateOnce);
|
|
12291
|
+
}
|
|
12029
12292
|
rpcHandlerManager.registerHandler("killSession", async () => {
|
|
12030
12293
|
logger.debug("Kill session request received");
|
|
12031
12294
|
terminateOnce();
|
|
@@ -12034,6 +12297,13 @@ function registerKillSessionHandler(rpcHandlerManager, killThisHappy, archiveEve
|
|
|
12034
12297
|
message: "Killing happy-cli process"
|
|
12035
12298
|
};
|
|
12036
12299
|
});
|
|
12300
|
+
return () => {
|
|
12301
|
+
archiveEvents.off?.("archived", terminateOnce);
|
|
12302
|
+
if (options?.processSignals) {
|
|
12303
|
+
process.off("SIGTERM", terminateOnce);
|
|
12304
|
+
process.off("SIGINT", terminateOnce);
|
|
12305
|
+
}
|
|
12306
|
+
};
|
|
12037
12307
|
}
|
|
12038
12308
|
|
|
12039
12309
|
const SIDE_QUESTION_SYSTEM_PROMPT = [
|
|
@@ -12148,7 +12418,7 @@ function registerSideQuestionHandler(rpc, deps) {
|
|
|
12148
12418
|
const retainMs = deps.retainMs ?? SIDE_QUESTION_RETAIN_MS;
|
|
12149
12419
|
const maxRunMs = deps.maxRunMs ?? SIDE_QUESTION_MAX_RUN_MS;
|
|
12150
12420
|
const run = deps.run ?? (async (input) => {
|
|
12151
|
-
const { query } = await import('./index-
|
|
12421
|
+
const { query } = await import('./index-CpEdOGpe.mjs');
|
|
12152
12422
|
return runSideQuestion(query, input);
|
|
12153
12423
|
});
|
|
12154
12424
|
const slots = /* @__PURE__ */ new Map();
|
|
@@ -12711,7 +12981,7 @@ async function runClaude(credentials, options = {}) {
|
|
|
12711
12981
|
// a brand-new session cannot pick a PDF until after sending once.
|
|
12712
12982
|
attachmentKinds: [...CLAUDE_ATTACHMENT_KINDS],
|
|
12713
12983
|
queueCancellation: true,
|
|
12714
|
-
capabilities: ["claude-steer-v1", "claude-live-permission-v1", "claude-live-permission-v2", "claude-btw-v1"],
|
|
12984
|
+
capabilities: ["claude-steer-v1", "claude-live-permission-v1", "claude-live-permission-v2", "claude-btw-v1", "claude-runtime-controls-v1"],
|
|
12715
12985
|
// Effective mode this process enforces. Kept current by
|
|
12716
12986
|
// publishPermissionMode below; the web renders it instead of guessing.
|
|
12717
12987
|
permissionMode: mapToClaudeMode(initialPermissionMode ?? "default"),
|
|
@@ -14892,1269 +15162,1325 @@ async function ensureDaemonRunning() {
|
|
|
14892
15162
|
logger.debug(`Happy background service did not become ready within ${DAEMON_READY_TIMEOUT_MS}ms; continuing anyway`);
|
|
14893
15163
|
}
|
|
14894
15164
|
|
|
14895
|
-
function
|
|
14896
|
-
|
|
14897
|
-
const attachment = fileEvent.content.data.ev;
|
|
14898
|
-
const download = (async () => {
|
|
14899
|
-
try {
|
|
14900
|
-
const data = await session.downloadAndDecryptAttachment(attachment.ref);
|
|
14901
|
-
if (!data) throw new Error("Attachment decryption failed");
|
|
14902
|
-
return { data, mimeType: attachment.mimeType ?? "image/jpeg", name: attachment.name };
|
|
14903
|
-
} catch {
|
|
14904
|
-
session.sendSessionEvent({ type: "message", message: `Could not download attachment: ${attachment.name}. Please attach it again.` });
|
|
14905
|
-
return null;
|
|
14906
|
-
}
|
|
14907
|
-
})();
|
|
14908
|
-
session.trackAttachmentDownload(download);
|
|
14909
|
-
});
|
|
15165
|
+
function getStartedSubagents(state) {
|
|
15166
|
+
return state.startedSubagents ?? /* @__PURE__ */ new Set();
|
|
14910
15167
|
}
|
|
14911
|
-
|
|
14912
|
-
|
|
14913
|
-
|
|
14914
|
-
|
|
14915
|
-
|
|
14916
|
-
|
|
14917
|
-
|
|
14918
|
-
|
|
15168
|
+
function getActiveSubagents(state) {
|
|
15169
|
+
return state.activeSubagents ?? /* @__PURE__ */ new Set();
|
|
15170
|
+
}
|
|
15171
|
+
function getProviderSubagentToSessionSubagent(state) {
|
|
15172
|
+
return state.providerSubagentToSessionSubagent ?? /* @__PURE__ */ new Map();
|
|
15173
|
+
}
|
|
15174
|
+
function maybeEmitSubagentStart(subagent, opts, startedSubagents, activeSubagents, envelopes) {
|
|
15175
|
+
if (!subagent || startedSubagents.has(subagent)) {
|
|
15176
|
+
return;
|
|
14919
15177
|
}
|
|
14920
|
-
|
|
14921
|
-
|
|
14922
|
-
|
|
14923
|
-
|
|
14924
|
-
|
|
14925
|
-
|
|
14926
|
-
|
|
14927
|
-
|
|
15178
|
+
envelopes.push(createEnvelope("agent", { t: "start" }, { ...opts, subagent }));
|
|
15179
|
+
startedSubagents.add(subagent);
|
|
15180
|
+
activeSubagents.add(subagent);
|
|
15181
|
+
}
|
|
15182
|
+
function emitSubagentStops(opts, startedSubagents, activeSubagents) {
|
|
15183
|
+
const envelopes = [];
|
|
15184
|
+
for (const subagent of activeSubagents) {
|
|
15185
|
+
envelopes.push(createEnvelope("agent", { t: "stop" }, { ...opts, subagent }));
|
|
14928
15186
|
}
|
|
14929
|
-
|
|
14930
|
-
|
|
14931
|
-
|
|
14932
|
-
|
|
14933
|
-
|
|
14934
|
-
|
|
14935
|
-
|
|
14936
|
-
|
|
14937
|
-
|
|
14938
|
-
|
|
14939
|
-
|
|
14940
|
-
|
|
14941
|
-
|
|
14942
|
-
|
|
14943
|
-
|
|
14944
|
-
|
|
14945
|
-
const request = currentState.requests?.[response.id];
|
|
14946
|
-
if (!request) return currentState;
|
|
14947
|
-
const { [response.id]: _, ...remainingRequests } = currentState.requests || {};
|
|
14948
|
-
let res = {
|
|
14949
|
-
...currentState,
|
|
14950
|
-
requests: remainingRequests,
|
|
14951
|
-
completedRequests: {
|
|
14952
|
-
...currentState.completedRequests,
|
|
14953
|
-
[response.id]: {
|
|
14954
|
-
...request,
|
|
14955
|
-
completedAt: Date.now(),
|
|
14956
|
-
status: response.approved ? "approved" : "denied",
|
|
14957
|
-
decision: result.decision
|
|
14958
|
-
}
|
|
14959
|
-
}
|
|
14960
|
-
};
|
|
14961
|
-
return res;
|
|
14962
|
-
});
|
|
14963
|
-
logger.debug(`${this.getLogPrefix()} Permission ${response.approved ? "approved" : "denied"} for ${pending.toolName}`);
|
|
14964
|
-
}
|
|
14965
|
-
);
|
|
15187
|
+
activeSubagents.clear();
|
|
15188
|
+
startedSubagents.clear();
|
|
15189
|
+
return envelopes;
|
|
15190
|
+
}
|
|
15191
|
+
function buildEnvelopeOptions(currentTurnId, subagent) {
|
|
15192
|
+
return {
|
|
15193
|
+
...currentTurnId ? { turn: currentTurnId } : {},
|
|
15194
|
+
...subagent ? { subagent } : {}
|
|
15195
|
+
};
|
|
15196
|
+
}
|
|
15197
|
+
function pickProviderSubagent(message) {
|
|
15198
|
+
const candidates = [message.subagent, message.parent_call_id, message.parentCallId];
|
|
15199
|
+
for (const candidate of candidates) {
|
|
15200
|
+
if (typeof candidate === "string" && candidate.length > 0) {
|
|
15201
|
+
return candidate;
|
|
15202
|
+
}
|
|
14966
15203
|
}
|
|
14967
|
-
|
|
14968
|
-
|
|
14969
|
-
|
|
14970
|
-
|
|
14971
|
-
|
|
14972
|
-
|
|
14973
|
-
requests: {
|
|
14974
|
-
...currentState.requests,
|
|
14975
|
-
[toolCallId]: {
|
|
14976
|
-
tool: toolName,
|
|
14977
|
-
arguments: input,
|
|
14978
|
-
createdAt: Date.now()
|
|
14979
|
-
}
|
|
14980
|
-
}
|
|
14981
|
-
}));
|
|
15204
|
+
return void 0;
|
|
15205
|
+
}
|
|
15206
|
+
function resolveSessionSubagent(message, providerSubagentToSessionSubagent) {
|
|
15207
|
+
const providerSubagent = pickProviderSubagent(message);
|
|
15208
|
+
if (!providerSubagent) {
|
|
15209
|
+
return void 0;
|
|
14982
15210
|
}
|
|
14983
|
-
|
|
14984
|
-
|
|
14985
|
-
|
|
14986
|
-
* causing the approval response to send 'cancel' to the provider. This is used when the
|
|
14987
|
-
* user presses the abort/stop button — it unblocks any pending tool approval so the provider
|
|
14988
|
-
* can process the turn cancellation.
|
|
14989
|
-
*/
|
|
14990
|
-
abortAll() {
|
|
14991
|
-
const pendingSnapshot = Array.from(this.pendingRequests.entries());
|
|
14992
|
-
if (pendingSnapshot.length === 0) return;
|
|
14993
|
-
this.pendingRequests.clear();
|
|
14994
|
-
for (const [id, pending] of pendingSnapshot) {
|
|
14995
|
-
try {
|
|
14996
|
-
pending.resolve({ decision: "abort" });
|
|
14997
|
-
} catch (err) {
|
|
14998
|
-
logger.debug(`${this.getLogPrefix()} Error resolving aborted request ${id}:`, err);
|
|
14999
|
-
}
|
|
15000
|
-
}
|
|
15001
|
-
this.session.updateAgentState((currentState) => {
|
|
15002
|
-
const pendingRequests = currentState.requests || {};
|
|
15003
|
-
const completedRequests = { ...currentState.completedRequests };
|
|
15004
|
-
for (const [id, request] of Object.entries(pendingRequests)) {
|
|
15005
|
-
completedRequests[id] = {
|
|
15006
|
-
...request,
|
|
15007
|
-
completedAt: Date.now(),
|
|
15008
|
-
status: "canceled",
|
|
15009
|
-
reason: "Aborted by user"
|
|
15010
|
-
};
|
|
15011
|
-
}
|
|
15012
|
-
return {
|
|
15013
|
-
...currentState,
|
|
15014
|
-
requests: {},
|
|
15015
|
-
completedRequests
|
|
15016
|
-
};
|
|
15017
|
-
});
|
|
15018
|
-
logger.debug(`${this.getLogPrefix()} Aborted ${pendingSnapshot.length} pending permission(s)`);
|
|
15019
|
-
}
|
|
15020
|
-
/**
|
|
15021
|
-
* Reset state for new sessions.
|
|
15022
|
-
* This method is idempotent - safe to call multiple times.
|
|
15023
|
-
*/
|
|
15024
|
-
reset(reason = "Session reset") {
|
|
15025
|
-
if (this.isResetting) {
|
|
15026
|
-
logger.debug(`${this.getLogPrefix()} Reset already in progress, skipping`);
|
|
15027
|
-
return;
|
|
15028
|
-
}
|
|
15029
|
-
this.isResetting = true;
|
|
15030
|
-
try {
|
|
15031
|
-
const pendingSnapshot = Array.from(this.pendingRequests.entries());
|
|
15032
|
-
this.pendingRequests.clear();
|
|
15033
|
-
for (const [id, pending] of pendingSnapshot) {
|
|
15034
|
-
try {
|
|
15035
|
-
pending.reject(new Error("Session reset"));
|
|
15036
|
-
} catch (err) {
|
|
15037
|
-
logger.debug(`${this.getLogPrefix()} Error rejecting pending request ${id}:`, err);
|
|
15038
|
-
}
|
|
15039
|
-
}
|
|
15040
|
-
this.session.updateAgentState((currentState) => {
|
|
15041
|
-
const pendingRequests = currentState.requests || {};
|
|
15042
|
-
const completedRequests = { ...currentState.completedRequests };
|
|
15043
|
-
for (const [id, request] of Object.entries(pendingRequests)) {
|
|
15044
|
-
completedRequests[id] = {
|
|
15045
|
-
...request,
|
|
15046
|
-
completedAt: Date.now(),
|
|
15047
|
-
status: "canceled",
|
|
15048
|
-
reason
|
|
15049
|
-
};
|
|
15050
|
-
}
|
|
15051
|
-
return {
|
|
15052
|
-
...currentState,
|
|
15053
|
-
requests: {},
|
|
15054
|
-
completedRequests
|
|
15055
|
-
};
|
|
15056
|
-
});
|
|
15057
|
-
logger.debug(`${this.getLogPrefix()} Permission handler reset`);
|
|
15058
|
-
} finally {
|
|
15059
|
-
this.isResetting = false;
|
|
15060
|
-
}
|
|
15211
|
+
const existing = providerSubagentToSessionSubagent.get(providerSubagent);
|
|
15212
|
+
if (existing) {
|
|
15213
|
+
return existing;
|
|
15061
15214
|
}
|
|
15215
|
+
const created = createId();
|
|
15216
|
+
providerSubagentToSessionSubagent.set(providerSubagent, created);
|
|
15217
|
+
return created;
|
|
15062
15218
|
}
|
|
15063
|
-
|
|
15064
|
-
|
|
15065
|
-
|
|
15066
|
-
|
|
15067
|
-
// and the MCP-qualified form for defense in depth.
|
|
15068
|
-
static ALWAYS_AUTO_APPROVE_NAMES = /* @__PURE__ */ new Set([
|
|
15069
|
-
"change_title",
|
|
15070
|
-
"mcp__happy__change_title"
|
|
15071
|
-
]);
|
|
15072
|
-
// Tool-call IDs that should auto-approve when they exactly match one of
|
|
15073
|
-
// these values or start with `<name>-` (e.g. `change_title-1765385846663`).
|
|
15074
|
-
// Substring matching was a bypass vector — any tool whose ID happened to
|
|
15075
|
-
// contain `change_title` as a substring would be silently approved.
|
|
15076
|
-
static ALWAYS_AUTO_APPROVE_ID_PREFIXES = [
|
|
15077
|
-
"change_title"
|
|
15078
|
-
];
|
|
15079
|
-
constructor(session) {
|
|
15080
|
-
super(session);
|
|
15219
|
+
function pickCallId(message) {
|
|
15220
|
+
const callId = message.call_id ?? message.callId;
|
|
15221
|
+
if (typeof callId === "string" && callId.length > 0) {
|
|
15222
|
+
return callId;
|
|
15081
15223
|
}
|
|
15082
|
-
|
|
15083
|
-
|
|
15224
|
+
return randomUUID();
|
|
15225
|
+
}
|
|
15226
|
+
function summarizeCommand(command) {
|
|
15227
|
+
if (typeof command === "string" && command.trim().length > 0) {
|
|
15228
|
+
return command;
|
|
15084
15229
|
}
|
|
15085
|
-
|
|
15086
|
-
|
|
15087
|
-
|
|
15088
|
-
}
|
|
15089
|
-
for (const prefix of CodexPermissionHandler.ALWAYS_AUTO_APPROVE_ID_PREFIXES) {
|
|
15090
|
-
if (toolCallId === prefix || toolCallId.startsWith(`${prefix}-`)) {
|
|
15091
|
-
return true;
|
|
15092
|
-
}
|
|
15093
|
-
}
|
|
15094
|
-
return false;
|
|
15230
|
+
if (Array.isArray(command)) {
|
|
15231
|
+
const cmd = command.map((v) => String(v)).join(" ").trim();
|
|
15232
|
+
return cmd.length > 0 ? cmd : null;
|
|
15095
15233
|
}
|
|
15096
|
-
|
|
15097
|
-
|
|
15098
|
-
|
|
15099
|
-
|
|
15100
|
-
|
|
15101
|
-
* @returns Promise resolving to permission result
|
|
15102
|
-
*/
|
|
15103
|
-
async handleToolCall(toolCallId, toolName, input) {
|
|
15104
|
-
if (this.shouldAutoApprove(toolName, toolCallId)) {
|
|
15105
|
-
logger.debug(`${this.getLogPrefix()} Auto-approving tool ${toolName} (${toolCallId})`);
|
|
15106
|
-
this.session.updateAgentState((currentState) => ({
|
|
15107
|
-
...currentState,
|
|
15108
|
-
completedRequests: {
|
|
15109
|
-
...currentState.completedRequests,
|
|
15110
|
-
[toolCallId]: {
|
|
15111
|
-
tool: toolName,
|
|
15112
|
-
arguments: input,
|
|
15113
|
-
createdAt: Date.now(),
|
|
15114
|
-
completedAt: Date.now(),
|
|
15115
|
-
status: "approved",
|
|
15116
|
-
decision: "approved"
|
|
15117
|
-
}
|
|
15118
|
-
}
|
|
15119
|
-
}));
|
|
15120
|
-
return { decision: "approved" };
|
|
15121
|
-
}
|
|
15122
|
-
return new Promise((resolve, reject) => {
|
|
15123
|
-
this.pendingRequests.set(toolCallId, {
|
|
15124
|
-
resolve,
|
|
15125
|
-
reject,
|
|
15126
|
-
toolName,
|
|
15127
|
-
input
|
|
15128
|
-
});
|
|
15129
|
-
this.addPendingRequestToState(toolCallId, toolName, input);
|
|
15130
|
-
logger.debug(`${this.getLogPrefix()} Permission request sent for tool: ${toolName} (${toolCallId})`);
|
|
15131
|
-
});
|
|
15234
|
+
return null;
|
|
15235
|
+
}
|
|
15236
|
+
function commandToTitle(command) {
|
|
15237
|
+
if (!command) {
|
|
15238
|
+
return "Run command";
|
|
15132
15239
|
}
|
|
15240
|
+
const short = command.length > 80 ? `${command.slice(0, 77)}...` : command;
|
|
15241
|
+
return `Run \`${short}\``;
|
|
15133
15242
|
}
|
|
15134
|
-
|
|
15135
|
-
|
|
15136
|
-
|
|
15137
|
-
|
|
15138
|
-
|
|
15139
|
-
|
|
15140
|
-
|
|
15141
|
-
|
|
15142
|
-
|
|
15143
|
-
|
|
15144
|
-
|
|
15145
|
-
constructor(onMessage) {
|
|
15146
|
-
this.onMessage = onMessage || null;
|
|
15147
|
-
this.reset();
|
|
15243
|
+
function turnTimestampMs(turn) {
|
|
15244
|
+
const seconds = turn.startedAt ?? turn.completedAt;
|
|
15245
|
+
return typeof seconds === "number" && Number.isFinite(seconds) ? seconds * 1e3 : Date.now();
|
|
15246
|
+
}
|
|
15247
|
+
function completedTimestampMs(turn) {
|
|
15248
|
+
const seconds = turn.completedAt ?? turn.startedAt;
|
|
15249
|
+
return typeof seconds === "number" && Number.isFinite(seconds) ? seconds * 1e3 : Date.now();
|
|
15250
|
+
}
|
|
15251
|
+
function textFromInputItems(items) {
|
|
15252
|
+
if (!Array.isArray(items)) {
|
|
15253
|
+
return null;
|
|
15148
15254
|
}
|
|
15149
|
-
|
|
15150
|
-
|
|
15151
|
-
|
|
15152
|
-
|
|
15153
|
-
|
|
15255
|
+
const text = items.filter((item) => Boolean(item) && typeof item === "object" && item.type === "text" && typeof item.text === "string").map((item) => item.text).join("\n").trim();
|
|
15256
|
+
return text.length > 0 ? text : null;
|
|
15257
|
+
}
|
|
15258
|
+
function reasoningText(item) {
|
|
15259
|
+
const summary = item.summary;
|
|
15260
|
+
const content = item.content;
|
|
15261
|
+
const parts = [
|
|
15262
|
+
...Array.isArray(summary) ? summary : [],
|
|
15263
|
+
...Array.isArray(content) ? content : []
|
|
15264
|
+
].filter((value) => typeof value === "string" && value.trim().length > 0);
|
|
15265
|
+
const text = parts.join("\n").trim();
|
|
15266
|
+
return text.length > 0 ? text : null;
|
|
15267
|
+
}
|
|
15268
|
+
function turnStatus(turn) {
|
|
15269
|
+
const status = typeof turn.status === "string" ? turn.status : null;
|
|
15270
|
+
if (status === "failed") {
|
|
15271
|
+
return "failed";
|
|
15154
15272
|
}
|
|
15155
|
-
|
|
15156
|
-
|
|
15157
|
-
*/
|
|
15158
|
-
handleSectionBreak() {
|
|
15159
|
-
this.finishCurrentToolCall("canceled");
|
|
15160
|
-
this.resetState();
|
|
15161
|
-
logger.debug(`${this.getLogPrefix()} Section break - reset state`);
|
|
15273
|
+
if (status === "cancelled" || status === "canceled" || status === "aborted" || status === "interrupted") {
|
|
15274
|
+
return "cancelled";
|
|
15162
15275
|
}
|
|
15163
|
-
|
|
15164
|
-
|
|
15165
|
-
|
|
15166
|
-
|
|
15167
|
-
|
|
15168
|
-
|
|
15169
|
-
|
|
15170
|
-
|
|
15171
|
-
|
|
15172
|
-
|
|
15173
|
-
|
|
15174
|
-
|
|
15175
|
-
|
|
15176
|
-
|
|
15177
|
-
|
|
15178
|
-
|
|
15179
|
-
|
|
15180
|
-
|
|
15181
|
-
|
|
15182
|
-
|
|
15183
|
-
|
|
15184
|
-
|
|
15185
|
-
|
|
15186
|
-
|
|
15187
|
-
|
|
15188
|
-
this.sendToolCallStart(title);
|
|
15189
|
-
}
|
|
15190
|
-
} else if (this.hasTitle) {
|
|
15191
|
-
const titleStartIndex = this.accumulator.indexOf("**");
|
|
15192
|
-
if (titleStartIndex !== -1) {
|
|
15193
|
-
this.contentBuffer = this.accumulator.substring(
|
|
15194
|
-
titleStartIndex + 2 + this.currentTitle.length + 2
|
|
15195
|
-
);
|
|
15196
|
-
}
|
|
15197
|
-
} else {
|
|
15198
|
-
this.contentBuffer = this.accumulator;
|
|
15199
|
-
}
|
|
15276
|
+
return "completed";
|
|
15277
|
+
}
|
|
15278
|
+
function emitHistoricalToolCall(envelopes, turn, item, name, title, args, output) {
|
|
15279
|
+
const time = turnTimestampMs(turn);
|
|
15280
|
+
const opts = { turn: turn.id, time, codexItemId: item.id };
|
|
15281
|
+
envelopes.push(createEnvelope("agent", {
|
|
15282
|
+
t: "tool-call-start",
|
|
15283
|
+
call: item.id,
|
|
15284
|
+
name,
|
|
15285
|
+
title,
|
|
15286
|
+
description: title,
|
|
15287
|
+
args
|
|
15288
|
+
}, {
|
|
15289
|
+
...opts,
|
|
15290
|
+
id: `${item.id}:start`
|
|
15291
|
+
}));
|
|
15292
|
+
if (output && output.trim().length > 0) {
|
|
15293
|
+
envelopes.push(createEnvelope("agent", {
|
|
15294
|
+
t: "text",
|
|
15295
|
+
text: output,
|
|
15296
|
+
thinking: true
|
|
15297
|
+
}, {
|
|
15298
|
+
...opts,
|
|
15299
|
+
id: `${item.id}:output`
|
|
15300
|
+
}));
|
|
15200
15301
|
}
|
|
15201
|
-
|
|
15202
|
-
|
|
15203
|
-
|
|
15204
|
-
|
|
15205
|
-
|
|
15206
|
-
|
|
15207
|
-
}
|
|
15208
|
-
|
|
15209
|
-
|
|
15210
|
-
|
|
15211
|
-
|
|
15212
|
-
|
|
15213
|
-
|
|
15214
|
-
|
|
15215
|
-
|
|
15216
|
-
|
|
15217
|
-
|
|
15218
|
-
|
|
15219
|
-
|
|
15302
|
+
if ("status" in item && (item.status === "inProgress" || item.status === "running")) return;
|
|
15303
|
+
envelopes.push(createEnvelope("agent", {
|
|
15304
|
+
t: "tool-call-end",
|
|
15305
|
+
call: item.id
|
|
15306
|
+
}, {
|
|
15307
|
+
...opts,
|
|
15308
|
+
id: `${item.id}:end`,
|
|
15309
|
+
time: completedTimestampMs(turn)
|
|
15310
|
+
}));
|
|
15311
|
+
}
|
|
15312
|
+
function mapCodexCollaborationItem(item, opts = {}, source = "history") {
|
|
15313
|
+
if (item.type === "subAgentActivity" && typeof item.agentThreadId === "string") {
|
|
15314
|
+
item = { ...item, type: "collabAgentToolCall", tool: item.kind, status: "completed", receiverThreadIds: [item.agentThreadId] };
|
|
15315
|
+
}
|
|
15316
|
+
if (item.type !== "collabAgentToolCall" || typeof item.id !== "string" || typeof item.tool !== "string") return [];
|
|
15317
|
+
const args = {
|
|
15318
|
+
operation: item.tool,
|
|
15319
|
+
...typeof item.prompt === "string" ? { prompt: item.prompt } : {},
|
|
15320
|
+
...typeof item.model === "string" ? { model: item.model } : {},
|
|
15321
|
+
receiverThreadIds: Array.isArray(item.receiverThreadIds) ? item.receiverThreadIds : [],
|
|
15322
|
+
agentsStates: item.agentsStates ?? {}
|
|
15323
|
+
};
|
|
15324
|
+
const startId = source === "live" ? `${item.id}:${item.status ?? "unknown"}:start` : `${item.id}:start`;
|
|
15325
|
+
const envelopes = [createEnvelope("agent", {
|
|
15326
|
+
t: "tool-call-start",
|
|
15327
|
+
call: item.id,
|
|
15328
|
+
name: "CodexCollaboration",
|
|
15329
|
+
title: `Codex \xB7 ${item.tool}`,
|
|
15330
|
+
description: `Codex \xB7 ${item.tool}`,
|
|
15331
|
+
args
|
|
15332
|
+
}, { ...opts, id: startId })];
|
|
15333
|
+
if (item.status === "completed" || item.status === "failed" || item.status === "interrupted") {
|
|
15334
|
+
envelopes.push(createEnvelope("agent", {
|
|
15335
|
+
t: "tool-call-end",
|
|
15336
|
+
call: item.id,
|
|
15337
|
+
result: { text: JSON.stringify(args, null, 2), isError: item.status !== "completed" }
|
|
15338
|
+
}, { ...opts, id: `${item.id}:end` }));
|
|
15220
15339
|
}
|
|
15221
|
-
|
|
15222
|
-
|
|
15223
|
-
|
|
15224
|
-
|
|
15225
|
-
|
|
15226
|
-
const
|
|
15227
|
-
|
|
15228
|
-
|
|
15229
|
-
|
|
15230
|
-
|
|
15231
|
-
|
|
15232
|
-
|
|
15233
|
-
|
|
15234
|
-
|
|
15235
|
-
|
|
15236
|
-
|
|
15237
|
-
|
|
15340
|
+
return envelopes;
|
|
15341
|
+
}
|
|
15342
|
+
function mapCodexThreadToSessionEnvelopes(thread) {
|
|
15343
|
+
const envelopes = [];
|
|
15344
|
+
for (const turn of thread.turns ?? []) {
|
|
15345
|
+
const startedAt = turnTimestampMs(turn);
|
|
15346
|
+
const completedAt = completedTimestampMs(turn);
|
|
15347
|
+
envelopes.push(createEnvelope("agent", { t: "turn-start" }, {
|
|
15348
|
+
id: `${turn.id}:start`,
|
|
15349
|
+
turn: turn.id,
|
|
15350
|
+
time: startedAt
|
|
15351
|
+
}));
|
|
15352
|
+
for (const item of turn.items ?? []) {
|
|
15353
|
+
switch (item.type) {
|
|
15354
|
+
case "subAgentActivity":
|
|
15355
|
+
case "collabAgentToolCall": {
|
|
15356
|
+
envelopes.push(...mapCodexCollaborationItem(item, { turn: turn.id, time: startedAt, codexItemId: item.id }));
|
|
15357
|
+
break;
|
|
15358
|
+
}
|
|
15359
|
+
case "userMessage": {
|
|
15360
|
+
const text = textFromInputItems(item.content);
|
|
15361
|
+
if (text) {
|
|
15362
|
+
envelopes.push(createEnvelope("user", { t: "text", text }, {
|
|
15363
|
+
id: item.id,
|
|
15364
|
+
time: startedAt,
|
|
15365
|
+
codexItemId: item.id
|
|
15366
|
+
}));
|
|
15367
|
+
}
|
|
15368
|
+
break;
|
|
15369
|
+
}
|
|
15370
|
+
case "agentMessage": {
|
|
15371
|
+
const text = typeof item.text === "string" ? item.text.trim() : "";
|
|
15372
|
+
if (text.length > 0) {
|
|
15373
|
+
envelopes.push(createEnvelope("agent", { t: "text", text }, {
|
|
15374
|
+
id: item.id,
|
|
15375
|
+
turn: turn.id,
|
|
15376
|
+
time: completedAt,
|
|
15377
|
+
codexItemId: item.id
|
|
15378
|
+
}));
|
|
15379
|
+
}
|
|
15380
|
+
break;
|
|
15381
|
+
}
|
|
15382
|
+
case "reasoning": {
|
|
15383
|
+
const text = reasoningText(item);
|
|
15384
|
+
if (text) {
|
|
15385
|
+
envelopes.push(createEnvelope("agent", { t: "text", text, thinking: true }, {
|
|
15386
|
+
id: item.id,
|
|
15387
|
+
turn: turn.id,
|
|
15388
|
+
time: startedAt,
|
|
15389
|
+
codexItemId: item.id
|
|
15390
|
+
}));
|
|
15391
|
+
}
|
|
15392
|
+
break;
|
|
15393
|
+
}
|
|
15394
|
+
case "commandExecution": {
|
|
15395
|
+
const command = typeof item.command === "string" ? item.command : "";
|
|
15396
|
+
emitHistoricalToolCall(
|
|
15397
|
+
envelopes,
|
|
15398
|
+
turn,
|
|
15399
|
+
item,
|
|
15400
|
+
"CodexBash",
|
|
15401
|
+
commandToTitle(command),
|
|
15402
|
+
{ command, cwd: item.cwd },
|
|
15403
|
+
typeof item.aggregatedOutput === "string" ? item.aggregatedOutput : null
|
|
15404
|
+
);
|
|
15405
|
+
break;
|
|
15406
|
+
}
|
|
15407
|
+
case "fileChange": {
|
|
15408
|
+
const title = "Apply patch";
|
|
15409
|
+
emitHistoricalToolCall(
|
|
15410
|
+
envelopes,
|
|
15411
|
+
turn,
|
|
15412
|
+
item,
|
|
15413
|
+
"CodexPatch",
|
|
15414
|
+
title,
|
|
15415
|
+
{ changes: item.changes, status: item.status },
|
|
15416
|
+
null
|
|
15417
|
+
);
|
|
15418
|
+
break;
|
|
15419
|
+
}
|
|
15420
|
+
case "mcpToolCall": {
|
|
15421
|
+
const title = `${item.server}.${item.tool}`;
|
|
15422
|
+
const output = item.error !== void 0 && item.error !== null ? String(item.error) : item.result !== void 0 && item.result !== null ? String(item.result) : null;
|
|
15423
|
+
emitHistoricalToolCall(
|
|
15424
|
+
envelopes,
|
|
15425
|
+
turn,
|
|
15426
|
+
item,
|
|
15427
|
+
"McpTool",
|
|
15428
|
+
title,
|
|
15429
|
+
{
|
|
15430
|
+
server: item.server,
|
|
15431
|
+
tool: item.tool,
|
|
15432
|
+
arguments: item.arguments
|
|
15433
|
+
},
|
|
15434
|
+
output
|
|
15435
|
+
);
|
|
15436
|
+
break;
|
|
15437
|
+
}
|
|
15238
15438
|
}
|
|
15239
15439
|
}
|
|
15240
|
-
|
|
15241
|
-
|
|
15242
|
-
|
|
15243
|
-
|
|
15244
|
-
}
|
|
15245
|
-
if (this.toolCallStarted && this.currentCallId) {
|
|
15246
|
-
const toolResult = {
|
|
15247
|
-
type: "tool-call-result",
|
|
15248
|
-
callId: this.currentCallId,
|
|
15249
|
-
output: {
|
|
15250
|
-
content,
|
|
15251
|
-
status: "completed"
|
|
15252
|
-
},
|
|
15253
|
-
id: randomUUID()
|
|
15254
|
-
};
|
|
15255
|
-
logger.debug(`${this.getLogPrefix()} Sending tool call result`);
|
|
15256
|
-
this.onMessage?.(toolResult);
|
|
15257
|
-
} else if (content.trim()) {
|
|
15258
|
-
const reasoningMessage = {
|
|
15259
|
-
type: "reasoning",
|
|
15260
|
-
message: content,
|
|
15261
|
-
id: randomUUID()
|
|
15262
|
-
};
|
|
15263
|
-
logger.debug(`${this.getLogPrefix()} Sending reasoning message`);
|
|
15264
|
-
this.onMessage?.(reasoningMessage);
|
|
15265
|
-
}
|
|
15266
|
-
this.resetState();
|
|
15267
|
-
return true;
|
|
15268
|
-
}
|
|
15269
|
-
/**
|
|
15270
|
-
* Abort the current reasoning section.
|
|
15271
|
-
*/
|
|
15272
|
-
abort() {
|
|
15273
|
-
logger.debug(`${this.getLogPrefix()} Abort called`);
|
|
15274
|
-
this.finishCurrentToolCall("canceled");
|
|
15275
|
-
this.resetState();
|
|
15276
|
-
}
|
|
15277
|
-
/**
|
|
15278
|
-
* Reset the processor state.
|
|
15279
|
-
*/
|
|
15280
|
-
reset() {
|
|
15281
|
-
this.finishCurrentToolCall("canceled");
|
|
15282
|
-
this.resetState();
|
|
15283
|
-
}
|
|
15284
|
-
/**
|
|
15285
|
-
* Finish current tool call if one is in progress.
|
|
15286
|
-
*/
|
|
15287
|
-
finishCurrentToolCall(status) {
|
|
15288
|
-
if (this.toolCallStarted && this.currentCallId) {
|
|
15289
|
-
const toolResult = {
|
|
15290
|
-
type: "tool-call-result",
|
|
15291
|
-
callId: this.currentCallId,
|
|
15292
|
-
output: {
|
|
15293
|
-
content: this.contentBuffer || "",
|
|
15294
|
-
status
|
|
15295
|
-
},
|
|
15296
|
-
id: randomUUID()
|
|
15297
|
-
};
|
|
15298
|
-
logger.debug(`${this.getLogPrefix()} Sending tool call result with status: ${status}`);
|
|
15299
|
-
this.onMessage?.(toolResult);
|
|
15300
|
-
}
|
|
15301
|
-
}
|
|
15302
|
-
/**
|
|
15303
|
-
* Reset internal state.
|
|
15304
|
-
*/
|
|
15305
|
-
resetState() {
|
|
15306
|
-
this.accumulator = "";
|
|
15307
|
-
this.inTitleCapture = false;
|
|
15308
|
-
this.titleBuffer = "";
|
|
15309
|
-
this.contentBuffer = "";
|
|
15310
|
-
this.hasTitle = false;
|
|
15311
|
-
this.currentCallId = null;
|
|
15312
|
-
this.toolCallStarted = false;
|
|
15313
|
-
this.currentTitle = null;
|
|
15440
|
+
envelopes.push(createEnvelope("agent", { t: "turn-end", status: turnStatus(turn) }, {
|
|
15441
|
+
id: `${turn.id}:end`,
|
|
15442
|
+
turn: turn.id,
|
|
15443
|
+
time: completedAt
|
|
15444
|
+
}));
|
|
15314
15445
|
}
|
|
15315
|
-
|
|
15316
|
-
|
|
15317
|
-
|
|
15318
|
-
|
|
15319
|
-
return
|
|
15446
|
+
return envelopes;
|
|
15447
|
+
}
|
|
15448
|
+
function patchDescription(changes) {
|
|
15449
|
+
if (!changes || typeof changes !== "object") {
|
|
15450
|
+
return "Applying patch";
|
|
15320
15451
|
}
|
|
15321
|
-
|
|
15322
|
-
|
|
15323
|
-
|
|
15324
|
-
hasStartedToolCall() {
|
|
15325
|
-
return this.toolCallStarted;
|
|
15452
|
+
const fileCount = Object.keys(changes).length;
|
|
15453
|
+
if (fileCount === 1) {
|
|
15454
|
+
return "Applying patch to 1 file";
|
|
15326
15455
|
}
|
|
15456
|
+
return `Applying patch to ${fileCount} files`;
|
|
15327
15457
|
}
|
|
15328
|
-
|
|
15329
|
-
|
|
15330
|
-
|
|
15331
|
-
return
|
|
15458
|
+
function pickTurnEndStatus(message, type) {
|
|
15459
|
+
const rawStatus = message.status;
|
|
15460
|
+
if (rawStatus === "completed" || rawStatus === "failed" || rawStatus === "cancelled") {
|
|
15461
|
+
return rawStatus;
|
|
15332
15462
|
}
|
|
15333
|
-
|
|
15334
|
-
return "
|
|
15463
|
+
if (rawStatus === "canceled") {
|
|
15464
|
+
return "cancelled";
|
|
15335
15465
|
}
|
|
15336
|
-
|
|
15337
|
-
|
|
15338
|
-
|
|
15339
|
-
|
|
15340
|
-
|
|
15466
|
+
if (type === "turn_aborted") {
|
|
15467
|
+
const reason = message.reason;
|
|
15468
|
+
const error = message.error;
|
|
15469
|
+
if (typeof reason === "string" && /(fail|error)/i.test(reason) || typeof error === "string" && error.length > 0 || error !== void 0 && error !== null && typeof error === "object") {
|
|
15470
|
+
return "failed";
|
|
15471
|
+
}
|
|
15472
|
+
return "cancelled";
|
|
15341
15473
|
}
|
|
15342
|
-
|
|
15343
|
-
|
|
15344
|
-
*/
|
|
15345
|
-
complete(fullText) {
|
|
15346
|
-
this.completeReasoning(fullText);
|
|
15474
|
+
if (message.error !== void 0 && message.error !== null) {
|
|
15475
|
+
return "failed";
|
|
15347
15476
|
}
|
|
15477
|
+
return "completed";
|
|
15348
15478
|
}
|
|
15349
|
-
|
|
15350
|
-
|
|
15351
|
-
|
|
15352
|
-
|
|
15353
|
-
|
|
15354
|
-
|
|
15479
|
+
function mapCodexMcpMessageToSessionEnvelopes(message, state) {
|
|
15480
|
+
const type = message.type;
|
|
15481
|
+
const startedSubagents = getStartedSubagents(state);
|
|
15482
|
+
const activeSubagents = getActiveSubagents(state);
|
|
15483
|
+
const providerSubagentToSessionSubagent = getProviderSubagentToSessionSubagent(state);
|
|
15484
|
+
if (type === "collab_agent_item") {
|
|
15485
|
+
return {
|
|
15486
|
+
currentTurnId: state.currentTurnId,
|
|
15487
|
+
startedSubagents,
|
|
15488
|
+
activeSubagents,
|
|
15489
|
+
providerSubagentToSessionSubagent,
|
|
15490
|
+
envelopes: mapCodexCollaborationItem(message.item, buildEnvelopeOptions(state.currentTurnId), "live")
|
|
15491
|
+
};
|
|
15355
15492
|
}
|
|
15356
|
-
|
|
15357
|
-
|
|
15358
|
-
|
|
15359
|
-
|
|
15360
|
-
|
|
15361
|
-
|
|
15362
|
-
|
|
15363
|
-
|
|
15364
|
-
|
|
15365
|
-
|
|
15366
|
-
|
|
15367
|
-
|
|
15368
|
-
|
|
15369
|
-
|
|
15370
|
-
|
|
15493
|
+
if (type === "task_started") {
|
|
15494
|
+
const turnId = createId();
|
|
15495
|
+
const turnStart = createEnvelope("agent", { t: "turn-start" }, { turn: turnId });
|
|
15496
|
+
startedSubagents.clear();
|
|
15497
|
+
activeSubagents.clear();
|
|
15498
|
+
providerSubagentToSessionSubagent.clear();
|
|
15499
|
+
return {
|
|
15500
|
+
currentTurnId: turnId,
|
|
15501
|
+
startedSubagents,
|
|
15502
|
+
activeSubagents,
|
|
15503
|
+
providerSubagentToSessionSubagent,
|
|
15504
|
+
envelopes: [turnStart]
|
|
15505
|
+
};
|
|
15506
|
+
}
|
|
15507
|
+
if (type === "task_complete" || type === "turn_aborted") {
|
|
15508
|
+
if (!state.currentTurnId) {
|
|
15509
|
+
return {
|
|
15510
|
+
currentTurnId: null,
|
|
15511
|
+
startedSubagents,
|
|
15512
|
+
activeSubagents,
|
|
15513
|
+
providerSubagentToSessionSubagent,
|
|
15514
|
+
envelopes: []
|
|
15371
15515
|
};
|
|
15372
|
-
|
|
15373
|
-
|
|
15374
|
-
|
|
15375
|
-
|
|
15376
|
-
|
|
15377
|
-
|
|
15378
|
-
|
|
15379
|
-
|
|
15516
|
+
}
|
|
15517
|
+
const lifecycleOpts = { turn: state.currentTurnId };
|
|
15518
|
+
providerSubagentToSessionSubagent.clear();
|
|
15519
|
+
return {
|
|
15520
|
+
currentTurnId: null,
|
|
15521
|
+
startedSubagents,
|
|
15522
|
+
activeSubagents,
|
|
15523
|
+
providerSubagentToSessionSubagent,
|
|
15524
|
+
envelopes: [
|
|
15525
|
+
...emitSubagentStops(lifecycleOpts, startedSubagents, activeSubagents),
|
|
15526
|
+
createEnvelope("agent", {
|
|
15527
|
+
t: "turn-end",
|
|
15528
|
+
status: pickTurnEndStatus(message, type)
|
|
15529
|
+
}, lifecycleOpts)
|
|
15530
|
+
]
|
|
15531
|
+
};
|
|
15532
|
+
}
|
|
15533
|
+
if (type === "token_count") {
|
|
15534
|
+
return {
|
|
15535
|
+
currentTurnId: state.currentTurnId,
|
|
15536
|
+
startedSubagents,
|
|
15537
|
+
activeSubagents,
|
|
15538
|
+
providerSubagentToSessionSubagent,
|
|
15539
|
+
envelopes: []
|
|
15540
|
+
};
|
|
15541
|
+
}
|
|
15542
|
+
const subagent = resolveSessionSubagent(message, providerSubagentToSessionSubagent);
|
|
15543
|
+
const opts = buildEnvelopeOptions(state.currentTurnId, subagent);
|
|
15544
|
+
if (type === "agent_message") {
|
|
15545
|
+
if (typeof message.message !== "string") {
|
|
15546
|
+
return {
|
|
15547
|
+
currentTurnId: state.currentTurnId,
|
|
15548
|
+
startedSubagents,
|
|
15549
|
+
activeSubagents,
|
|
15550
|
+
providerSubagentToSessionSubagent,
|
|
15551
|
+
envelopes: []
|
|
15380
15552
|
};
|
|
15381
|
-
this.onMessage?.(toolResult);
|
|
15382
15553
|
}
|
|
15383
|
-
|
|
15384
|
-
|
|
15554
|
+
const envelopes = [];
|
|
15555
|
+
maybeEmitSubagentStart(subagent, opts, startedSubagents, activeSubagents, envelopes);
|
|
15556
|
+
envelopes.push(createEnvelope("agent", { t: "text", text: message.message }, opts));
|
|
15557
|
+
return {
|
|
15558
|
+
currentTurnId: state.currentTurnId,
|
|
15559
|
+
startedSubagents,
|
|
15560
|
+
activeSubagents,
|
|
15561
|
+
providerSubagentToSessionSubagent,
|
|
15562
|
+
envelopes
|
|
15563
|
+
};
|
|
15385
15564
|
}
|
|
15386
|
-
|
|
15387
|
-
|
|
15388
|
-
|
|
15389
|
-
|
|
15390
|
-
|
|
15391
|
-
|
|
15565
|
+
if (type === "agent_reasoning" || type === "agent_reasoning_delta") {
|
|
15566
|
+
const text = typeof message.text === "string" ? message.text : typeof message.delta === "string" ? message.delta : null;
|
|
15567
|
+
if (!text) {
|
|
15568
|
+
return {
|
|
15569
|
+
currentTurnId: state.currentTurnId,
|
|
15570
|
+
startedSubagents,
|
|
15571
|
+
activeSubagents,
|
|
15572
|
+
providerSubagentToSessionSubagent,
|
|
15573
|
+
envelopes: []
|
|
15574
|
+
};
|
|
15575
|
+
}
|
|
15576
|
+
const envelopes = [];
|
|
15577
|
+
maybeEmitSubagentStart(subagent, opts, startedSubagents, activeSubagents, envelopes);
|
|
15578
|
+
envelopes.push(createEnvelope("agent", { t: "text", text, thinking: true }, opts));
|
|
15579
|
+
return {
|
|
15580
|
+
currentTurnId: state.currentTurnId,
|
|
15581
|
+
startedSubagents,
|
|
15582
|
+
activeSubagents,
|
|
15583
|
+
providerSubagentToSessionSubagent,
|
|
15584
|
+
envelopes
|
|
15585
|
+
};
|
|
15392
15586
|
}
|
|
15393
|
-
|
|
15394
|
-
|
|
15395
|
-
|
|
15396
|
-
|
|
15397
|
-
|
|
15587
|
+
if (type === "exec_command_begin") {
|
|
15588
|
+
const call = pickCallId(message);
|
|
15589
|
+
const { call_id: _callIdSnake, callId: _callIdCamel, type: _type, ...args } = message;
|
|
15590
|
+
const command = summarizeCommand(args.command);
|
|
15591
|
+
const description = typeof args.description === "string" ? args.description : command ?? "Execute command";
|
|
15592
|
+
const envelopes = [];
|
|
15593
|
+
maybeEmitSubagentStart(subagent, opts, startedSubagents, activeSubagents, envelopes);
|
|
15594
|
+
envelopes.push(
|
|
15595
|
+
createEnvelope("agent", {
|
|
15596
|
+
t: "tool-call-start",
|
|
15597
|
+
call,
|
|
15598
|
+
name: "CodexBash",
|
|
15599
|
+
title: commandToTitle(command),
|
|
15600
|
+
description,
|
|
15601
|
+
args
|
|
15602
|
+
}, opts)
|
|
15603
|
+
);
|
|
15604
|
+
return {
|
|
15605
|
+
currentTurnId: state.currentTurnId,
|
|
15606
|
+
startedSubagents,
|
|
15607
|
+
activeSubagents,
|
|
15608
|
+
providerSubagentToSessionSubagent,
|
|
15609
|
+
envelopes
|
|
15610
|
+
};
|
|
15398
15611
|
}
|
|
15399
|
-
|
|
15400
|
-
|
|
15401
|
-
|
|
15402
|
-
|
|
15403
|
-
|
|
15612
|
+
if (type === "exec_command_end") {
|
|
15613
|
+
const call = pickCallId(message);
|
|
15614
|
+
const envelopes = [];
|
|
15615
|
+
maybeEmitSubagentStart(subagent, opts, startedSubagents, activeSubagents, envelopes);
|
|
15616
|
+
envelopes.push(createEnvelope("agent", { t: "tool-call-end", call }, opts));
|
|
15617
|
+
return {
|
|
15618
|
+
currentTurnId: state.currentTurnId,
|
|
15619
|
+
startedSubagents,
|
|
15620
|
+
activeSubagents,
|
|
15621
|
+
providerSubagentToSessionSubagent,
|
|
15622
|
+
envelopes
|
|
15623
|
+
};
|
|
15624
|
+
}
|
|
15625
|
+
if (type === "patch_apply_begin") {
|
|
15626
|
+
const call = pickCallId(message);
|
|
15627
|
+
const autoApproved = message.auto_approved;
|
|
15628
|
+
const changes = message.changes;
|
|
15629
|
+
const envelopes = [];
|
|
15630
|
+
maybeEmitSubagentStart(subagent, opts, startedSubagents, activeSubagents, envelopes);
|
|
15631
|
+
envelopes.push(
|
|
15632
|
+
createEnvelope("agent", {
|
|
15633
|
+
t: "tool-call-start",
|
|
15634
|
+
call,
|
|
15635
|
+
name: "CodexPatch",
|
|
15636
|
+
title: "Apply patch",
|
|
15637
|
+
description: patchDescription(changes),
|
|
15638
|
+
args: {
|
|
15639
|
+
auto_approved: autoApproved,
|
|
15640
|
+
changes
|
|
15641
|
+
}
|
|
15642
|
+
}, opts)
|
|
15643
|
+
);
|
|
15644
|
+
return {
|
|
15645
|
+
currentTurnId: state.currentTurnId,
|
|
15646
|
+
startedSubagents,
|
|
15647
|
+
activeSubagents,
|
|
15648
|
+
providerSubagentToSessionSubagent,
|
|
15649
|
+
envelopes
|
|
15650
|
+
};
|
|
15651
|
+
}
|
|
15652
|
+
if (type === "patch_apply_end") {
|
|
15653
|
+
const call = pickCallId(message);
|
|
15654
|
+
const envelopes = [];
|
|
15655
|
+
maybeEmitSubagentStart(subagent, opts, startedSubagents, activeSubagents, envelopes);
|
|
15656
|
+
envelopes.push(createEnvelope("agent", { t: "tool-call-end", call }, opts));
|
|
15657
|
+
return {
|
|
15658
|
+
currentTurnId: state.currentTurnId,
|
|
15659
|
+
startedSubagents,
|
|
15660
|
+
activeSubagents,
|
|
15661
|
+
providerSubagentToSessionSubagent,
|
|
15662
|
+
envelopes
|
|
15663
|
+
};
|
|
15664
|
+
}
|
|
15665
|
+
return {
|
|
15666
|
+
currentTurnId: state.currentTurnId,
|
|
15667
|
+
startedSubagents,
|
|
15668
|
+
activeSubagents,
|
|
15669
|
+
providerSubagentToSessionSubagent,
|
|
15670
|
+
envelopes: []
|
|
15671
|
+
};
|
|
15672
|
+
}
|
|
15673
|
+
function mapCodexProcessorMessageToSessionEnvelopes(message, state) {
|
|
15674
|
+
const toolLikeMessage = message;
|
|
15675
|
+
const opts = buildEnvelopeOptions(state.currentTurnId);
|
|
15676
|
+
if (message.type === "reasoning") {
|
|
15677
|
+
return [createEnvelope("agent", {
|
|
15678
|
+
t: "text",
|
|
15679
|
+
text: message.message,
|
|
15680
|
+
thinking: true
|
|
15681
|
+
}, opts)];
|
|
15682
|
+
}
|
|
15683
|
+
if (message.type === "tool-call") {
|
|
15684
|
+
const title = typeof toolLikeMessage.input?.title === "string" ? toolLikeMessage.input.title : `${toolLikeMessage.name || "Tool"} call`;
|
|
15685
|
+
return [createEnvelope("agent", {
|
|
15686
|
+
t: "tool-call-start",
|
|
15687
|
+
call: toolLikeMessage.callId,
|
|
15688
|
+
name: toolLikeMessage.name || "unknown",
|
|
15689
|
+
title,
|
|
15690
|
+
description: title,
|
|
15691
|
+
args: toolLikeMessage.input && typeof toolLikeMessage.input === "object" ? toolLikeMessage.input : {}
|
|
15692
|
+
}, opts)];
|
|
15693
|
+
}
|
|
15694
|
+
if (message.type === "tool-call-result") {
|
|
15695
|
+
const envelopes = [];
|
|
15696
|
+
const content = toolLikeMessage.output?.content;
|
|
15697
|
+
if (typeof content === "string" && content.trim().length > 0) {
|
|
15698
|
+
envelopes.push(createEnvelope("agent", {
|
|
15699
|
+
t: "text",
|
|
15700
|
+
text: content,
|
|
15701
|
+
thinking: true
|
|
15702
|
+
}, opts));
|
|
15703
|
+
}
|
|
15704
|
+
envelopes.push(createEnvelope("agent", {
|
|
15705
|
+
t: "tool-call-end",
|
|
15706
|
+
call: toolLikeMessage.callId
|
|
15707
|
+
}, opts));
|
|
15708
|
+
return envelopes;
|
|
15404
15709
|
}
|
|
15710
|
+
return [];
|
|
15405
15711
|
}
|
|
15406
15712
|
|
|
15407
|
-
|
|
15408
|
-
|
|
15409
|
-
const
|
|
15410
|
-
const
|
|
15411
|
-
const
|
|
15412
|
-
|
|
15413
|
-
const
|
|
15414
|
-
|
|
15415
|
-
|
|
15416
|
-
|
|
15417
|
-
|
|
15418
|
-
|
|
15419
|
-
|
|
15420
|
-
|
|
15421
|
-
|
|
15422
|
-
|
|
15423
|
-
|
|
15713
|
+
async function readChildThread(client, childId) {
|
|
15714
|
+
if (!client.threadId || typeof childId !== "string" || !childId) throw new Error("Invalid child thread");
|
|
15715
|
+
const parentId = client.threadId;
|
|
15716
|
+
const { thread: parent } = await client.readThread({ threadId: parentId, includeTurns: true });
|
|
15717
|
+
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));
|
|
15718
|
+
if (!belongs) throw new Error("Thread is not a child of this session");
|
|
15719
|
+
const { thread } = await client.readThread({ threadId: childId, includeTurns: true });
|
|
15720
|
+
if (thread.id !== childId) throw new Error("Child thread mismatch");
|
|
15721
|
+
return { envelopes: mapCodexThreadToSessionEnvelopes(thread) };
|
|
15722
|
+
}
|
|
15723
|
+
|
|
15724
|
+
function registerAgentAttachmentDownloads(session) {
|
|
15725
|
+
session.onFileEvent((fileEvent) => {
|
|
15726
|
+
const attachment = fileEvent.content.data.ev;
|
|
15727
|
+
const download = (async () => {
|
|
15728
|
+
try {
|
|
15729
|
+
const data = await session.downloadAndDecryptAttachment(attachment.ref);
|
|
15730
|
+
if (!data) throw new Error("Attachment decryption failed");
|
|
15731
|
+
return { data, mimeType: attachment.mimeType ?? "image/jpeg", name: attachment.name };
|
|
15732
|
+
} catch {
|
|
15733
|
+
session.sendSessionEvent({ type: "message", message: `Could not download attachment: ${attachment.name}. Please attach it again.` });
|
|
15734
|
+
return null;
|
|
15424
15735
|
}
|
|
15425
|
-
};
|
|
15426
|
-
|
|
15427
|
-
|
|
15428
|
-
|
|
15429
|
-
|
|
15430
|
-
|
|
15431
|
-
|
|
15432
|
-
|
|
15433
|
-
|
|
15434
|
-
|
|
15435
|
-
|
|
15436
|
-
|
|
15437
|
-
|
|
15438
|
-
|
|
15439
|
-
|
|
15440
|
-
|
|
15441
|
-
|
|
15442
|
-
|
|
15443
|
-
|
|
15444
|
-
|
|
15445
|
-
|
|
15446
|
-
|
|
15447
|
-
|
|
15448
|
-
|
|
15449
|
-
|
|
15450
|
-
|
|
15451
|
-
|
|
15452
|
-
|
|
15736
|
+
})();
|
|
15737
|
+
session.trackAttachmentDownload(download);
|
|
15738
|
+
});
|
|
15739
|
+
}
|
|
15740
|
+
|
|
15741
|
+
class BasePermissionHandler {
|
|
15742
|
+
pendingRequests = /* @__PURE__ */ new Map();
|
|
15743
|
+
session;
|
|
15744
|
+
isResetting = false;
|
|
15745
|
+
constructor(session) {
|
|
15746
|
+
this.session = session;
|
|
15747
|
+
this.setupRpcHandler();
|
|
15748
|
+
}
|
|
15749
|
+
/**
|
|
15750
|
+
* Update the session reference (used after offline reconnection swaps sessions).
|
|
15751
|
+
* This is critical for avoiding stale session references after onSessionSwap.
|
|
15752
|
+
*/
|
|
15753
|
+
updateSession(newSession) {
|
|
15754
|
+
logger.debug(`${this.getLogPrefix()} Session reference updated`);
|
|
15755
|
+
this.session = newSession;
|
|
15756
|
+
this.setupRpcHandler();
|
|
15757
|
+
}
|
|
15758
|
+
/**
|
|
15759
|
+
* Setup RPC handler for permission responses.
|
|
15760
|
+
*/
|
|
15761
|
+
setupRpcHandler() {
|
|
15762
|
+
this.session.rpcHandlerManager.registerHandler(
|
|
15763
|
+
"permission",
|
|
15764
|
+
async (response) => {
|
|
15765
|
+
const pending = this.pendingRequests.get(response.id);
|
|
15766
|
+
if (!pending) {
|
|
15767
|
+
logger.debug(`${this.getLogPrefix()} Permission request not found or already resolved`);
|
|
15768
|
+
return;
|
|
15769
|
+
}
|
|
15770
|
+
this.pendingRequests.delete(response.id);
|
|
15771
|
+
const result = response.approved ? { decision: response.decision === "approved_for_session" ? "approved_for_session" : "approved" } : { decision: response.decision === "denied" ? "denied" : "abort" };
|
|
15772
|
+
pending.resolve(result);
|
|
15773
|
+
this.session.updateAgentState((currentState) => {
|
|
15774
|
+
const request = currentState.requests?.[response.id];
|
|
15775
|
+
if (!request) return currentState;
|
|
15776
|
+
const { [response.id]: _, ...remainingRequests } = currentState.requests || {};
|
|
15777
|
+
let res = {
|
|
15778
|
+
...currentState,
|
|
15779
|
+
requests: remainingRequests,
|
|
15780
|
+
completedRequests: {
|
|
15781
|
+
...currentState.completedRequests,
|
|
15782
|
+
[response.id]: {
|
|
15783
|
+
...request,
|
|
15784
|
+
completedAt: Date.now(),
|
|
15785
|
+
status: response.approved ? "approved" : "denied",
|
|
15786
|
+
decision: result.decision
|
|
15787
|
+
}
|
|
15788
|
+
}
|
|
15789
|
+
};
|
|
15790
|
+
return res;
|
|
15791
|
+
});
|
|
15792
|
+
logger.debug(`${this.getLogPrefix()} Permission ${response.approved ? "approved" : "denied"} for ${pending.toolName}`);
|
|
15453
15793
|
}
|
|
15454
|
-
|
|
15455
|
-
|
|
15456
|
-
|
|
15457
|
-
|
|
15458
|
-
|
|
15459
|
-
|
|
15460
|
-
|
|
15461
|
-
|
|
15462
|
-
|
|
15463
|
-
|
|
15464
|
-
|
|
15465
|
-
|
|
15466
|
-
|
|
15467
|
-
|
|
15468
|
-
|
|
15469
|
-
return "yellow";
|
|
15470
|
-
case "result":
|
|
15471
|
-
return "green";
|
|
15472
|
-
case "status":
|
|
15473
|
-
return "gray";
|
|
15474
|
-
default:
|
|
15475
|
-
return "white";
|
|
15476
|
-
}
|
|
15477
|
-
};
|
|
15478
|
-
const formatMessage = (msg) => {
|
|
15479
|
-
const lines = msg.content.split("\n");
|
|
15480
|
-
const maxLineLength = terminalWidth - 10;
|
|
15481
|
-
return lines.map((line) => {
|
|
15482
|
-
if (line.length <= maxLineLength) return line;
|
|
15483
|
-
const chunks = [];
|
|
15484
|
-
for (let i = 0; i < line.length; i += maxLineLength) {
|
|
15485
|
-
chunks.push(line.slice(i, i + maxLineLength));
|
|
15794
|
+
);
|
|
15795
|
+
}
|
|
15796
|
+
/**
|
|
15797
|
+
* Add a pending request to the agent state.
|
|
15798
|
+
*/
|
|
15799
|
+
addPendingRequestToState(toolCallId, toolName, input) {
|
|
15800
|
+
this.session.updateAgentState((currentState) => ({
|
|
15801
|
+
...currentState,
|
|
15802
|
+
requests: {
|
|
15803
|
+
...currentState.requests,
|
|
15804
|
+
[toolCallId]: {
|
|
15805
|
+
tool: toolName,
|
|
15806
|
+
arguments: input,
|
|
15807
|
+
createdAt: Date.now()
|
|
15808
|
+
}
|
|
15486
15809
|
}
|
|
15487
|
-
|
|
15488
|
-
|
|
15489
|
-
|
|
15490
|
-
|
|
15491
|
-
|
|
15492
|
-
|
|
15493
|
-
|
|
15494
|
-
|
|
15495
|
-
|
|
15496
|
-
|
|
15497
|
-
|
|
15498
|
-
|
|
15499
|
-
|
|
15500
|
-
|
|
15501
|
-
|
|
15502
|
-
|
|
15503
|
-
|
|
15504
|
-
|
|
15505
|
-
))
|
|
15506
|
-
), /* @__PURE__ */ React.createElement(
|
|
15507
|
-
Box,
|
|
15508
|
-
{
|
|
15509
|
-
width: terminalWidth,
|
|
15510
|
-
borderStyle: "round",
|
|
15511
|
-
borderColor: actionInProgress ? "gray" : confirmationMode ? "red" : "green",
|
|
15512
|
-
paddingX: 2,
|
|
15513
|
-
justifyContent: "center",
|
|
15514
|
-
alignItems: "center",
|
|
15515
|
-
flexDirection: "column"
|
|
15516
|
-
},
|
|
15517
|
-
/* @__PURE__ */ React.createElement(Box, { flexDirection: "column", alignItems: "center" }, actionInProgress ? /* @__PURE__ */ React.createElement(Text, { color: "gray", bold: true }, "Exiting agent...") : confirmationMode ? /* @__PURE__ */ React.createElement(Text, { color: "red", bold: true }, "\u26A0\uFE0F Press Ctrl-C again to exit the agent") : /* @__PURE__ */ React.createElement(React.Fragment, null, /* @__PURE__ */ React.createElement(Text, { color: "green", bold: true }, "\u{1F916} Codex Agent Running \u2022 Ctrl-C to exit")), process.env.DEBUG && logPath && /* @__PURE__ */ React.createElement(Text, { color: "gray", dimColor: true }, "Debug logs: ", logPath))
|
|
15518
|
-
));
|
|
15519
|
-
};
|
|
15520
|
-
|
|
15521
|
-
function createOfflineSessionStub(sessionTag) {
|
|
15522
|
-
return {
|
|
15523
|
-
sessionId: `offline-${sessionTag}`,
|
|
15524
|
-
sendCodexMessage: () => {
|
|
15525
|
-
},
|
|
15526
|
-
sendAgentMessage: () => {
|
|
15527
|
-
},
|
|
15528
|
-
sendAgentUsageSnapshot: () => false,
|
|
15529
|
-
sendClaudeSessionMessage: () => {
|
|
15530
|
-
},
|
|
15531
|
-
keepAlive: () => {
|
|
15532
|
-
},
|
|
15533
|
-
sendSessionEvent: () => {
|
|
15534
|
-
},
|
|
15535
|
-
sendSessionDeath: () => {
|
|
15536
|
-
},
|
|
15537
|
-
updateLifecycleState: () => {
|
|
15538
|
-
},
|
|
15539
|
-
requestControlTransfer: async () => {
|
|
15540
|
-
},
|
|
15541
|
-
flush: async () => {
|
|
15542
|
-
},
|
|
15543
|
-
close: async () => {
|
|
15544
|
-
},
|
|
15545
|
-
updateMetadata: () => {
|
|
15546
|
-
},
|
|
15547
|
-
updateAgentState: () => {
|
|
15548
|
-
},
|
|
15549
|
-
onUserMessage: () => {
|
|
15550
|
-
},
|
|
15551
|
-
onFileEvent: () => {
|
|
15552
|
-
},
|
|
15553
|
-
trackAttachmentDownload: () => {
|
|
15554
|
-
},
|
|
15555
|
-
drainAttachmentsForUserMessage: async () => [],
|
|
15556
|
-
rpcHandlerManager: {
|
|
15557
|
-
registerHandler: () => {
|
|
15810
|
+
}));
|
|
15811
|
+
}
|
|
15812
|
+
/**
|
|
15813
|
+
* Abort all pending permission requests.
|
|
15814
|
+
* Unlike reset(), this resolves (not rejects) pending promises with { decision: 'abort' },
|
|
15815
|
+
* causing the approval response to send 'cancel' to the provider. This is used when the
|
|
15816
|
+
* user presses the abort/stop button — it unblocks any pending tool approval so the provider
|
|
15817
|
+
* can process the turn cancellation.
|
|
15818
|
+
*/
|
|
15819
|
+
abortAll() {
|
|
15820
|
+
const pendingSnapshot = Array.from(this.pendingRequests.entries());
|
|
15821
|
+
if (pendingSnapshot.length === 0) return;
|
|
15822
|
+
this.pendingRequests.clear();
|
|
15823
|
+
for (const [id, pending] of pendingSnapshot) {
|
|
15824
|
+
try {
|
|
15825
|
+
pending.resolve({ decision: "abort" });
|
|
15826
|
+
} catch (err) {
|
|
15827
|
+
logger.debug(`${this.getLogPrefix()} Error resolving aborted request ${id}:`, err);
|
|
15558
15828
|
}
|
|
15559
15829
|
}
|
|
15560
|
-
|
|
15561
|
-
}
|
|
15562
|
-
|
|
15563
|
-
|
|
15564
|
-
|
|
15565
|
-
|
|
15566
|
-
|
|
15567
|
-
|
|
15568
|
-
|
|
15569
|
-
|
|
15570
|
-
serverUrl: configuration.serverUrl,
|
|
15571
|
-
onReconnected: async () => {
|
|
15572
|
-
const resp = await api.getOrCreateSession({ tag: sessionTag, metadata, state });
|
|
15573
|
-
if (!resp) throw new Error("Server unavailable");
|
|
15574
|
-
const realSession = api.sessionSyncClient(resp);
|
|
15575
|
-
onSessionSwap(realSession);
|
|
15576
|
-
return realSession;
|
|
15577
|
-
},
|
|
15578
|
-
onNotify: (msg) => {
|
|
15579
|
-
console.log(msg);
|
|
15830
|
+
this.session.updateAgentState((currentState) => {
|
|
15831
|
+
const pendingRequests = currentState.requests || {};
|
|
15832
|
+
const completedRequests = { ...currentState.completedRequests };
|
|
15833
|
+
for (const [id, request] of Object.entries(pendingRequests)) {
|
|
15834
|
+
completedRequests[id] = {
|
|
15835
|
+
...request,
|
|
15836
|
+
completedAt: Date.now(),
|
|
15837
|
+
status: "canceled",
|
|
15838
|
+
reason: "Aborted by user"
|
|
15839
|
+
};
|
|
15580
15840
|
}
|
|
15841
|
+
return {
|
|
15842
|
+
...currentState,
|
|
15843
|
+
requests: {},
|
|
15844
|
+
completedRequests
|
|
15845
|
+
};
|
|
15581
15846
|
});
|
|
15582
|
-
|
|
15583
|
-
} else {
|
|
15584
|
-
session = api.sessionSyncClient(response, opts.sessionClientOptions);
|
|
15585
|
-
return { session, reconnectionHandle: null, isOffline: false };
|
|
15586
|
-
}
|
|
15587
|
-
}
|
|
15588
|
-
|
|
15589
|
-
function resolveCodexExecutionPolicy(permissionMode, sandboxManagedByHappy) {
|
|
15590
|
-
if (sandboxManagedByHappy) {
|
|
15591
|
-
return {
|
|
15592
|
-
approvalPolicy: "never",
|
|
15593
|
-
sandbox: "danger-full-access"
|
|
15594
|
-
};
|
|
15847
|
+
logger.debug(`${this.getLogPrefix()} Aborted ${pendingSnapshot.length} pending permission(s)`);
|
|
15595
15848
|
}
|
|
15596
|
-
|
|
15597
|
-
|
|
15598
|
-
|
|
15599
|
-
|
|
15600
|
-
|
|
15601
|
-
|
|
15602
|
-
|
|
15603
|
-
|
|
15604
|
-
// Never ask, read-only enforced by sandbox
|
|
15605
|
-
case "safe-yolo":
|
|
15606
|
-
return "on-request";
|
|
15607
|
-
// Workspace auto-run; request approval for escalation (0.153 removed on-failure)
|
|
15608
|
-
case "yolo":
|
|
15609
|
-
return "never";
|
|
15610
|
-
// Full YOLO: never interrupt for approvals
|
|
15611
|
-
// Defensive fallback for Claude-specific modes (backward compatibility)
|
|
15612
|
-
case "bypassPermissions":
|
|
15613
|
-
return "never";
|
|
15614
|
-
// Full access: map to yolo behavior
|
|
15615
|
-
case "acceptEdits":
|
|
15616
|
-
return "on-request";
|
|
15617
|
-
// Let model decide (closest to auto-approve edits)
|
|
15618
|
-
case "plan":
|
|
15619
|
-
return "untrusted";
|
|
15620
|
-
// Conservative: ask for non-trusted
|
|
15621
|
-
default:
|
|
15622
|
-
return "untrusted";
|
|
15849
|
+
/**
|
|
15850
|
+
* Reset state for new sessions.
|
|
15851
|
+
* This method is idempotent - safe to call multiple times.
|
|
15852
|
+
*/
|
|
15853
|
+
reset(reason = "Session reset") {
|
|
15854
|
+
if (this.isResetting) {
|
|
15855
|
+
logger.debug(`${this.getLogPrefix()} Reset already in progress, skipping`);
|
|
15856
|
+
return;
|
|
15623
15857
|
}
|
|
15624
|
-
|
|
15625
|
-
|
|
15626
|
-
|
|
15627
|
-
|
|
15628
|
-
|
|
15629
|
-
|
|
15630
|
-
|
|
15631
|
-
|
|
15632
|
-
|
|
15633
|
-
|
|
15634
|
-
|
|
15635
|
-
|
|
15636
|
-
|
|
15637
|
-
|
|
15638
|
-
|
|
15639
|
-
|
|
15640
|
-
|
|
15641
|
-
|
|
15642
|
-
|
|
15643
|
-
|
|
15644
|
-
|
|
15645
|
-
|
|
15646
|
-
|
|
15647
|
-
|
|
15648
|
-
|
|
15649
|
-
|
|
15650
|
-
|
|
15651
|
-
|
|
15858
|
+
this.isResetting = true;
|
|
15859
|
+
try {
|
|
15860
|
+
const pendingSnapshot = Array.from(this.pendingRequests.entries());
|
|
15861
|
+
this.pendingRequests.clear();
|
|
15862
|
+
for (const [id, pending] of pendingSnapshot) {
|
|
15863
|
+
try {
|
|
15864
|
+
pending.reject(new Error("Session reset"));
|
|
15865
|
+
} catch (err) {
|
|
15866
|
+
logger.debug(`${this.getLogPrefix()} Error rejecting pending request ${id}:`, err);
|
|
15867
|
+
}
|
|
15868
|
+
}
|
|
15869
|
+
this.session.updateAgentState((currentState) => {
|
|
15870
|
+
const pendingRequests = currentState.requests || {};
|
|
15871
|
+
const completedRequests = { ...currentState.completedRequests };
|
|
15872
|
+
for (const [id, request] of Object.entries(pendingRequests)) {
|
|
15873
|
+
completedRequests[id] = {
|
|
15874
|
+
...request,
|
|
15875
|
+
completedAt: Date.now(),
|
|
15876
|
+
status: "canceled",
|
|
15877
|
+
reason
|
|
15878
|
+
};
|
|
15879
|
+
}
|
|
15880
|
+
return {
|
|
15881
|
+
...currentState,
|
|
15882
|
+
requests: {},
|
|
15883
|
+
completedRequests
|
|
15884
|
+
};
|
|
15885
|
+
});
|
|
15886
|
+
logger.debug(`${this.getLogPrefix()} Permission handler reset`);
|
|
15887
|
+
} finally {
|
|
15888
|
+
this.isResetting = false;
|
|
15652
15889
|
}
|
|
15653
|
-
}
|
|
15654
|
-
return { approvalPolicy, sandbox };
|
|
15890
|
+
}
|
|
15655
15891
|
}
|
|
15656
15892
|
|
|
15657
|
-
|
|
15658
|
-
|
|
15659
|
-
|
|
15660
|
-
|
|
15661
|
-
|
|
15662
|
-
|
|
15663
|
-
|
|
15664
|
-
|
|
15665
|
-
|
|
15666
|
-
|
|
15667
|
-
|
|
15668
|
-
|
|
15893
|
+
class CodexPermissionHandler extends BasePermissionHandler {
|
|
15894
|
+
// Exact tool names that should always be auto-approved. Include the bare
|
|
15895
|
+
// form (used by Codex elicitation messages like `tool "change_title"`)
|
|
15896
|
+
// and the MCP-qualified form for defense in depth.
|
|
15897
|
+
static ALWAYS_AUTO_APPROVE_NAMES = /* @__PURE__ */ new Set([
|
|
15898
|
+
"change_title",
|
|
15899
|
+
"mcp__happy__change_title"
|
|
15900
|
+
]);
|
|
15901
|
+
// Tool-call IDs that should auto-approve when they exactly match one of
|
|
15902
|
+
// these values or start with `<name>-` (e.g. `change_title-1765385846663`).
|
|
15903
|
+
// Substring matching was a bypass vector — any tool whose ID happened to
|
|
15904
|
+
// contain `change_title` as a substring would be silently approved.
|
|
15905
|
+
static ALWAYS_AUTO_APPROVE_ID_PREFIXES = [
|
|
15906
|
+
"change_title"
|
|
15907
|
+
];
|
|
15908
|
+
constructor(session) {
|
|
15909
|
+
super(session);
|
|
15669
15910
|
}
|
|
15670
|
-
|
|
15671
|
-
|
|
15672
|
-
activeSubagents.add(subagent);
|
|
15673
|
-
}
|
|
15674
|
-
function emitSubagentStops(opts, startedSubagents, activeSubagents) {
|
|
15675
|
-
const envelopes = [];
|
|
15676
|
-
for (const subagent of activeSubagents) {
|
|
15677
|
-
envelopes.push(createEnvelope("agent", { t: "stop" }, { ...opts, subagent }));
|
|
15911
|
+
getLogPrefix() {
|
|
15912
|
+
return "[Codex]";
|
|
15678
15913
|
}
|
|
15679
|
-
|
|
15680
|
-
|
|
15681
|
-
|
|
15682
|
-
}
|
|
15683
|
-
function buildEnvelopeOptions(currentTurnId, subagent) {
|
|
15684
|
-
return {
|
|
15685
|
-
...currentTurnId ? { turn: currentTurnId } : {},
|
|
15686
|
-
...subagent ? { subagent } : {}
|
|
15687
|
-
};
|
|
15688
|
-
}
|
|
15689
|
-
function pickProviderSubagent(message) {
|
|
15690
|
-
const candidates = [message.subagent, message.parent_call_id, message.parentCallId];
|
|
15691
|
-
for (const candidate of candidates) {
|
|
15692
|
-
if (typeof candidate === "string" && candidate.length > 0) {
|
|
15693
|
-
return candidate;
|
|
15914
|
+
shouldAutoApprove(toolName, toolCallId) {
|
|
15915
|
+
if (CodexPermissionHandler.ALWAYS_AUTO_APPROVE_NAMES.has(toolName)) {
|
|
15916
|
+
return true;
|
|
15694
15917
|
}
|
|
15918
|
+
for (const prefix of CodexPermissionHandler.ALWAYS_AUTO_APPROVE_ID_PREFIXES) {
|
|
15919
|
+
if (toolCallId === prefix || toolCallId.startsWith(`${prefix}-`)) {
|
|
15920
|
+
return true;
|
|
15921
|
+
}
|
|
15922
|
+
}
|
|
15923
|
+
return false;
|
|
15695
15924
|
}
|
|
15696
|
-
|
|
15697
|
-
|
|
15698
|
-
|
|
15699
|
-
|
|
15700
|
-
|
|
15701
|
-
|
|
15702
|
-
|
|
15703
|
-
|
|
15704
|
-
|
|
15705
|
-
|
|
15925
|
+
/**
|
|
15926
|
+
* Handle a tool permission request
|
|
15927
|
+
* @param toolCallId - The unique ID of the tool call
|
|
15928
|
+
* @param toolName - The name of the tool being called
|
|
15929
|
+
* @param input - The input parameters for the tool
|
|
15930
|
+
* @returns Promise resolving to permission result
|
|
15931
|
+
*/
|
|
15932
|
+
async handleToolCall(toolCallId, toolName, input) {
|
|
15933
|
+
if (this.shouldAutoApprove(toolName, toolCallId)) {
|
|
15934
|
+
logger.debug(`${this.getLogPrefix()} Auto-approving tool ${toolName} (${toolCallId})`);
|
|
15935
|
+
this.session.updateAgentState((currentState) => ({
|
|
15936
|
+
...currentState,
|
|
15937
|
+
completedRequests: {
|
|
15938
|
+
...currentState.completedRequests,
|
|
15939
|
+
[toolCallId]: {
|
|
15940
|
+
tool: toolName,
|
|
15941
|
+
arguments: input,
|
|
15942
|
+
createdAt: Date.now(),
|
|
15943
|
+
completedAt: Date.now(),
|
|
15944
|
+
status: "approved",
|
|
15945
|
+
decision: "approved"
|
|
15946
|
+
}
|
|
15947
|
+
}
|
|
15948
|
+
}));
|
|
15949
|
+
return { decision: "approved" };
|
|
15950
|
+
}
|
|
15951
|
+
return new Promise((resolve, reject) => {
|
|
15952
|
+
this.pendingRequests.set(toolCallId, {
|
|
15953
|
+
resolve,
|
|
15954
|
+
reject,
|
|
15955
|
+
toolName,
|
|
15956
|
+
input
|
|
15957
|
+
});
|
|
15958
|
+
this.addPendingRequestToState(toolCallId, toolName, input);
|
|
15959
|
+
logger.debug(`${this.getLogPrefix()} Permission request sent for tool: ${toolName} (${toolCallId})`);
|
|
15960
|
+
});
|
|
15706
15961
|
}
|
|
15707
|
-
const created = createId();
|
|
15708
|
-
providerSubagentToSessionSubagent.set(providerSubagent, created);
|
|
15709
|
-
return created;
|
|
15710
15962
|
}
|
|
15711
|
-
|
|
15712
|
-
|
|
15713
|
-
|
|
15714
|
-
|
|
15963
|
+
|
|
15964
|
+
class BaseReasoningProcessor {
|
|
15965
|
+
accumulator = "";
|
|
15966
|
+
inTitleCapture = false;
|
|
15967
|
+
titleBuffer = "";
|
|
15968
|
+
contentBuffer = "";
|
|
15969
|
+
hasTitle = false;
|
|
15970
|
+
currentCallId = null;
|
|
15971
|
+
toolCallStarted = false;
|
|
15972
|
+
currentTitle = null;
|
|
15973
|
+
onMessage = null;
|
|
15974
|
+
constructor(onMessage) {
|
|
15975
|
+
this.onMessage = onMessage || null;
|
|
15976
|
+
this.reset();
|
|
15715
15977
|
}
|
|
15716
|
-
|
|
15717
|
-
|
|
15718
|
-
|
|
15719
|
-
|
|
15720
|
-
|
|
15978
|
+
/**
|
|
15979
|
+
* Set the message callback for sending messages directly.
|
|
15980
|
+
*/
|
|
15981
|
+
setMessageCallback(callback) {
|
|
15982
|
+
this.onMessage = callback;
|
|
15721
15983
|
}
|
|
15722
|
-
|
|
15723
|
-
|
|
15724
|
-
|
|
15984
|
+
/**
|
|
15985
|
+
* Process a reasoning section break - indicates a new reasoning section is starting.
|
|
15986
|
+
*/
|
|
15987
|
+
handleSectionBreak() {
|
|
15988
|
+
this.finishCurrentToolCall("canceled");
|
|
15989
|
+
this.resetState();
|
|
15990
|
+
logger.debug(`${this.getLogPrefix()} Section break - reset state`);
|
|
15725
15991
|
}
|
|
15726
|
-
|
|
15727
|
-
|
|
15728
|
-
|
|
15729
|
-
|
|
15730
|
-
|
|
15992
|
+
/**
|
|
15993
|
+
* Process a reasoning delta/chunk and accumulate content.
|
|
15994
|
+
*/
|
|
15995
|
+
processInput(input) {
|
|
15996
|
+
this.accumulator += input;
|
|
15997
|
+
if (!this.inTitleCapture && !this.hasTitle && !this.contentBuffer) {
|
|
15998
|
+
if (this.accumulator.startsWith("**")) {
|
|
15999
|
+
this.inTitleCapture = true;
|
|
16000
|
+
this.titleBuffer = this.accumulator.substring(2);
|
|
16001
|
+
logger.debug(`${this.getLogPrefix()} Started title capture`);
|
|
16002
|
+
} else if (this.accumulator.length > 0) {
|
|
16003
|
+
this.contentBuffer = this.accumulator;
|
|
16004
|
+
}
|
|
16005
|
+
} else if (this.inTitleCapture) {
|
|
16006
|
+
this.titleBuffer = this.accumulator.substring(2);
|
|
16007
|
+
const titleEndIndex = this.titleBuffer.indexOf("**");
|
|
16008
|
+
if (titleEndIndex !== -1) {
|
|
16009
|
+
const title = this.titleBuffer.substring(0, titleEndIndex);
|
|
16010
|
+
const afterTitle = this.titleBuffer.substring(titleEndIndex + 2);
|
|
16011
|
+
this.hasTitle = true;
|
|
16012
|
+
this.inTitleCapture = false;
|
|
16013
|
+
this.currentTitle = title;
|
|
16014
|
+
this.contentBuffer = afterTitle;
|
|
16015
|
+
this.currentCallId = randomUUID();
|
|
16016
|
+
logger.debug(`${this.getLogPrefix()} Title captured: "${title}"`);
|
|
16017
|
+
this.sendToolCallStart(title);
|
|
16018
|
+
}
|
|
16019
|
+
} else if (this.hasTitle) {
|
|
16020
|
+
const titleStartIndex = this.accumulator.indexOf("**");
|
|
16021
|
+
if (titleStartIndex !== -1) {
|
|
16022
|
+
this.contentBuffer = this.accumulator.substring(
|
|
16023
|
+
titleStartIndex + 2 + this.currentTitle.length + 2
|
|
16024
|
+
);
|
|
16025
|
+
}
|
|
16026
|
+
} else {
|
|
16027
|
+
this.contentBuffer = this.accumulator;
|
|
16028
|
+
}
|
|
15731
16029
|
}
|
|
15732
|
-
|
|
15733
|
-
|
|
15734
|
-
|
|
15735
|
-
|
|
15736
|
-
|
|
15737
|
-
|
|
15738
|
-
}
|
|
15739
|
-
|
|
15740
|
-
|
|
15741
|
-
|
|
15742
|
-
|
|
15743
|
-
|
|
15744
|
-
|
|
15745
|
-
|
|
16030
|
+
/**
|
|
16031
|
+
* Send the tool call start message.
|
|
16032
|
+
*/
|
|
16033
|
+
sendToolCallStart(title) {
|
|
16034
|
+
if (!this.currentCallId || this.toolCallStarted) {
|
|
16035
|
+
return;
|
|
16036
|
+
}
|
|
16037
|
+
const toolCall = {
|
|
16038
|
+
type: "tool-call",
|
|
16039
|
+
name: this.getToolName(),
|
|
16040
|
+
callId: this.currentCallId,
|
|
16041
|
+
input: {
|
|
16042
|
+
title
|
|
16043
|
+
},
|
|
16044
|
+
id: randomUUID()
|
|
16045
|
+
};
|
|
16046
|
+
logger.debug(`${this.getLogPrefix()} Sending tool call start for: "${title}"`);
|
|
16047
|
+
this.onMessage?.(toolCall);
|
|
16048
|
+
this.toolCallStarted = true;
|
|
15746
16049
|
}
|
|
15747
|
-
|
|
15748
|
-
|
|
15749
|
-
|
|
15750
|
-
|
|
15751
|
-
|
|
15752
|
-
|
|
15753
|
-
|
|
15754
|
-
|
|
15755
|
-
|
|
15756
|
-
|
|
15757
|
-
|
|
15758
|
-
|
|
15759
|
-
|
|
15760
|
-
|
|
15761
|
-
|
|
15762
|
-
|
|
15763
|
-
|
|
16050
|
+
/**
|
|
16051
|
+
* Complete the reasoning section.
|
|
16052
|
+
* Returns true if reasoning was completed, false if there was nothing to complete.
|
|
16053
|
+
*/
|
|
16054
|
+
completeReasoning(fullText) {
|
|
16055
|
+
const text = fullText ?? this.accumulator;
|
|
16056
|
+
if (!text.trim() && !this.toolCallStarted) {
|
|
16057
|
+
logger.debug(`${this.getLogPrefix()} Complete called but no content accumulated, skipping`);
|
|
16058
|
+
return false;
|
|
16059
|
+
}
|
|
16060
|
+
let title;
|
|
16061
|
+
let content = text;
|
|
16062
|
+
if (text.startsWith("**")) {
|
|
16063
|
+
const titleEndIndex = text.indexOf("**", 2);
|
|
16064
|
+
if (titleEndIndex !== -1) {
|
|
16065
|
+
title = text.substring(2, titleEndIndex);
|
|
16066
|
+
content = text.substring(titleEndIndex + 2).trim();
|
|
16067
|
+
}
|
|
16068
|
+
}
|
|
16069
|
+
logger.debug(`${this.getLogPrefix()} Complete reasoning - Title: "${title}", Has content: ${content.length > 0}`);
|
|
16070
|
+
if (title && !this.toolCallStarted) {
|
|
16071
|
+
this.currentCallId = this.currentCallId || randomUUID();
|
|
16072
|
+
this.sendToolCallStart(title);
|
|
16073
|
+
}
|
|
16074
|
+
if (this.toolCallStarted && this.currentCallId) {
|
|
16075
|
+
const toolResult = {
|
|
16076
|
+
type: "tool-call-result",
|
|
16077
|
+
callId: this.currentCallId,
|
|
16078
|
+
output: {
|
|
16079
|
+
content,
|
|
16080
|
+
status: "completed"
|
|
16081
|
+
},
|
|
16082
|
+
id: randomUUID()
|
|
16083
|
+
};
|
|
16084
|
+
logger.debug(`${this.getLogPrefix()} Sending tool call result`);
|
|
16085
|
+
this.onMessage?.(toolResult);
|
|
16086
|
+
} else if (content.trim()) {
|
|
16087
|
+
const reasoningMessage = {
|
|
16088
|
+
type: "reasoning",
|
|
16089
|
+
message: content,
|
|
16090
|
+
id: randomUUID()
|
|
16091
|
+
};
|
|
16092
|
+
logger.debug(`${this.getLogPrefix()} Sending reasoning message`);
|
|
16093
|
+
this.onMessage?.(reasoningMessage);
|
|
16094
|
+
}
|
|
16095
|
+
this.resetState();
|
|
16096
|
+
return true;
|
|
15764
16097
|
}
|
|
15765
|
-
|
|
15766
|
-
|
|
16098
|
+
/**
|
|
16099
|
+
* Abort the current reasoning section.
|
|
16100
|
+
*/
|
|
16101
|
+
abort() {
|
|
16102
|
+
logger.debug(`${this.getLogPrefix()} Abort called`);
|
|
16103
|
+
this.finishCurrentToolCall("canceled");
|
|
16104
|
+
this.resetState();
|
|
15767
16105
|
}
|
|
15768
|
-
|
|
15769
|
-
|
|
15770
|
-
|
|
15771
|
-
|
|
15772
|
-
|
|
15773
|
-
|
|
15774
|
-
t: "tool-call-start",
|
|
15775
|
-
call: item.id,
|
|
15776
|
-
name,
|
|
15777
|
-
title,
|
|
15778
|
-
description: title,
|
|
15779
|
-
args
|
|
15780
|
-
}, {
|
|
15781
|
-
...opts,
|
|
15782
|
-
id: `${item.id}:start`
|
|
15783
|
-
}));
|
|
15784
|
-
if (output && output.trim().length > 0) {
|
|
15785
|
-
envelopes.push(createEnvelope("agent", {
|
|
15786
|
-
t: "text",
|
|
15787
|
-
text: output,
|
|
15788
|
-
thinking: true
|
|
15789
|
-
}, {
|
|
15790
|
-
...opts,
|
|
15791
|
-
id: `${item.id}:output`
|
|
15792
|
-
}));
|
|
16106
|
+
/**
|
|
16107
|
+
* Reset the processor state.
|
|
16108
|
+
*/
|
|
16109
|
+
reset() {
|
|
16110
|
+
this.finishCurrentToolCall("canceled");
|
|
16111
|
+
this.resetState();
|
|
15793
16112
|
}
|
|
15794
|
-
|
|
15795
|
-
|
|
15796
|
-
|
|
15797
|
-
|
|
15798
|
-
|
|
15799
|
-
|
|
15800
|
-
|
|
15801
|
-
|
|
15802
|
-
|
|
15803
|
-
|
|
15804
|
-
|
|
15805
|
-
|
|
15806
|
-
|
|
15807
|
-
|
|
15808
|
-
|
|
15809
|
-
|
|
15810
|
-
turn: turn.id,
|
|
15811
|
-
time: startedAt
|
|
15812
|
-
}));
|
|
15813
|
-
for (const item of turn.items ?? []) {
|
|
15814
|
-
switch (item.type) {
|
|
15815
|
-
case "userMessage": {
|
|
15816
|
-
const text = textFromInputItems(item.content);
|
|
15817
|
-
if (text) {
|
|
15818
|
-
envelopes.push(createEnvelope("user", { t: "text", text }, {
|
|
15819
|
-
id: item.id,
|
|
15820
|
-
time: startedAt,
|
|
15821
|
-
codexItemId: item.id
|
|
15822
|
-
}));
|
|
15823
|
-
}
|
|
15824
|
-
break;
|
|
15825
|
-
}
|
|
15826
|
-
case "agentMessage": {
|
|
15827
|
-
const text = typeof item.text === "string" ? item.text.trim() : "";
|
|
15828
|
-
if (text.length > 0) {
|
|
15829
|
-
envelopes.push(createEnvelope("agent", { t: "text", text }, {
|
|
15830
|
-
id: item.id,
|
|
15831
|
-
turn: turn.id,
|
|
15832
|
-
time: completedAt,
|
|
15833
|
-
codexItemId: item.id
|
|
15834
|
-
}));
|
|
15835
|
-
}
|
|
15836
|
-
break;
|
|
15837
|
-
}
|
|
15838
|
-
case "reasoning": {
|
|
15839
|
-
const text = reasoningText(item);
|
|
15840
|
-
if (text) {
|
|
15841
|
-
envelopes.push(createEnvelope("agent", { t: "text", text, thinking: true }, {
|
|
15842
|
-
id: item.id,
|
|
15843
|
-
turn: turn.id,
|
|
15844
|
-
time: startedAt,
|
|
15845
|
-
codexItemId: item.id
|
|
15846
|
-
}));
|
|
15847
|
-
}
|
|
15848
|
-
break;
|
|
15849
|
-
}
|
|
15850
|
-
case "commandExecution": {
|
|
15851
|
-
const command = typeof item.command === "string" ? item.command : "";
|
|
15852
|
-
emitHistoricalToolCall(
|
|
15853
|
-
envelopes,
|
|
15854
|
-
turn,
|
|
15855
|
-
item,
|
|
15856
|
-
"CodexBash",
|
|
15857
|
-
commandToTitle(command),
|
|
15858
|
-
{ command, cwd: item.cwd },
|
|
15859
|
-
typeof item.aggregatedOutput === "string" ? item.aggregatedOutput : null
|
|
15860
|
-
);
|
|
15861
|
-
break;
|
|
15862
|
-
}
|
|
15863
|
-
case "fileChange": {
|
|
15864
|
-
const title = "Apply patch";
|
|
15865
|
-
emitHistoricalToolCall(
|
|
15866
|
-
envelopes,
|
|
15867
|
-
turn,
|
|
15868
|
-
item,
|
|
15869
|
-
"CodexPatch",
|
|
15870
|
-
title,
|
|
15871
|
-
{ changes: item.changes, status: item.status },
|
|
15872
|
-
null
|
|
15873
|
-
);
|
|
15874
|
-
break;
|
|
15875
|
-
}
|
|
15876
|
-
case "mcpToolCall": {
|
|
15877
|
-
const title = `${item.server}.${item.tool}`;
|
|
15878
|
-
const output = item.error !== void 0 && item.error !== null ? String(item.error) : item.result !== void 0 && item.result !== null ? String(item.result) : null;
|
|
15879
|
-
emitHistoricalToolCall(
|
|
15880
|
-
envelopes,
|
|
15881
|
-
turn,
|
|
15882
|
-
item,
|
|
15883
|
-
"McpTool",
|
|
15884
|
-
title,
|
|
15885
|
-
{
|
|
15886
|
-
server: item.server,
|
|
15887
|
-
tool: item.tool,
|
|
15888
|
-
arguments: item.arguments
|
|
15889
|
-
},
|
|
15890
|
-
output
|
|
15891
|
-
);
|
|
15892
|
-
break;
|
|
15893
|
-
}
|
|
15894
|
-
}
|
|
16113
|
+
/**
|
|
16114
|
+
* Finish current tool call if one is in progress.
|
|
16115
|
+
*/
|
|
16116
|
+
finishCurrentToolCall(status) {
|
|
16117
|
+
if (this.toolCallStarted && this.currentCallId) {
|
|
16118
|
+
const toolResult = {
|
|
16119
|
+
type: "tool-call-result",
|
|
16120
|
+
callId: this.currentCallId,
|
|
16121
|
+
output: {
|
|
16122
|
+
content: this.contentBuffer || "",
|
|
16123
|
+
status
|
|
16124
|
+
},
|
|
16125
|
+
id: randomUUID()
|
|
16126
|
+
};
|
|
16127
|
+
logger.debug(`${this.getLogPrefix()} Sending tool call result with status: ${status}`);
|
|
16128
|
+
this.onMessage?.(toolResult);
|
|
15895
16129
|
}
|
|
15896
|
-
envelopes.push(createEnvelope("agent", { t: "turn-end", status: turnStatus(turn) }, {
|
|
15897
|
-
id: `${turn.id}:end`,
|
|
15898
|
-
turn: turn.id,
|
|
15899
|
-
time: completedAt
|
|
15900
|
-
}));
|
|
15901
16130
|
}
|
|
15902
|
-
|
|
15903
|
-
|
|
15904
|
-
|
|
15905
|
-
|
|
15906
|
-
|
|
16131
|
+
/**
|
|
16132
|
+
* Reset internal state.
|
|
16133
|
+
*/
|
|
16134
|
+
resetState() {
|
|
16135
|
+
this.accumulator = "";
|
|
16136
|
+
this.inTitleCapture = false;
|
|
16137
|
+
this.titleBuffer = "";
|
|
16138
|
+
this.contentBuffer = "";
|
|
16139
|
+
this.hasTitle = false;
|
|
16140
|
+
this.currentCallId = null;
|
|
16141
|
+
this.toolCallStarted = false;
|
|
16142
|
+
this.currentTitle = null;
|
|
15907
16143
|
}
|
|
15908
|
-
|
|
15909
|
-
|
|
15910
|
-
|
|
16144
|
+
/**
|
|
16145
|
+
* Get the current call ID for tool result matching.
|
|
16146
|
+
*/
|
|
16147
|
+
getCurrentCallId() {
|
|
16148
|
+
return this.currentCallId;
|
|
16149
|
+
}
|
|
16150
|
+
/**
|
|
16151
|
+
* Check if a tool call has been started.
|
|
16152
|
+
*/
|
|
16153
|
+
hasStartedToolCall() {
|
|
16154
|
+
return this.toolCallStarted;
|
|
15911
16155
|
}
|
|
15912
|
-
return `Applying patch to ${fileCount} files`;
|
|
15913
16156
|
}
|
|
15914
|
-
|
|
15915
|
-
|
|
15916
|
-
|
|
15917
|
-
return
|
|
16157
|
+
|
|
16158
|
+
class ReasoningProcessor extends BaseReasoningProcessor {
|
|
16159
|
+
getToolName() {
|
|
16160
|
+
return "CodexReasoning";
|
|
15918
16161
|
}
|
|
15919
|
-
|
|
15920
|
-
return "
|
|
16162
|
+
getLogPrefix() {
|
|
16163
|
+
return "[ReasoningProcessor]";
|
|
15921
16164
|
}
|
|
15922
|
-
|
|
15923
|
-
|
|
15924
|
-
|
|
15925
|
-
|
|
15926
|
-
|
|
15927
|
-
}
|
|
15928
|
-
return "cancelled";
|
|
16165
|
+
/**
|
|
16166
|
+
* Process a reasoning delta and accumulate content.
|
|
16167
|
+
*/
|
|
16168
|
+
processDelta(delta) {
|
|
16169
|
+
this.processInput(delta);
|
|
15929
16170
|
}
|
|
15930
|
-
|
|
15931
|
-
|
|
16171
|
+
/**
|
|
16172
|
+
* Complete the reasoning section with final text.
|
|
16173
|
+
*/
|
|
16174
|
+
complete(fullText) {
|
|
16175
|
+
this.completeReasoning(fullText);
|
|
15932
16176
|
}
|
|
15933
|
-
return "completed";
|
|
15934
16177
|
}
|
|
15935
|
-
|
|
15936
|
-
|
|
15937
|
-
|
|
15938
|
-
|
|
15939
|
-
|
|
15940
|
-
|
|
15941
|
-
const turnId = createId();
|
|
15942
|
-
const turnStart = createEnvelope("agent", { t: "turn-start" }, { turn: turnId });
|
|
15943
|
-
startedSubagents.clear();
|
|
15944
|
-
activeSubagents.clear();
|
|
15945
|
-
providerSubagentToSessionSubagent.clear();
|
|
15946
|
-
return {
|
|
15947
|
-
currentTurnId: turnId,
|
|
15948
|
-
startedSubagents,
|
|
15949
|
-
activeSubagents,
|
|
15950
|
-
providerSubagentToSessionSubagent,
|
|
15951
|
-
envelopes: [turnStart]
|
|
15952
|
-
};
|
|
15953
|
-
}
|
|
15954
|
-
if (type === "task_complete" || type === "turn_aborted") {
|
|
15955
|
-
if (!state.currentTurnId) {
|
|
15956
|
-
return {
|
|
15957
|
-
currentTurnId: null,
|
|
15958
|
-
startedSubagents,
|
|
15959
|
-
activeSubagents,
|
|
15960
|
-
providerSubagentToSessionSubagent,
|
|
15961
|
-
envelopes: []
|
|
15962
|
-
};
|
|
15963
|
-
}
|
|
15964
|
-
const lifecycleOpts = { turn: state.currentTurnId };
|
|
15965
|
-
providerSubagentToSessionSubagent.clear();
|
|
15966
|
-
return {
|
|
15967
|
-
currentTurnId: null,
|
|
15968
|
-
startedSubagents,
|
|
15969
|
-
activeSubagents,
|
|
15970
|
-
providerSubagentToSessionSubagent,
|
|
15971
|
-
envelopes: [
|
|
15972
|
-
...emitSubagentStops(lifecycleOpts, startedSubagents, activeSubagents),
|
|
15973
|
-
createEnvelope("agent", {
|
|
15974
|
-
t: "turn-end",
|
|
15975
|
-
status: pickTurnEndStatus(message, type)
|
|
15976
|
-
}, lifecycleOpts)
|
|
15977
|
-
]
|
|
15978
|
-
};
|
|
15979
|
-
}
|
|
15980
|
-
if (type === "token_count") {
|
|
15981
|
-
return {
|
|
15982
|
-
currentTurnId: state.currentTurnId,
|
|
15983
|
-
startedSubagents,
|
|
15984
|
-
activeSubagents,
|
|
15985
|
-
providerSubagentToSessionSubagent,
|
|
15986
|
-
envelopes: []
|
|
15987
|
-
};
|
|
16178
|
+
|
|
16179
|
+
class DiffProcessor {
|
|
16180
|
+
previousDiff = null;
|
|
16181
|
+
onMessage = null;
|
|
16182
|
+
constructor(onMessage) {
|
|
16183
|
+
this.onMessage = onMessage || null;
|
|
15988
16184
|
}
|
|
15989
|
-
|
|
15990
|
-
|
|
15991
|
-
|
|
15992
|
-
|
|
15993
|
-
|
|
15994
|
-
|
|
15995
|
-
|
|
15996
|
-
|
|
15997
|
-
|
|
15998
|
-
|
|
16185
|
+
/**
|
|
16186
|
+
* Process a turn_diff message and check if the unified_diff has changed
|
|
16187
|
+
*/
|
|
16188
|
+
processDiff(unifiedDiff) {
|
|
16189
|
+
if (this.previousDiff !== unifiedDiff) {
|
|
16190
|
+
logger.debug("[DiffProcessor] Unified diff changed, sending CodexDiff tool call");
|
|
16191
|
+
const callId = randomUUID();
|
|
16192
|
+
const toolCall = {
|
|
16193
|
+
type: "tool-call",
|
|
16194
|
+
name: "CodexDiff",
|
|
16195
|
+
callId,
|
|
16196
|
+
input: {
|
|
16197
|
+
unified_diff: unifiedDiff
|
|
16198
|
+
},
|
|
16199
|
+
id: randomUUID()
|
|
15999
16200
|
};
|
|
16000
|
-
|
|
16001
|
-
|
|
16002
|
-
|
|
16003
|
-
|
|
16004
|
-
|
|
16005
|
-
|
|
16006
|
-
|
|
16007
|
-
|
|
16008
|
-
providerSubagentToSessionSubagent,
|
|
16009
|
-
envelopes
|
|
16010
|
-
};
|
|
16011
|
-
}
|
|
16012
|
-
if (type === "agent_reasoning" || type === "agent_reasoning_delta") {
|
|
16013
|
-
const text = typeof message.text === "string" ? message.text : typeof message.delta === "string" ? message.delta : null;
|
|
16014
|
-
if (!text) {
|
|
16015
|
-
return {
|
|
16016
|
-
currentTurnId: state.currentTurnId,
|
|
16017
|
-
startedSubagents,
|
|
16018
|
-
activeSubagents,
|
|
16019
|
-
providerSubagentToSessionSubagent,
|
|
16020
|
-
envelopes: []
|
|
16201
|
+
this.onMessage?.(toolCall);
|
|
16202
|
+
const toolResult = {
|
|
16203
|
+
type: "tool-call-result",
|
|
16204
|
+
callId,
|
|
16205
|
+
output: {
|
|
16206
|
+
status: "completed"
|
|
16207
|
+
},
|
|
16208
|
+
id: randomUUID()
|
|
16021
16209
|
};
|
|
16210
|
+
this.onMessage?.(toolResult);
|
|
16022
16211
|
}
|
|
16023
|
-
|
|
16024
|
-
|
|
16025
|
-
envelopes.push(createEnvelope("agent", { t: "text", text, thinking: true }, opts));
|
|
16026
|
-
return {
|
|
16027
|
-
currentTurnId: state.currentTurnId,
|
|
16028
|
-
startedSubagents,
|
|
16029
|
-
activeSubagents,
|
|
16030
|
-
providerSubagentToSessionSubagent,
|
|
16031
|
-
envelopes
|
|
16032
|
-
};
|
|
16212
|
+
this.previousDiff = unifiedDiff;
|
|
16213
|
+
logger.debug("[DiffProcessor] Updated stored diff");
|
|
16033
16214
|
}
|
|
16034
|
-
|
|
16035
|
-
|
|
16036
|
-
|
|
16037
|
-
|
|
16038
|
-
|
|
16039
|
-
|
|
16040
|
-
maybeEmitSubagentStart(subagent, opts, startedSubagents, activeSubagents, envelopes);
|
|
16041
|
-
envelopes.push(
|
|
16042
|
-
createEnvelope("agent", {
|
|
16043
|
-
t: "tool-call-start",
|
|
16044
|
-
call,
|
|
16045
|
-
name: "CodexBash",
|
|
16046
|
-
title: commandToTitle(command),
|
|
16047
|
-
description,
|
|
16048
|
-
args
|
|
16049
|
-
}, opts)
|
|
16050
|
-
);
|
|
16051
|
-
return {
|
|
16052
|
-
currentTurnId: state.currentTurnId,
|
|
16053
|
-
startedSubagents,
|
|
16054
|
-
activeSubagents,
|
|
16055
|
-
providerSubagentToSessionSubagent,
|
|
16056
|
-
envelopes
|
|
16057
|
-
};
|
|
16215
|
+
/**
|
|
16216
|
+
* Reset the processor state (called on task_complete or turn_aborted)
|
|
16217
|
+
*/
|
|
16218
|
+
reset() {
|
|
16219
|
+
logger.debug("[DiffProcessor] Resetting diff state");
|
|
16220
|
+
this.previousDiff = null;
|
|
16058
16221
|
}
|
|
16059
|
-
|
|
16060
|
-
|
|
16061
|
-
|
|
16062
|
-
|
|
16063
|
-
|
|
16064
|
-
return {
|
|
16065
|
-
currentTurnId: state.currentTurnId,
|
|
16066
|
-
startedSubagents,
|
|
16067
|
-
activeSubagents,
|
|
16068
|
-
providerSubagentToSessionSubagent,
|
|
16069
|
-
envelopes
|
|
16070
|
-
};
|
|
16222
|
+
/**
|
|
16223
|
+
* Set the message callback for sending messages directly
|
|
16224
|
+
*/
|
|
16225
|
+
setMessageCallback(callback) {
|
|
16226
|
+
this.onMessage = callback;
|
|
16071
16227
|
}
|
|
16072
|
-
|
|
16073
|
-
|
|
16074
|
-
|
|
16075
|
-
|
|
16076
|
-
|
|
16077
|
-
maybeEmitSubagentStart(subagent, opts, startedSubagents, activeSubagents, envelopes);
|
|
16078
|
-
envelopes.push(
|
|
16079
|
-
createEnvelope("agent", {
|
|
16080
|
-
t: "tool-call-start",
|
|
16081
|
-
call,
|
|
16082
|
-
name: "CodexPatch",
|
|
16083
|
-
title: "Apply patch",
|
|
16084
|
-
description: patchDescription(changes),
|
|
16085
|
-
args: {
|
|
16086
|
-
auto_approved: autoApproved,
|
|
16087
|
-
changes
|
|
16088
|
-
}
|
|
16089
|
-
}, opts)
|
|
16090
|
-
);
|
|
16091
|
-
return {
|
|
16092
|
-
currentTurnId: state.currentTurnId,
|
|
16093
|
-
startedSubagents,
|
|
16094
|
-
activeSubagents,
|
|
16095
|
-
providerSubagentToSessionSubagent,
|
|
16096
|
-
envelopes
|
|
16097
|
-
};
|
|
16228
|
+
/**
|
|
16229
|
+
* Get the current diff value
|
|
16230
|
+
*/
|
|
16231
|
+
getCurrentDiff() {
|
|
16232
|
+
return this.previousDiff;
|
|
16098
16233
|
}
|
|
16099
|
-
|
|
16100
|
-
|
|
16101
|
-
|
|
16102
|
-
|
|
16103
|
-
|
|
16104
|
-
|
|
16105
|
-
|
|
16106
|
-
|
|
16107
|
-
|
|
16108
|
-
|
|
16109
|
-
|
|
16234
|
+
}
|
|
16235
|
+
|
|
16236
|
+
const CodexDisplay = ({ messageBuffer, logPath, onExit }) => {
|
|
16237
|
+
const [messages, setMessages] = useState([]);
|
|
16238
|
+
const [confirmationMode, setConfirmationMode] = useState(false);
|
|
16239
|
+
const [actionInProgress, setActionInProgress] = useState(false);
|
|
16240
|
+
const confirmationTimeoutRef = useRef(null);
|
|
16241
|
+
const { stdout } = useStdout();
|
|
16242
|
+
const terminalWidth = stdout.columns || 80;
|
|
16243
|
+
const terminalHeight = stdout.rows || 24;
|
|
16244
|
+
useEffect(() => {
|
|
16245
|
+
setMessages(messageBuffer.getMessages());
|
|
16246
|
+
const unsubscribe = messageBuffer.onUpdate((newMessages) => {
|
|
16247
|
+
setMessages(newMessages);
|
|
16248
|
+
});
|
|
16249
|
+
return () => {
|
|
16250
|
+
unsubscribe();
|
|
16251
|
+
if (confirmationTimeoutRef.current) {
|
|
16252
|
+
clearTimeout(confirmationTimeoutRef.current);
|
|
16253
|
+
}
|
|
16110
16254
|
};
|
|
16111
|
-
}
|
|
16255
|
+
}, [messageBuffer]);
|
|
16256
|
+
const resetConfirmation = useCallback(() => {
|
|
16257
|
+
setConfirmationMode(false);
|
|
16258
|
+
if (confirmationTimeoutRef.current) {
|
|
16259
|
+
clearTimeout(confirmationTimeoutRef.current);
|
|
16260
|
+
confirmationTimeoutRef.current = null;
|
|
16261
|
+
}
|
|
16262
|
+
}, []);
|
|
16263
|
+
const setConfirmationWithTimeout = useCallback(() => {
|
|
16264
|
+
setConfirmationMode(true);
|
|
16265
|
+
if (confirmationTimeoutRef.current) {
|
|
16266
|
+
clearTimeout(confirmationTimeoutRef.current);
|
|
16267
|
+
}
|
|
16268
|
+
confirmationTimeoutRef.current = setTimeout(() => {
|
|
16269
|
+
resetConfirmation();
|
|
16270
|
+
}, 15e3);
|
|
16271
|
+
}, [resetConfirmation]);
|
|
16272
|
+
useInput(useCallback(async (input, key) => {
|
|
16273
|
+
if (actionInProgress) return;
|
|
16274
|
+
if (key.ctrl && input === "c") {
|
|
16275
|
+
if (confirmationMode) {
|
|
16276
|
+
resetConfirmation();
|
|
16277
|
+
setActionInProgress(true);
|
|
16278
|
+
await new Promise((resolve) => setTimeout(resolve, 100));
|
|
16279
|
+
onExit?.();
|
|
16280
|
+
} else {
|
|
16281
|
+
setConfirmationWithTimeout();
|
|
16282
|
+
}
|
|
16283
|
+
return;
|
|
16284
|
+
}
|
|
16285
|
+
if (confirmationMode) {
|
|
16286
|
+
resetConfirmation();
|
|
16287
|
+
}
|
|
16288
|
+
}, [confirmationMode, actionInProgress, onExit, setConfirmationWithTimeout, resetConfirmation]));
|
|
16289
|
+
const getMessageColor = (type) => {
|
|
16290
|
+
switch (type) {
|
|
16291
|
+
case "user":
|
|
16292
|
+
return "magenta";
|
|
16293
|
+
case "assistant":
|
|
16294
|
+
return "cyan";
|
|
16295
|
+
case "system":
|
|
16296
|
+
return "blue";
|
|
16297
|
+
case "tool":
|
|
16298
|
+
return "yellow";
|
|
16299
|
+
case "result":
|
|
16300
|
+
return "green";
|
|
16301
|
+
case "status":
|
|
16302
|
+
return "gray";
|
|
16303
|
+
default:
|
|
16304
|
+
return "white";
|
|
16305
|
+
}
|
|
16306
|
+
};
|
|
16307
|
+
const formatMessage = (msg) => {
|
|
16308
|
+
const lines = msg.content.split("\n");
|
|
16309
|
+
const maxLineLength = terminalWidth - 10;
|
|
16310
|
+
return lines.map((line) => {
|
|
16311
|
+
if (line.length <= maxLineLength) return line;
|
|
16312
|
+
const chunks = [];
|
|
16313
|
+
for (let i = 0; i < line.length; i += maxLineLength) {
|
|
16314
|
+
chunks.push(line.slice(i, i + maxLineLength));
|
|
16315
|
+
}
|
|
16316
|
+
return chunks.join("\n");
|
|
16317
|
+
}).join("\n");
|
|
16318
|
+
};
|
|
16319
|
+
return /* @__PURE__ */ React.createElement(Box, { flexDirection: "column", width: terminalWidth, height: terminalHeight }, /* @__PURE__ */ React.createElement(
|
|
16320
|
+
Box,
|
|
16321
|
+
{
|
|
16322
|
+
flexDirection: "column",
|
|
16323
|
+
width: terminalWidth,
|
|
16324
|
+
height: terminalHeight - 4,
|
|
16325
|
+
borderStyle: "round",
|
|
16326
|
+
borderColor: "gray",
|
|
16327
|
+
paddingX: 1,
|
|
16328
|
+
overflow: "hidden"
|
|
16329
|
+
},
|
|
16330
|
+
/* @__PURE__ */ React.createElement(Box, { flexDirection: "column", marginBottom: 1 }, /* @__PURE__ */ React.createElement(Text, { color: "gray", bold: true }, "\u{1F916} Codex Agent Messages"), /* @__PURE__ */ React.createElement(Text, { color: "gray", dimColor: true }, "\u2500".repeat(Math.min(terminalWidth - 4, 60)))),
|
|
16331
|
+
/* @__PURE__ */ React.createElement(Box, { flexDirection: "column", height: terminalHeight - 10, overflow: "hidden" }, messages.length === 0 ? /* @__PURE__ */ React.createElement(Text, { color: "gray", dimColor: true }, "Waiting for messages...") : (
|
|
16332
|
+
// Show only the last messages that fit in the available space
|
|
16333
|
+
messages.slice(-Math.max(1, terminalHeight - 10)).map((msg) => /* @__PURE__ */ React.createElement(Box, { key: msg.id, flexDirection: "column", marginBottom: 1 }, /* @__PURE__ */ React.createElement(Text, { color: getMessageColor(msg.type), dimColor: true }, formatMessage(msg))))
|
|
16334
|
+
))
|
|
16335
|
+
), /* @__PURE__ */ React.createElement(
|
|
16336
|
+
Box,
|
|
16337
|
+
{
|
|
16338
|
+
width: terminalWidth,
|
|
16339
|
+
borderStyle: "round",
|
|
16340
|
+
borderColor: actionInProgress ? "gray" : confirmationMode ? "red" : "green",
|
|
16341
|
+
paddingX: 2,
|
|
16342
|
+
justifyContent: "center",
|
|
16343
|
+
alignItems: "center",
|
|
16344
|
+
flexDirection: "column"
|
|
16345
|
+
},
|
|
16346
|
+
/* @__PURE__ */ React.createElement(Box, { flexDirection: "column", alignItems: "center" }, actionInProgress ? /* @__PURE__ */ React.createElement(Text, { color: "gray", bold: true }, "Exiting agent...") : confirmationMode ? /* @__PURE__ */ React.createElement(Text, { color: "red", bold: true }, "\u26A0\uFE0F Press Ctrl-C again to exit the agent") : /* @__PURE__ */ React.createElement(React.Fragment, null, /* @__PURE__ */ React.createElement(Text, { color: "green", bold: true }, "\u{1F916} Codex Agent Running \u2022 Ctrl-C to exit")), process.env.DEBUG && logPath && /* @__PURE__ */ React.createElement(Text, { color: "gray", dimColor: true }, "Debug logs: ", logPath))
|
|
16347
|
+
));
|
|
16348
|
+
};
|
|
16349
|
+
|
|
16350
|
+
function createOfflineSessionStub(sessionTag) {
|
|
16112
16351
|
return {
|
|
16113
|
-
|
|
16114
|
-
|
|
16115
|
-
|
|
16116
|
-
|
|
16117
|
-
|
|
16352
|
+
sessionId: `offline-${sessionTag}`,
|
|
16353
|
+
sendCodexMessage: () => {
|
|
16354
|
+
},
|
|
16355
|
+
sendAgentMessage: () => {
|
|
16356
|
+
},
|
|
16357
|
+
sendAgentUsageSnapshot: () => false,
|
|
16358
|
+
sendClaudeSessionMessage: () => {
|
|
16359
|
+
},
|
|
16360
|
+
keepAlive: () => {
|
|
16361
|
+
},
|
|
16362
|
+
sendSessionEvent: () => {
|
|
16363
|
+
},
|
|
16364
|
+
sendSessionDeath: () => {
|
|
16365
|
+
},
|
|
16366
|
+
updateLifecycleState: () => {
|
|
16367
|
+
},
|
|
16368
|
+
requestControlTransfer: async () => {
|
|
16369
|
+
},
|
|
16370
|
+
flush: async () => {
|
|
16371
|
+
},
|
|
16372
|
+
close: async () => {
|
|
16373
|
+
},
|
|
16374
|
+
updateMetadata: () => {
|
|
16375
|
+
},
|
|
16376
|
+
updateAgentState: () => {
|
|
16377
|
+
},
|
|
16378
|
+
onUserMessage: () => {
|
|
16379
|
+
},
|
|
16380
|
+
onFileEvent: () => {
|
|
16381
|
+
},
|
|
16382
|
+
trackAttachmentDownload: () => {
|
|
16383
|
+
},
|
|
16384
|
+
drainAttachmentsForUserMessage: async () => [],
|
|
16385
|
+
rpcHandlerManager: {
|
|
16386
|
+
registerHandler: () => {
|
|
16387
|
+
}
|
|
16388
|
+
}
|
|
16118
16389
|
};
|
|
16119
16390
|
}
|
|
16120
|
-
|
|
16121
|
-
|
|
16122
|
-
const
|
|
16123
|
-
|
|
16124
|
-
|
|
16125
|
-
|
|
16126
|
-
|
|
16127
|
-
|
|
16128
|
-
|
|
16391
|
+
|
|
16392
|
+
function setupOfflineReconnection(opts) {
|
|
16393
|
+
const { api, sessionTag, metadata, state, response, onSessionSwap } = opts;
|
|
16394
|
+
let session;
|
|
16395
|
+
let reconnectionHandle = null;
|
|
16396
|
+
if (!response) {
|
|
16397
|
+
session = createOfflineSessionStub(sessionTag);
|
|
16398
|
+
reconnectionHandle = startOfflineReconnection({
|
|
16399
|
+
serverUrl: configuration.serverUrl,
|
|
16400
|
+
onReconnected: async () => {
|
|
16401
|
+
const resp = await api.getOrCreateSession({ tag: sessionTag, metadata, state });
|
|
16402
|
+
if (!resp) throw new Error("Server unavailable");
|
|
16403
|
+
const realSession = api.sessionSyncClient(resp);
|
|
16404
|
+
onSessionSwap(realSession);
|
|
16405
|
+
return realSession;
|
|
16406
|
+
},
|
|
16407
|
+
onNotify: (msg) => {
|
|
16408
|
+
console.log(msg);
|
|
16409
|
+
}
|
|
16410
|
+
});
|
|
16411
|
+
return { session, reconnectionHandle, isOffline: true };
|
|
16412
|
+
} else {
|
|
16413
|
+
session = api.sessionSyncClient(response, opts.sessionClientOptions);
|
|
16414
|
+
return { session, reconnectionHandle: null, isOffline: false };
|
|
16129
16415
|
}
|
|
16130
|
-
|
|
16131
|
-
|
|
16132
|
-
|
|
16133
|
-
|
|
16134
|
-
|
|
16135
|
-
|
|
16136
|
-
|
|
16137
|
-
|
|
16138
|
-
args: toolLikeMessage.input && typeof toolLikeMessage.input === "object" ? toolLikeMessage.input : {}
|
|
16139
|
-
}, opts)];
|
|
16416
|
+
}
|
|
16417
|
+
|
|
16418
|
+
function resolveCodexExecutionPolicy(permissionMode, sandboxManagedByHappy) {
|
|
16419
|
+
if (sandboxManagedByHappy) {
|
|
16420
|
+
return {
|
|
16421
|
+
approvalPolicy: "never",
|
|
16422
|
+
sandbox: "danger-full-access"
|
|
16423
|
+
};
|
|
16140
16424
|
}
|
|
16141
|
-
|
|
16142
|
-
|
|
16143
|
-
|
|
16144
|
-
|
|
16145
|
-
|
|
16146
|
-
|
|
16147
|
-
|
|
16148
|
-
|
|
16149
|
-
|
|
16425
|
+
const approvalPolicy = (() => {
|
|
16426
|
+
switch (permissionMode) {
|
|
16427
|
+
// Codex native modes
|
|
16428
|
+
case "default":
|
|
16429
|
+
return "untrusted";
|
|
16430
|
+
// Ask for non-trusted commands
|
|
16431
|
+
case "read-only":
|
|
16432
|
+
return "never";
|
|
16433
|
+
// Never ask, read-only enforced by sandbox
|
|
16434
|
+
case "safe-yolo":
|
|
16435
|
+
return "on-request";
|
|
16436
|
+
// Workspace auto-run; request approval for escalation (0.153 removed on-failure)
|
|
16437
|
+
case "yolo":
|
|
16438
|
+
return "never";
|
|
16439
|
+
// Full YOLO: never interrupt for approvals
|
|
16440
|
+
// Defensive fallback for Claude-specific modes (backward compatibility)
|
|
16441
|
+
case "bypassPermissions":
|
|
16442
|
+
return "never";
|
|
16443
|
+
// Full access: map to yolo behavior
|
|
16444
|
+
case "acceptEdits":
|
|
16445
|
+
return "on-request";
|
|
16446
|
+
// Let model decide (closest to auto-approve edits)
|
|
16447
|
+
case "plan":
|
|
16448
|
+
return "untrusted";
|
|
16449
|
+
// Conservative: ask for non-trusted
|
|
16450
|
+
default:
|
|
16451
|
+
return "untrusted";
|
|
16150
16452
|
}
|
|
16151
|
-
|
|
16152
|
-
|
|
16153
|
-
|
|
16154
|
-
|
|
16155
|
-
|
|
16156
|
-
|
|
16157
|
-
|
|
16453
|
+
})();
|
|
16454
|
+
const sandbox = (() => {
|
|
16455
|
+
switch (permissionMode) {
|
|
16456
|
+
// Codex native modes
|
|
16457
|
+
case "default":
|
|
16458
|
+
return "workspace-write";
|
|
16459
|
+
// Can write in workspace
|
|
16460
|
+
case "read-only":
|
|
16461
|
+
return "read-only";
|
|
16462
|
+
// Read-only filesystem
|
|
16463
|
+
case "safe-yolo":
|
|
16464
|
+
return "workspace-write";
|
|
16465
|
+
// Can write in workspace
|
|
16466
|
+
case "yolo":
|
|
16467
|
+
return "danger-full-access";
|
|
16468
|
+
// Full system access
|
|
16469
|
+
// Defensive fallback for Claude-specific modes
|
|
16470
|
+
case "bypassPermissions":
|
|
16471
|
+
return "danger-full-access";
|
|
16472
|
+
// Full access: map to yolo
|
|
16473
|
+
case "acceptEdits":
|
|
16474
|
+
return "workspace-write";
|
|
16475
|
+
// Can edit files in workspace
|
|
16476
|
+
case "plan":
|
|
16477
|
+
return "workspace-write";
|
|
16478
|
+
// Can write for planning
|
|
16479
|
+
default:
|
|
16480
|
+
return "workspace-write";
|
|
16481
|
+
}
|
|
16482
|
+
})();
|
|
16483
|
+
return { approvalPolicy, sandbox };
|
|
16158
16484
|
}
|
|
16159
16485
|
|
|
16160
16486
|
async function resumeExistingThread(opts) {
|
|
@@ -16626,8 +16952,15 @@ async function runCodex(opts) {
|
|
|
16626
16952
|
process.exit(1);
|
|
16627
16953
|
}
|
|
16628
16954
|
};
|
|
16955
|
+
session.rpcHandlerManager.registerHandler("codex-child-read", async (args) => {
|
|
16956
|
+
try {
|
|
16957
|
+
return await readChildThread(client, args?.threadId);
|
|
16958
|
+
} catch (error) {
|
|
16959
|
+
return { error: error instanceof Error ? error.message : "Child read failed" };
|
|
16960
|
+
}
|
|
16961
|
+
});
|
|
16629
16962
|
session.rpcHandlerManager.registerHandler("abort", handleAbort);
|
|
16630
|
-
registerKillSessionHandler(session.rpcHandlerManager, handleKillSession, session);
|
|
16963
|
+
const disposeTermination = registerKillSessionHandler(session.rpcHandlerManager, handleKillSession, session, { processSignals: true });
|
|
16631
16964
|
const messageBuffer = new MessageBuffer();
|
|
16632
16965
|
const hasTTY = process.stdout.isTTY && process.stdin.isTTY;
|
|
16633
16966
|
let inkInstance = null;
|
|
@@ -16963,6 +17296,7 @@ async function runCodex(opts) {
|
|
|
16963
17296
|
}
|
|
16964
17297
|
}
|
|
16965
17298
|
} finally {
|
|
17299
|
+
disposeTermination?.();
|
|
16966
17300
|
logger.debug("[codex]: Final cleanup start");
|
|
16967
17301
|
logActiveHandles("cleanup-start");
|
|
16968
17302
|
if (reconnectionHandle) {
|
|
@@ -17165,7 +17499,7 @@ Conversation history is preserved on the server, but in-flight tool calls are in
|
|
|
17165
17499
|
process.exit(0);
|
|
17166
17500
|
} else if (subcommand === "install-terminal-hooks") {
|
|
17167
17501
|
try {
|
|
17168
|
-
const { installTerminalHooks, parseTerminalHooksArgs, TERMINAL_HOOKS_HELP } = await import('./installTerminalHooks-
|
|
17502
|
+
const { installTerminalHooks, parseTerminalHooksArgs, TERMINAL_HOOKS_HELP } = await import('./installTerminalHooks-BWoHGCew.mjs');
|
|
17169
17503
|
const command = parseTerminalHooksArgs(args.slice(1));
|
|
17170
17504
|
if (command.action === "help") {
|
|
17171
17505
|
console.log(TERMINAL_HOOKS_HELP);
|
|
@@ -17182,7 +17516,7 @@ Conversation history is preserved on the server, but in-flight tool calls are in
|
|
|
17182
17516
|
}
|
|
17183
17517
|
} else if (subcommand === "spawn") {
|
|
17184
17518
|
try {
|
|
17185
|
-
const { handleSpawnCommand } = await import('./spawn-
|
|
17519
|
+
const { handleSpawnCommand } = await import('./spawn-CF1ZV-YH.mjs');
|
|
17186
17520
|
await handleSpawnCommand(args.slice(1));
|
|
17187
17521
|
} catch (error) {
|
|
17188
17522
|
console.error(chalk.red("Error:"), error instanceof Error ? error.message : "Unknown error");
|
|
@@ -17194,7 +17528,7 @@ Conversation history is preserved on the server, but in-flight tool calls are in
|
|
|
17194
17528
|
return;
|
|
17195
17529
|
} else if (subcommand === "sessions") {
|
|
17196
17530
|
try {
|
|
17197
|
-
const { handleSessionsCommand } = await import('./sessions-
|
|
17531
|
+
const { handleSessionsCommand } = await import('./sessions-5fJxQ2xj.mjs');
|
|
17198
17532
|
await handleSessionsCommand(args.slice(1));
|
|
17199
17533
|
} catch (error) {
|
|
17200
17534
|
console.error(chalk.red("Error:"), error instanceof Error ? error.message : "Unknown error");
|
|
@@ -17206,7 +17540,7 @@ Conversation history is preserved on the server, but in-flight tool calls are in
|
|
|
17206
17540
|
return;
|
|
17207
17541
|
} else if (subcommand === "send") {
|
|
17208
17542
|
try {
|
|
17209
|
-
const { handleSendCommand } = await import('./send-
|
|
17543
|
+
const { handleSendCommand } = await import('./send-fWHOFJV9.mjs');
|
|
17210
17544
|
await handleSendCommand(args.slice(1));
|
|
17211
17545
|
} catch (error) {
|
|
17212
17546
|
console.error(chalk.red("Error:"), error instanceof Error ? error.message : "Unknown error");
|
|
@@ -17312,9 +17646,9 @@ Conversation history is preserved on the server, but in-flight tool calls are in
|
|
|
17312
17646
|
if (geminiSubcommand === "project" && args[2] === "set" && args[3]) {
|
|
17313
17647
|
const projectId = args[3];
|
|
17314
17648
|
try {
|
|
17315
|
-
const { saveGoogleCloudProjectToConfig } = await import('./config-
|
|
17316
|
-
const { readCredentialsForConfiguredRelay: readCredentialsForConfiguredRelay2 } = await import('./limits-
|
|
17317
|
-
const { ApiClient: ApiClient2 } = await import('./types-
|
|
17649
|
+
const { saveGoogleCloudProjectToConfig } = await import('./config-DzvbcL_x.mjs');
|
|
17650
|
+
const { readCredentialsForConfiguredRelay: readCredentialsForConfiguredRelay2 } = await import('./limits-CPTgiQ9A.mjs').then(function (n) { return n.W; });
|
|
17651
|
+
const { ApiClient: ApiClient2 } = await import('./types-BEXGahmj.mjs').then(function (n) { return n.a0; });
|
|
17318
17652
|
let userEmail = void 0;
|
|
17319
17653
|
try {
|
|
17320
17654
|
const credentials = await readCredentialsForConfiguredRelay2();
|
|
@@ -17345,7 +17679,7 @@ Conversation history is preserved on the server, but in-flight tool calls are in
|
|
|
17345
17679
|
}
|
|
17346
17680
|
if (geminiSubcommand === "project" && args[2] === "get") {
|
|
17347
17681
|
try {
|
|
17348
|
-
const { readGeminiLocalConfig } = await import('./config-
|
|
17682
|
+
const { readGeminiLocalConfig } = await import('./config-DzvbcL_x.mjs');
|
|
17349
17683
|
const config = readGeminiLocalConfig();
|
|
17350
17684
|
if (config.googleCloudProject) {
|
|
17351
17685
|
console.log(`Current Google Cloud Project: ${config.googleCloudProject}`);
|
|
@@ -17385,7 +17719,7 @@ Conversation history is preserved on the server, but in-flight tool calls are in
|
|
|
17385
17719
|
process.exit(0);
|
|
17386
17720
|
}
|
|
17387
17721
|
try {
|
|
17388
|
-
const { runGemini } = await import('./runGemini-
|
|
17722
|
+
const { runGemini } = await import('./runGemini-BVJE7LZl.mjs');
|
|
17389
17723
|
let startedBy = void 0;
|
|
17390
17724
|
for (let i = 1; i < args.length; i++) {
|
|
17391
17725
|
if (args[i] === "--started-by") {
|
|
@@ -17415,7 +17749,7 @@ Conversation history is preserved on the server, but in-flight tool calls are in
|
|
|
17415
17749
|
}
|
|
17416
17750
|
};
|
|
17417
17751
|
try {
|
|
17418
|
-
const { runAcp, resolveAcpAgentConfig } = await import('./index-
|
|
17752
|
+
const { runAcp, resolveAcpAgentConfig } = await import('./index-C33JB4xB.mjs');
|
|
17419
17753
|
const parsed = parsePiRunnerArgs(args.slice(1));
|
|
17420
17754
|
const resolved = resolveAcpAgentConfig(["pi", ...parsed.passthrough]);
|
|
17421
17755
|
const { credentials } = await authAndSetupMachineIfNeeded();
|
|
@@ -17443,7 +17777,7 @@ Conversation history is preserved on the server, but in-flight tool calls are in
|
|
|
17443
17777
|
return;
|
|
17444
17778
|
} else if (subcommand === "acp") {
|
|
17445
17779
|
try {
|
|
17446
|
-
const { runAcp, resolveAcpAgentConfig } = await import('./index-
|
|
17780
|
+
const { runAcp, resolveAcpAgentConfig } = await import('./index-C33JB4xB.mjs');
|
|
17447
17781
|
let startedBy = void 0;
|
|
17448
17782
|
let verbose = false;
|
|
17449
17783
|
const acpArgs = [];
|
|
@@ -17483,7 +17817,7 @@ Conversation history is preserved on the server, but in-flight tool calls are in
|
|
|
17483
17817
|
return;
|
|
17484
17818
|
} else if (subcommand === "openclaw") {
|
|
17485
17819
|
try {
|
|
17486
|
-
const { runOpenClaw } = await import('./runOpenClaw-
|
|
17820
|
+
const { runOpenClaw } = await import('./runOpenClaw-CJaIYpB7.mjs');
|
|
17487
17821
|
let startedBy = void 0;
|
|
17488
17822
|
let verbose = false;
|
|
17489
17823
|
let gatewayUrl;
|
|
@@ -17534,7 +17868,7 @@ Conversation history is preserved on the server, but in-flight tool calls are in
|
|
|
17534
17868
|
return;
|
|
17535
17869
|
} else if (subcommand === "todo") {
|
|
17536
17870
|
try {
|
|
17537
|
-
const { handleTodoCommand } = await import('./todo-
|
|
17871
|
+
const { handleTodoCommand } = await import('./todo-BAK2DVLV.mjs');
|
|
17538
17872
|
await handleTodoCommand(args.slice(1));
|
|
17539
17873
|
} catch (error) {
|
|
17540
17874
|
console.error(JSON.stringify({ error: error instanceof Error ? error.message : "Todo command failed" }));
|
|
@@ -17543,7 +17877,7 @@ Conversation history is preserved on the server, but in-flight tool calls are in
|
|
|
17543
17877
|
return;
|
|
17544
17878
|
} else if (subcommand === "teams") {
|
|
17545
17879
|
try {
|
|
17546
|
-
const { handleTeamsCommand } = await import('./teams-
|
|
17880
|
+
const { handleTeamsCommand } = await import('./teams-gzvKrMfn.mjs');
|
|
17547
17881
|
await handleTeamsCommand(args.slice(1));
|
|
17548
17882
|
} catch (error) {
|
|
17549
17883
|
console.error(error instanceof Error ? error.message : "Teams command failed");
|
|
@@ -17552,7 +17886,7 @@ Conversation history is preserved on the server, but in-flight tool calls are in
|
|
|
17552
17886
|
return;
|
|
17553
17887
|
} else if (subcommand === "mcp" && args.length === 1) {
|
|
17554
17888
|
try {
|
|
17555
|
-
const { handleMcpCommand } = await import('./mcp-
|
|
17889
|
+
const { handleMcpCommand } = await import('./mcp-DhuxpwTB.mjs');
|
|
17556
17890
|
await handleMcpCommand();
|
|
17557
17891
|
} catch (error) {
|
|
17558
17892
|
process.stderr.write(`[very-happy mcp] Fatal: ${error instanceof Error ? error.message : String(error)}
|