cli-jaw 2.2.8 → 2.2.10
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/README.md +4 -4
- package/dist/bin/agent-driven.js +33 -0
- package/dist/bin/agent-driven.js.map +1 -0
- package/dist/bin/commands/doctor.js +66 -1
- package/dist/bin/commands/doctor.js.map +1 -1
- package/dist/bin/commands/init.js +107 -8
- package/dist/bin/commands/init.js.map +1 -1
- package/dist/bin/interactive-confirm.js +110 -0
- package/dist/bin/interactive-confirm.js.map +1 -0
- package/dist/bin/star-prompt.js +46 -15
- package/dist/bin/star-prompt.js.map +1 -1
- package/dist/lib/upload.js +5 -1
- package/dist/lib/upload.js.map +1 -1
- package/dist/server.js +1 -0
- package/dist/server.js.map +1 -1
- package/dist/src/agent/alert-escalation.js +1 -1
- package/dist/src/agent/alert-escalation.js.map +1 -1
- package/dist/src/agent/codex-app-catalog.js +57 -0
- package/dist/src/agent/codex-app-catalog.js.map +1 -0
- package/dist/src/agent/codex-app-client.js +89 -7
- package/dist/src/agent/codex-app-client.js.map +1 -1
- package/dist/src/agent/pi-rpc-verdict.js +22 -0
- package/dist/src/agent/pi-rpc-verdict.js.map +1 -0
- package/dist/src/agent/pi-runtime.js +240 -0
- package/dist/src/agent/pi-runtime.js.map +1 -1
- package/dist/src/agent/runtime-pool.js +445 -0
- package/dist/src/agent/runtime-pool.js.map +1 -0
- package/dist/src/agent/spawn.js +395 -240
- package/dist/src/agent/spawn.js.map +1 -1
- package/dist/src/cli/command-context.js +5 -2
- package/dist/src/cli/command-context.js.map +1 -1
- package/dist/src/cli/commands.js +43 -39
- package/dist/src/cli/commands.js.map +1 -1
- package/dist/src/cli/handlers-runtime.js +15 -7
- package/dist/src/cli/handlers-runtime.js.map +1 -1
- package/dist/src/cli/handlers-search.js +1 -1
- package/dist/src/cli/handlers-search.js.map +1 -1
- package/dist/src/cli/handlers-skill-invoke.js +1 -1
- package/dist/src/cli/handlers-skill-invoke.js.map +1 -1
- package/dist/src/cli/handlers-workflows.js +1 -1
- package/dist/src/cli/handlers-workflows.js.map +1 -1
- package/dist/src/cli/handlers.js +1 -1
- package/dist/src/cli/handlers.js.map +1 -1
- package/dist/src/cli/opencodex-models.js +40 -7
- package/dist/src/cli/opencodex-models.js.map +1 -1
- package/dist/src/cli/registry-live.js +6 -5
- package/dist/src/cli/registry-live.js.map +1 -1
- package/dist/src/command-contract/catalog.js +4 -0
- package/dist/src/command-contract/catalog.js.map +1 -1
- package/dist/src/core/config.js +69 -4
- package/dist/src/core/config.js.map +1 -1
- package/dist/src/core/runtime-settings.js +17 -0
- package/dist/src/core/runtime-settings.js.map +1 -1
- package/dist/src/core/settings-merge.js +1 -1
- package/dist/src/core/settings-merge.js.map +1 -1
- package/dist/src/discord/bot.js +29 -14
- package/dist/src/discord/bot.js.map +1 -1
- package/dist/src/discord/commands.js +5 -4
- package/dist/src/discord/commands.js.map +1 -1
- package/dist/src/discord/discord-file.js +8 -2
- package/dist/src/discord/discord-file.js.map +1 -1
- package/dist/src/discord/forwarder.js +17 -19
- package/dist/src/discord/forwarder.js.map +1 -1
- package/dist/src/discord/send-only-client.js +9 -1
- package/dist/src/discord/send-only-client.js.map +1 -1
- package/dist/src/manager/dashboard-service.js +38 -1
- package/dist/src/manager/dashboard-service.js.map +1 -1
- package/dist/src/manager/telegram-hub/hub-bot.js +47 -29
- package/dist/src/manager/telegram-hub/hub-bot.js.map +1 -1
- package/dist/src/messaging/channel-health.js +32 -0
- package/dist/src/messaging/channel-health.js.map +1 -1
- package/dist/src/messaging/chunk.js +376 -0
- package/dist/src/messaging/chunk.js.map +1 -0
- package/dist/src/messaging/dedupe.js +104 -0
- package/dist/src/messaging/dedupe.js.map +1 -0
- package/dist/src/messaging/fold.js +210 -0
- package/dist/src/messaging/fold.js.map +1 -0
- package/dist/src/messaging/redact.js +577 -0
- package/dist/src/messaging/redact.js.map +1 -0
- package/dist/src/messaging/retry.js +76 -0
- package/dist/src/messaging/retry.js.map +1 -0
- package/dist/src/messaging/runtime.js +6 -3
- package/dist/src/messaging/runtime.js.map +1 -1
- package/dist/src/messaging/send.js +45 -15
- package/dist/src/messaging/send.js.map +1 -1
- package/dist/src/messaging/slack-target.js +50 -0
- package/dist/src/messaging/slack-target.js.map +1 -0
- package/dist/src/messaging/types.js.map +1 -1
- package/dist/src/orchestrator/pipeline.js +4 -4
- package/dist/src/orchestrator/pipeline.js.map +1 -1
- package/dist/src/routes/command.js +11 -7
- package/dist/src/routes/command.js.map +1 -1
- package/dist/src/routes/messaging.js +28 -12
- package/dist/src/routes/messaging.js.map +1 -1
- package/dist/src/routes/settings.js +22 -6
- package/dist/src/routes/settings.js.map +1 -1
- package/dist/src/slack/api.js +116 -0
- package/dist/src/slack/api.js.map +1 -0
- package/dist/src/slack/bot.js +262 -0
- package/dist/src/slack/bot.js.map +1 -0
- package/dist/src/slack/commands.js +98 -0
- package/dist/src/slack/commands.js.map +1 -0
- package/dist/src/slack/events.js +116 -0
- package/dist/src/slack/events.js.map +1 -0
- package/dist/src/slack/format.js +58 -0
- package/dist/src/slack/format.js.map +1 -0
- package/dist/src/slack/forwarder.js +57 -0
- package/dist/src/slack/forwarder.js.map +1 -0
- package/dist/src/slack/register.js +13 -0
- package/dist/src/slack/register.js.map +1 -0
- package/dist/src/slack/send-handler.js +41 -0
- package/dist/src/slack/send-handler.js.map +1 -0
- package/dist/src/slack/send-only-client.js +46 -0
- package/dist/src/slack/send-only-client.js.map +1 -0
- package/dist/src/slack/slack-file.js +72 -0
- package/dist/src/slack/slack-file.js.map +1 -0
- package/dist/src/slack/socket.js +341 -0
- package/dist/src/slack/socket.js.map +1 -0
- package/dist/src/telegram/bot.js +117 -37
- package/dist/src/telegram/bot.js.map +1 -1
- package/dist/src/telegram/elicitation-buttons.js +7 -2
- package/dist/src/telegram/elicitation-buttons.js.map +1 -1
- package/dist/src/telegram/forwarder.js +15 -7
- package/dist/src/telegram/forwarder.js.map +1 -1
- package/dist/src/telegram/rich-message.js +209 -24
- package/dist/src/telegram/rich-message.js.map +1 -1
- package/dist/src/telegram/telegram-file.js +35 -4
- package/dist/src/telegram/telegram-file.js.map +1 -1
- package/dist/src/telegram/voice.js +4 -3
- package/dist/src/telegram/voice.js.map +1 -1
- package/package.json +5 -1
- package/public/assets/providers/slack.svg +1 -0
- package/public/dist/assets/ChannelsDiscord-D9FLnZso.js +1 -0
- package/public/dist/assets/ChannelsSlack-ybvupgdK.js +1 -0
- package/public/dist/assets/ChannelsTelegram-BOCOPrBc.js +1 -0
- package/public/dist/assets/HealthBadge-megTlF4n.js +1 -0
- package/public/dist/assets/TransportStatusChips-CjEySMis.js +1 -0
- package/public/dist/assets/app-BGIAy4he.js +55 -0
- package/public/dist/assets/{bgtask-badge-CdBqBy1L.js → bgtask-badge-DXca8E7c.js} +1 -1
- package/public/dist/assets/bgtask-badge-GRSiNILQ.js +1 -0
- package/public/dist/assets/{employees-C8qufeJl.js → employees-BL4qMxJj.js} +1 -1
- package/public/dist/assets/iframe-renderer-BUSk0Rw9.js +1 -0
- package/public/dist/assets/{iframe-renderer-CZ67aeTO.js → iframe-renderer-DUI0LYBy.js} +2 -2
- package/public/dist/assets/{manager-CLXT60M5.js → manager-B-gpf-3j.js} +3 -3
- package/public/dist/assets/{memory-lWramLVw.js → memory-B_Y0L0KD.js} +1 -1
- package/public/dist/assets/memory-CX6YahTc.js +1 -0
- package/public/dist/assets/message-history-Det7u76S.js +1 -0
- package/public/dist/assets/{message-history-2NUN3UxM.js → message-history-Dl8dJzez.js} +1 -1
- package/public/dist/assets/{provider-icons-stsNmQKx.js → provider-icons-VDfahiUp.js} +3 -2
- package/public/dist/assets/{render-CsF-ojLe.js → render-BI1aqKoc.js} +1 -1
- package/public/dist/assets/{settings-BMLowRCh.js → settings-B0Sj4sUH.js} +1 -1
- package/public/dist/assets/settings-C7NutP6X.js +1 -0
- package/public/dist/assets/settings-core-CyX-px6_.js +100 -0
- package/public/dist/assets/settings-core-DVpFmrhY.js +1 -0
- package/public/dist/assets/{sidebar-gKjYLv49.js → sidebar-DOR9fTgN.js} +3 -3
- package/public/dist/assets/skills-BWhKreQ2.js +1 -0
- package/public/dist/assets/{skills-CKTbomdm.js → skills-wt0fkV9Y.js} +1 -1
- package/public/dist/assets/slash-commands-BZbqTg3v.js +20 -0
- package/public/dist/assets/slash-commands-Di4NDA4w.js +1 -0
- package/public/dist/assets/{trace-drawer-C3G4mmB1.js → trace-drawer-kMYzaVFW.js} +1 -1
- package/public/dist/assets/ui-BghexWrB.js +1 -0
- package/public/dist/assets/{ui-CVVC_flX.js → ui-D4D5HUfo.js} +1 -1
- package/public/dist/index.html +62 -1
- package/public/dist/manager/index.html +1 -1
- package/public/index.html +61 -0
- package/public/js/features/command-info.ts +1 -0
- package/public/js/features/help-content.ts +8 -0
- package/public/js/features/settings-channel.ts +5 -1
- package/public/js/features/settings-core.ts +2 -0
- package/public/js/features/settings-slack.ts +74 -0
- package/public/js/features/settings-types.ts +5 -1
- package/public/js/features/settings.ts +1 -0
- package/public/js/features/transport-status-row.ts +15 -3
- package/public/js/main.ts +19 -0
- package/public/js/provider-icons.ts +4 -1
- package/public/js/ws.ts +1 -1
- package/public/locales/en.json +21 -0
- package/public/locales/ja.json +21 -0
- package/public/locales/ko.json +21 -0
- package/public/locales/zh.json +21 -0
- package/public/manager/src/settings/SettingsShell.tsx +1 -0
- package/public/manager/src/settings/SettingsSidebar.tsx +1 -0
- package/public/manager/src/settings/pages/ChannelsSlack.tsx +323 -0
- package/public/manager/src/settings/pages/components/ActiveChannelToggle.tsx +2 -1
- package/public/manager/src/settings/pages/components/TransportStatusChips.tsx +13 -4
- package/public/manager/src/settings/types.ts +1 -0
- package/scripts/check-redaction-sinks.mjs +276 -0
- package/scripts/pi-rpc-probe.mts +361 -0
- package/scripts/release-gates.mjs +83 -0
- package/scripts/release-preview.sh +8 -1
- package/scripts/release.sh +13 -2
- package/scripts/sync-electron-version.cjs +93 -0
- package/public/dist/assets/ChannelsDiscord-Bt1_rtNC.js +0 -1
- package/public/dist/assets/ChannelsTelegram-BLV0m1oq.js +0 -1
- package/public/dist/assets/TransportStatusChips-Bld0yXi7.js +0 -1
- package/public/dist/assets/app-iSJhsP20.js +0 -55
- package/public/dist/assets/bgtask-badge-CSkSsoB6.js +0 -1
- package/public/dist/assets/iframe-renderer-DXdo0YXN.js +0 -1
- package/public/dist/assets/memory-DeKUlD2M.js +0 -1
- package/public/dist/assets/message-history-CWTQ2woA.js +0 -1
- package/public/dist/assets/settings-CDjs7hTT.js +0 -1
- package/public/dist/assets/settings-core-Cs_oq-b3.js +0 -99
- package/public/dist/assets/settings-core-D-TOh1a6.js +0 -1
- package/public/dist/assets/skills-GuIfNASs.js +0 -1
- package/public/dist/assets/slash-commands-BtZa093n.js +0 -20
- package/public/dist/assets/slash-commands-DGJKfpMT.js +0 -1
- package/public/dist/assets/ui-DJg5Q_NJ.js +0 -1
- /package/public/dist/assets/{DashboardMeta-B7CVqXcU.js → DashboardMeta-DennaaA_.js} +0 -0
- /package/public/dist/assets/{Display-BF-rACK6.js → Display-hGuSn_W5.js} +0 -0
- /package/public/dist/assets/{Employees-D3hnciP0.js → Employees-B5YXk5ma.js} +0 -0
- /package/public/dist/assets/{Heartbeat-D4Pn5O3O.js → Heartbeat-vDGhPfct.js} +0 -0
- /package/public/dist/assets/{Mcp-SfytKWGX.js → Mcp-BHWnJ6SP.js} +0 -0
- /package/public/dist/assets/{Memory-DNxBOQ7N.js → Memory-B_UZ-iCA.js} +0 -0
- /package/public/dist/assets/{ModelProvider-CXwtlG7l.js → ModelProvider-CgUvs6pE.js} +0 -0
- /package/public/dist/assets/{Network-DISUhige.js → Network-AWpSkALD.js} +0 -0
- /package/public/dist/assets/{Profile-B8yBO3Ju.js → Profile-DnIE2ios.js} +0 -0
- /package/public/dist/assets/{Prompts-5lNQ5qOm.js → Prompts-B9aKLall.js} +0 -0
- /package/public/dist/assets/{SpeechKeys-BepaIHBa.js → SpeechKeys-K4Be_o7z.js} +0 -0
- /package/public/dist/assets/{TelegramHub--DNjRAwW.js → TelegramHub-CFwSkzHP.js} +0 -0
- /package/public/dist/assets/{TerminalPanel-DQovYfwz.js → TerminalPanel-CdlFZHAK.js} +0 -0
package/dist/src/agent/spawn.js
CHANGED
|
@@ -209,6 +209,9 @@ export const { messageQueue, enqueueMessage, removeQueuedMessage, processQueue,
|
|
|
209
209
|
let mainSpawnStarting = false;
|
|
210
210
|
let cancelPendingMainSpawn = null;
|
|
211
211
|
let steerInProgress = false;
|
|
212
|
+
let cancelActiveCodexAppTurn = null;
|
|
213
|
+
let cancelActivePiTurn = null;
|
|
214
|
+
const piProfileFingerprintKey = crypto.randomBytes(32);
|
|
212
215
|
export function setSteerInProgress(v) {
|
|
213
216
|
const was = steerInProgress;
|
|
214
217
|
steerInProgress = v;
|
|
@@ -230,6 +233,12 @@ const DEFAULT_STEER_WAIT_MS = 3_000;
|
|
|
230
233
|
const DEFAULT_KILL_ESCALATION_MS = 2_000;
|
|
231
234
|
const CLAUDE_E_STEER_WAIT_MS = 30_000;
|
|
232
235
|
const CLAUDE_E_STEER_KILL_ESCALATION_MS = 8_000;
|
|
236
|
+
const DEFAULT_CODEX_APP_TURN_IDLE_MS = 300_000;
|
|
237
|
+
const DEFAULT_CODEX_APP_TURN_ABS_MS = 2 * 60 * 60_000;
|
|
238
|
+
function configuredPositiveMs(value, fallback) {
|
|
239
|
+
const parsed = Number(value);
|
|
240
|
+
return Number.isFinite(parsed) && parsed > 0 ? parsed : fallback;
|
|
241
|
+
}
|
|
233
242
|
function getActiveMainCli() {
|
|
234
243
|
return typeof currentMainMeta?.cli === 'string' ? currentMainMeta.cli : null;
|
|
235
244
|
}
|
|
@@ -310,6 +319,24 @@ export function killActiveAgent(reason = 'user') {
|
|
|
310
319
|
queueCtrl.purgeQueueOnStop(reason);
|
|
311
320
|
clearWorkerSlotsOnStop(reason);
|
|
312
321
|
}
|
|
322
|
+
if (cancelActiveCodexAppTurn && getActiveMainCli() === 'codex-app') {
|
|
323
|
+
if (activeProcess?.pid)
|
|
324
|
+
killReasons.set(activeProcess.pid, reason);
|
|
325
|
+
console.log(`[jaw:kill] reason=${reason} cli=codex-app action=lease.cancel`);
|
|
326
|
+
cancelActiveCodexAppTurn(reason);
|
|
327
|
+
if (reason === 'api' || reason === 'user' || reason === 'steer')
|
|
328
|
+
activeProcess = null;
|
|
329
|
+
return true;
|
|
330
|
+
}
|
|
331
|
+
if (cancelActivePiTurn && getActiveMainCli() === 'pi') {
|
|
332
|
+
if (activeProcess?.pid)
|
|
333
|
+
killReasons.set(activeProcess.pid, reason);
|
|
334
|
+
console.log(`[jaw:kill] reason=${reason} cli=pi action=lease.cancel`);
|
|
335
|
+
cancelActivePiTurn(reason);
|
|
336
|
+
if (reason === 'api' || reason === 'user' || reason === 'steer')
|
|
337
|
+
activeProcess = null;
|
|
338
|
+
return true;
|
|
339
|
+
}
|
|
313
340
|
if (!activeProcess)
|
|
314
341
|
return hadTimer || cancelledPendingMain || abortedInProcess; // timer/gated spawn/jwc abort 취소도 "killed" 취급
|
|
315
342
|
const policy = getKillPolicy(reason);
|
|
@@ -560,7 +587,9 @@ export const saveUpload = (buffer, originalName, options) => _saveUpload(UPLOADS
|
|
|
560
587
|
export { buildMediaPrompt, buildMediaPromptMany };
|
|
561
588
|
// ─── Spawn Agent ─────────────────────────────────────
|
|
562
589
|
import { AcpClient } from '../cli/acp-client.js';
|
|
563
|
-
import { CodexAppClient } from './codex-app-client.js';
|
|
590
|
+
import { CodexAppClient, isRecoverableResumeError } from './codex-app-client.js';
|
|
591
|
+
import { acquireCodexAppRuntime, acquirePiRuntime } from './runtime-pool.js';
|
|
592
|
+
import { loadCatalogEfforts, resolveCatalogPath, validateModelEffort } from './codex-app-catalog.js';
|
|
564
593
|
import { extractFromCodexAppEvent } from './codex-app-events.js';
|
|
565
594
|
import { canGuardedAgyResume, resolveAgyNativeResume, shouldEmitHeartbeat, shouldResumeBucketSession } from './spawn/resume.js';
|
|
566
595
|
export { canGuardedAgyResume, resolveAgyNativeResume, shouldEmitHeartbeat, shouldResumeBucketSession };
|
|
@@ -1079,6 +1108,8 @@ export function spawnAgent(prompt, opts = {}) {
|
|
|
1079
1108
|
}
|
|
1080
1109
|
if (!opts.internal)
|
|
1081
1110
|
broadcast('agent_status', { status: 'running', cli, agentId: agentLabel, ...empTag }, traceAudience);
|
|
1111
|
+
if (mainManaged && !opts.internal)
|
|
1112
|
+
beginLiveRun(liveScope, cli);
|
|
1082
1113
|
const traceRunId = startTraceRun({ cli, model, workingDir: settings["workingDir"] || null, agentLabel, audience: traceAudience });
|
|
1083
1114
|
if (mainManaged && !opts.internal)
|
|
1084
1115
|
setLiveRunTraceId(liveScope, traceRunId);
|
|
@@ -1383,174 +1414,207 @@ export function spawnAgent(prompt, opts = {}) {
|
|
|
1383
1414
|
'Capitalized variants (Read, Bash, Edit, Write, Grep, Find, Ls) do NOT exist and will fail.',
|
|
1384
1415
|
].join('\n');
|
|
1385
1416
|
const piSysPrompt = sysPrompt ? `${sysPrompt}\n\n${piToolDiscipline}` : piToolDiscipline;
|
|
1386
|
-
const
|
|
1387
|
-
|
|
1388
|
-
|
|
1389
|
-
|
|
1390
|
-
|
|
1391
|
-
|
|
1392
|
-
|
|
1393
|
-
|
|
1394
|
-
|
|
1395
|
-
if (
|
|
1396
|
-
ctx.thinkingBuf = (ctx.thinkingBuf || '') + event.text;
|
|
1397
|
-
return;
|
|
1398
|
-
}
|
|
1399
|
-
if (event.kind === 'text') {
|
|
1400
|
-
flushPiThinking();
|
|
1401
|
-
const delta = String(event.text || '');
|
|
1402
|
-
if (!delta)
|
|
1403
|
-
return;
|
|
1404
|
-
ctx.fullText += delta;
|
|
1405
|
-
const displayDelta = normalizeAssistantDisplayText(delta);
|
|
1406
|
-
if (ctx.liveOutputText !== undefined)
|
|
1407
|
-
ctx.liveOutputText += displayDelta;
|
|
1408
|
-
if (!ctx.outputTextStarted)
|
|
1409
|
-
ctx.outputTextStarted = true;
|
|
1410
|
-
broadcastAgentOutput(ctx, agentLabel, cli, displayDelta, empTag, traceAudience);
|
|
1411
|
-
return;
|
|
1412
|
-
}
|
|
1413
|
-
if (event.kind === 'tool') {
|
|
1414
|
-
flushPiThinking();
|
|
1415
|
-
const tool = stripUndefined({ icon: '🔧', label: event.label, status: event.status, detail: event.detail, toolType: 'tool' });
|
|
1416
|
-
stampTraceTool(tool, ctx, 'tool');
|
|
1417
|
-
ctx.toolLog.push(tool);
|
|
1418
|
-
if (ctx.liveScope)
|
|
1419
|
-
replaceLiveRunTools(ctx.liveScope, ctx.toolLog);
|
|
1420
|
-
appendParentLiveRunTool(ctx, tool);
|
|
1421
|
-
emitAgentTool(ctx, agentLabel, tool, empTag);
|
|
1417
|
+
const onPiEvent = (event) => {
|
|
1418
|
+
opts.lifecycle?.onActivity?.('pi-rpc');
|
|
1419
|
+
if (event.kind === 'thinking') {
|
|
1420
|
+
ctx.thinkingBuf = (ctx.thinkingBuf || '') + event.text;
|
|
1421
|
+
return;
|
|
1422
|
+
}
|
|
1423
|
+
if (event.kind === 'text') {
|
|
1424
|
+
flushPiThinking();
|
|
1425
|
+
const delta = String(event.text || '');
|
|
1426
|
+
if (!delta)
|
|
1422
1427
|
return;
|
|
1423
|
-
|
|
1424
|
-
|
|
1425
|
-
|
|
1426
|
-
|
|
1427
|
-
|
|
1428
|
-
|
|
1429
|
-
|
|
1430
|
-
|
|
1431
|
-
ctx.stallReason = reason;
|
|
1432
|
-
if (child.pid) {
|
|
1433
|
-
killProcessTree(child.pid, 'SIGTERM');
|
|
1434
|
-
const pid = child.pid;
|
|
1435
|
-
setTimeout(() => {
|
|
1436
|
-
try {
|
|
1437
|
-
killProcessTree(pid, 'SIGKILL');
|
|
1438
|
-
}
|
|
1439
|
-
catch { /* already dead */ }
|
|
1440
|
-
}, 5_000);
|
|
1428
|
+
ctx.fullText += delta;
|
|
1429
|
+
const displayDelta = normalizeAssistantDisplayText(delta);
|
|
1430
|
+
if (ctx.liveOutputText !== undefined)
|
|
1431
|
+
ctx.liveOutputText += displayDelta;
|
|
1432
|
+
if (!ctx.outputTextStarted)
|
|
1433
|
+
ctx.outputTextStarted = true;
|
|
1434
|
+
broadcastAgentOutput(ctx, agentLabel, cli, displayDelta, empTag, traceAudience);
|
|
1435
|
+
return;
|
|
1441
1436
|
}
|
|
1442
|
-
|
|
1443
|
-
|
|
1444
|
-
|
|
1445
|
-
|
|
1446
|
-
|
|
1447
|
-
|
|
1448
|
-
|
|
1449
|
-
|
|
1450
|
-
|
|
1451
|
-
|
|
1452
|
-
|
|
1453
|
-
|
|
1454
|
-
|
|
1455
|
-
}
|
|
1456
|
-
|
|
1457
|
-
|
|
1458
|
-
|
|
1459
|
-
|
|
1460
|
-
|
|
1461
|
-
|
|
1462
|
-
|
|
1463
|
-
|
|
1464
|
-
|
|
1465
|
-
|
|
1466
|
-
|
|
1467
|
-
|
|
1468
|
-
|
|
1469
|
-
|
|
1470
|
-
|
|
1471
|
-
|
|
1472
|
-
|
|
1473
|
-
|
|
1474
|
-
|
|
1475
|
-
|
|
1476
|
-
|
|
1477
|
-
|
|
1478
|
-
|
|
1479
|
-
|
|
1480
|
-
|
|
1481
|
-
|
|
1482
|
-
|
|
1483
|
-
|
|
1484
|
-
fallbackMaxRetries: FALLBACK_MAX_RETRIES,
|
|
1485
|
-
processQueue,
|
|
1437
|
+
if (event.kind === 'tool') {
|
|
1438
|
+
flushPiThinking();
|
|
1439
|
+
const tool = stripUndefined({ icon: '🔧', label: event.label, status: event.status, detail: event.detail, toolType: 'tool' });
|
|
1440
|
+
stampTraceTool(tool, ctx, 'tool');
|
|
1441
|
+
ctx.toolLog.push(tool);
|
|
1442
|
+
if (ctx.liveScope)
|
|
1443
|
+
replaceLiveRunTools(ctx.liveScope, ctx.toolLog);
|
|
1444
|
+
appendParentLiveRunTool(ctx, tool);
|
|
1445
|
+
emitAgentTool(ctx, agentLabel, tool, empTag);
|
|
1446
|
+
return;
|
|
1447
|
+
}
|
|
1448
|
+
if (event.kind === 'session')
|
|
1449
|
+
ctx.sessionId = event.sessionId;
|
|
1450
|
+
};
|
|
1451
|
+
const runPiTurn = (child, done, lease) => {
|
|
1452
|
+
let leaseCancel = null;
|
|
1453
|
+
const requestCancel = () => {
|
|
1454
|
+
if (!lease) {
|
|
1455
|
+
if (child.pid) {
|
|
1456
|
+
const pid = child.pid;
|
|
1457
|
+
killProcessTree(pid, 'SIGTERM');
|
|
1458
|
+
setTimeout(() => {
|
|
1459
|
+
try {
|
|
1460
|
+
killProcessTree(pid, 'SIGKILL');
|
|
1461
|
+
}
|
|
1462
|
+
catch { /* already dead */ }
|
|
1463
|
+
}, 5_000);
|
|
1464
|
+
}
|
|
1465
|
+
else
|
|
1466
|
+
child.kill('SIGTERM');
|
|
1467
|
+
return Promise.resolve();
|
|
1468
|
+
}
|
|
1469
|
+
leaseCancel ??= lease.cancel();
|
|
1470
|
+
return leaseCancel;
|
|
1471
|
+
};
|
|
1472
|
+
const cancelHook = (_reason) => { void requestCancel(); };
|
|
1473
|
+
if (lease)
|
|
1474
|
+
cancelActivePiTurn = cancelHook;
|
|
1475
|
+
const piWatchdog = attachWatchdog(child, agentLabel, (reason) => {
|
|
1476
|
+
console.log(`[jaw:watchdog] cancelling ${agentLabel} (pi) — ${reason}`);
|
|
1477
|
+
ctx.stallReason = reason;
|
|
1478
|
+
void requestCancel();
|
|
1486
1479
|
});
|
|
1487
|
-
|
|
1488
|
-
|
|
1489
|
-
|
|
1490
|
-
|
|
1491
|
-
|
|
1492
|
-
|
|
1493
|
-
|
|
1494
|
-
|
|
1495
|
-
|
|
1496
|
-
|
|
1497
|
-
|
|
1498
|
-
|
|
1499
|
-
|
|
1500
|
-
|
|
1501
|
-
|
|
1502
|
-
|
|
1503
|
-
|
|
1504
|
-
|
|
1505
|
-
|
|
1506
|
-
|
|
1480
|
+
ctx.stallWatchdog = piWatchdog;
|
|
1481
|
+
if (mainManaged)
|
|
1482
|
+
activeProcess = child;
|
|
1483
|
+
registerActiveProcess(agentLabel, child);
|
|
1484
|
+
if (!opts.internal)
|
|
1485
|
+
broadcast('agent_status', { running: true, agentId: agentLabel, cli, provider: profile.id, ...empTag });
|
|
1486
|
+
if (mainManaged && !opts.internal) {
|
|
1487
|
+
beginLiveRun(liveScope, cli);
|
|
1488
|
+
setLiveRunTraceId(liveScope, traceRunId);
|
|
1489
|
+
}
|
|
1490
|
+
if (mainManaged && !opts.internal && !opts._skipInsert) {
|
|
1491
|
+
insertMessage.run('user', prompt, cli, runtimeModel, settings["workingDir"] || null, getActiveChatSession());
|
|
1492
|
+
}
|
|
1493
|
+
if (!opts.internal)
|
|
1494
|
+
broadcast('agent_status', { status: 'running', cli, agentId: agentLabel, provider: profile.id, ...empTag }, traceAudience);
|
|
1495
|
+
const releaseLease = async () => {
|
|
1496
|
+
if (leaseCancel)
|
|
1497
|
+
await leaseCancel;
|
|
1498
|
+
if (cancelActivePiTurn === cancelHook)
|
|
1499
|
+
cancelActivePiTurn = null;
|
|
1500
|
+
if (lease)
|
|
1501
|
+
lease.release();
|
|
1502
|
+
else
|
|
1503
|
+
cleanupEmployeeTmpDir(spawnCwd, settings["workingDir"], agentLabel);
|
|
1504
|
+
};
|
|
1505
|
+
done.then(async (result) => {
|
|
1506
|
+
piWatchdog.stop();
|
|
1507
|
+
await releaseLease();
|
|
1508
|
+
flushPiThinking();
|
|
1509
|
+
if (ctx.stderrBuf.length < 4000)
|
|
1510
|
+
ctx.stderrBuf += result.stderr || '';
|
|
1511
|
+
if (result.sessionId)
|
|
1512
|
+
ctx.sessionId = result.sessionId;
|
|
1513
|
+
if (!ctx.fullText && result.text)
|
|
1514
|
+
ctx.fullText = result.text;
|
|
1515
|
+
opts.lifecycle?.onExit?.(result.code);
|
|
1516
|
+
const killReason = consumeKillReason(child.pid);
|
|
1517
|
+
const wasKilled = !!killReason;
|
|
1518
|
+
const wasSteer = killReason === 'steer';
|
|
1519
|
+
const smokeResult = detectSmokeResponse(ctx.fullText, ctx.toolLog, result.code, cli);
|
|
1520
|
+
return handleAgentExit({
|
|
1521
|
+
ctx, code: result.code, cli, model: runtimeModel, effectiveProvider: profile.id, agentLabel, mainManaged, origin,
|
|
1522
|
+
resumeKey,
|
|
1523
|
+
prompt, opts, cfg, ownerGeneration, forceNew, empSid,
|
|
1524
|
+
isResume: false, wasKilled, wasSteer, smokeResult,
|
|
1525
|
+
effortDefault: 'medium', costLine: '',
|
|
1526
|
+
resolve: resolve,
|
|
1527
|
+
activeProcesses,
|
|
1528
|
+
setActiveProcess: (v) => { activeProcess = v; },
|
|
1529
|
+
retryState: queueCtrl.retryState,
|
|
1530
|
+
fallbackState: queueCtrl.fallbackState,
|
|
1531
|
+
fallbackMaxRetries: FALLBACK_MAX_RETRIES,
|
|
1532
|
+
processQueue,
|
|
1533
|
+
});
|
|
1534
|
+
}).catch(async (err) => {
|
|
1535
|
+
piWatchdog.stop();
|
|
1536
|
+
await releaseLease().catch(() => { });
|
|
1537
|
+
if (ctx.stderrBuf.length < 4000)
|
|
1538
|
+
ctx.stderrBuf += err.message;
|
|
1539
|
+
console.error('[jaw:pi] runtime failed:', err.message);
|
|
1540
|
+
handleAgentExit({
|
|
1541
|
+
ctx, code: 1, cli, model: runtimeModel, effectiveProvider: profile.id, agentLabel, mainManaged, origin,
|
|
1542
|
+
resumeKey,
|
|
1543
|
+
prompt, opts, cfg, ownerGeneration, forceNew, empSid,
|
|
1544
|
+
isResume: false, wasKilled: false, wasSteer: false, smokeResult: detectSmokeResponse('', [], 1, cli),
|
|
1545
|
+
effortDefault: 'medium', costLine: '',
|
|
1546
|
+
resolve: resolve,
|
|
1547
|
+
activeProcesses,
|
|
1548
|
+
setActiveProcess: (v) => { activeProcess = v; },
|
|
1549
|
+
retryState: queueCtrl.retryState,
|
|
1550
|
+
fallbackState: queueCtrl.fallbackState,
|
|
1551
|
+
fallbackMaxRetries: FALLBACK_MAX_RETRIES,
|
|
1552
|
+
processQueue,
|
|
1553
|
+
}).catch((handleErr) => {
|
|
1554
|
+
console.error('[jaw:lifecycle] handleAgentExit failed (Pi):', handleErr.message);
|
|
1555
|
+
});
|
|
1507
1556
|
});
|
|
1557
|
+
};
|
|
1558
|
+
if (opts.agentId) {
|
|
1559
|
+
const { child, done } = spawnPiRpc(profile, pi, {
|
|
1560
|
+
prompt: piPrompt,
|
|
1561
|
+
model: runtimeModel,
|
|
1562
|
+
...(piSessionId ? { sessionId: piSessionId } : {}),
|
|
1563
|
+
effort,
|
|
1564
|
+
cwd: spawnCwd,
|
|
1565
|
+
sysPrompt: piSysPrompt,
|
|
1566
|
+
onEvent: onPiEvent,
|
|
1567
|
+
});
|
|
1568
|
+
runPiTurn(child, done, null);
|
|
1569
|
+
return { child, promise: resultPromise };
|
|
1570
|
+
}
|
|
1571
|
+
const profileFp = crypto.createHmac('sha256', piProfileFingerprintKey)
|
|
1572
|
+
.update(profile.apiKey || '')
|
|
1573
|
+
.digest('hex')
|
|
1574
|
+
.slice(0, 12);
|
|
1575
|
+
mainSpawnStarting = true;
|
|
1576
|
+
void acquirePiRuntime({
|
|
1577
|
+
key: {
|
|
1578
|
+
scopeKey: `chat:${getActiveChatSession()}`,
|
|
1579
|
+
cwd: spawnCwd,
|
|
1580
|
+
profileId: profile.id,
|
|
1581
|
+
fullEndpoint: profile.endpoint,
|
|
1582
|
+
apiKind: profile.apiKind,
|
|
1583
|
+
model: runtimeModel,
|
|
1584
|
+
effort,
|
|
1585
|
+
profileFp,
|
|
1586
|
+
},
|
|
1587
|
+
piSettings: pi,
|
|
1588
|
+
storedSessionId: piSessionId || null,
|
|
1589
|
+
instructions: piSysPrompt,
|
|
1590
|
+
forceNew,
|
|
1591
|
+
}).then((lease) => {
|
|
1592
|
+
mainSpawnStarting = false;
|
|
1593
|
+
ctx.sessionId = lease.session.sessionId;
|
|
1594
|
+
console.log(`[jaw:pi:pool] reused=${lease.reused} sessionId=${lease.session.sessionId || 'new'}`);
|
|
1595
|
+
const done = lease.session.sendPrompt(piPrompt, { effort, onEvent: onPiEvent })
|
|
1596
|
+
.then((result) => ({ ...result, code: 0, sessionId: lease.session.sessionId }));
|
|
1597
|
+
runPiTurn(lease.session.child, done, lease);
|
|
1598
|
+
}).catch((err) => {
|
|
1599
|
+
mainSpawnStarting = false;
|
|
1600
|
+
console.error(`[jaw:pi:pool] acquire failed: ${err.message}`);
|
|
1601
|
+
clearLiveRun(liveScope);
|
|
1602
|
+
broadcast('agent_status', { running: false, agentId: agentLabel });
|
|
1603
|
+
broadcast('agent_done', { text: `❌ Pi RPC acquire failed: ${err.message}`, error: true, origin }, 'public');
|
|
1604
|
+
resolve({ text: '', code: 1 });
|
|
1605
|
+
processQueue();
|
|
1508
1606
|
});
|
|
1509
|
-
return { child, promise: resultPromise };
|
|
1607
|
+
return { child: null, promise: resultPromise };
|
|
1510
1608
|
}
|
|
1511
1609
|
// ─── Codex AppServer branch ────────────────────
|
|
1512
1610
|
if (cli === 'codex-app') {
|
|
1513
|
-
const
|
|
1514
|
-
|
|
1515
|
-
|
|
1516
|
-
|
|
1517
|
-
|
|
1518
|
-
effort,
|
|
1519
|
-
fastMode: cfg.fastMode ?? settings["perCli"]?.["codex"]?.fastMode,
|
|
1520
|
-
});
|
|
1521
|
-
appClient.spawn();
|
|
1522
|
-
const child = appClient.proc;
|
|
1523
|
-
if (!child) {
|
|
1524
|
-
throw new Error('Codex AppServer process was not created');
|
|
1525
|
-
}
|
|
1526
|
-
if (mainManaged)
|
|
1527
|
-
activeProcess = child;
|
|
1528
|
-
registerActiveProcess(agentLabel, child);
|
|
1529
|
-
if (!opts.internal)
|
|
1530
|
-
broadcast('agent_status', { running: true, agentId: agentLabel, cli, ...empTag });
|
|
1531
|
-
if (mainManaged && !opts.internal)
|
|
1532
|
-
beginLiveRun(liveScope, cli);
|
|
1533
|
-
let codexAppSettled = false;
|
|
1534
|
-
appClient.on('error', (err) => {
|
|
1535
|
-
if (codexAppSettled)
|
|
1536
|
-
return;
|
|
1537
|
-
codexAppSettled = true;
|
|
1538
|
-
appClient.cleanup();
|
|
1539
|
-
cleanupEmployeeTmpDir(spawnCwd, settings["workingDir"], agentLabel);
|
|
1540
|
-
opts.lifecycle?.onExit?.(null);
|
|
1541
|
-
const msg = `Codex AppServer spawn failed: ${err.message}`;
|
|
1542
|
-
console.error(`[codex-app:error] ${msg}`);
|
|
1543
|
-
activeProcesses.delete(agentLabel);
|
|
1544
|
-
if (mainManaged) {
|
|
1545
|
-
activeProcess = null;
|
|
1546
|
-
clearLiveRun(liveScope);
|
|
1547
|
-
broadcast('agent_status', { running: false, agentId: agentLabel });
|
|
1611
|
+
const catalogPath = resolveCatalogPath();
|
|
1612
|
+
if (catalogPath) {
|
|
1613
|
+
const verdict = validateModelEffort(model, effort, loadCatalogEfforts(catalogPath));
|
|
1614
|
+
if (!verdict.ok) {
|
|
1615
|
+
throw new Error(`[codex-app] ${verdict.error}`);
|
|
1548
1616
|
}
|
|
1549
|
-
|
|
1550
|
-
resolve({ text: '', code: 1 });
|
|
1551
|
-
if (mainManaged)
|
|
1552
|
-
processQueue();
|
|
1553
|
-
});
|
|
1617
|
+
}
|
|
1554
1618
|
if (mainManaged && !opts.internal && !opts._skipInsert) {
|
|
1555
1619
|
insertMessage.run('user', prompt, cli, model, settings["workingDir"] || null, getActiveChatSession());
|
|
1556
1620
|
}
|
|
@@ -1590,14 +1654,27 @@ export function spawnAgent(prompt, opts = {}) {
|
|
|
1590
1654
|
}
|
|
1591
1655
|
let lastVisibleBroadcastTs = Date.now();
|
|
1592
1656
|
let heartbeatSent = false;
|
|
1593
|
-
|
|
1657
|
+
let turnCompleted = false;
|
|
1658
|
+
let turnReportedFailure = false;
|
|
1659
|
+
let markCodexProgress = () => { };
|
|
1660
|
+
let settleTurn;
|
|
1661
|
+
let rejectTurn;
|
|
1662
|
+
const turnDone = new Promise((resolveTurn, rejectTurnPromise) => {
|
|
1663
|
+
settleTurn = resolveTurn;
|
|
1664
|
+
rejectTurn = rejectTurnPromise;
|
|
1665
|
+
});
|
|
1666
|
+
const handleNotification = (method, params) => {
|
|
1667
|
+
markCodexProgress();
|
|
1594
1668
|
if (method === 'turn/completed' || method === 'turn/started' || method === 'error') {
|
|
1595
1669
|
console.log(`[codex-app:notify] ${method}`);
|
|
1596
1670
|
}
|
|
1597
1671
|
appendTraceEvent({ runId: ctx.traceRunId, source: 'codex_app_raw', eventType: method, raw: params });
|
|
1598
1672
|
const parsed = extractFromCodexAppEvent(method, params, ctx);
|
|
1599
|
-
if (!parsed)
|
|
1673
|
+
if (!parsed) {
|
|
1674
|
+
if (method === 'turn/completed')
|
|
1675
|
+
settleTurn();
|
|
1600
1676
|
return;
|
|
1677
|
+
}
|
|
1601
1678
|
if (parsed.flushThinking) {
|
|
1602
1679
|
flushCodexAppThinking();
|
|
1603
1680
|
}
|
|
@@ -1638,11 +1715,13 @@ export function spawnAgent(prompt, opts = {}) {
|
|
|
1638
1715
|
}
|
|
1639
1716
|
if (parsed.turnStatus && parsed.turnStatus !== 'completed') {
|
|
1640
1717
|
console.warn(`[codex-app:turn] final status: ${parsed.turnStatus}`);
|
|
1641
|
-
|
|
1718
|
+
turnReportedFailure = true;
|
|
1642
1719
|
}
|
|
1643
1720
|
opts.lifecycle?.onActivity?.('codex-app');
|
|
1644
|
-
|
|
1645
|
-
|
|
1721
|
+
if (method === 'turn/completed')
|
|
1722
|
+
settleTurn();
|
|
1723
|
+
};
|
|
1724
|
+
const handleStderr = (text) => {
|
|
1646
1725
|
appendTraceEvent({ runId: ctx.traceRunId, source: 'stderr', eventType: 'stderr', raw: text });
|
|
1647
1726
|
if (ctx.stderrBuf.length < 4000) {
|
|
1648
1727
|
ctx.stderrBuf += text + '\n';
|
|
@@ -1657,51 +1736,103 @@ export function spawnAgent(prompt, opts = {}) {
|
|
|
1657
1736
|
label: 'working... (no visible progress)',
|
|
1658
1737
|
}, empTag);
|
|
1659
1738
|
}
|
|
1660
|
-
}
|
|
1661
|
-
|
|
1662
|
-
|
|
1739
|
+
};
|
|
1740
|
+
const effectiveFastMode = cfg.fastMode ?? settings["perCli"]?.["codex"]?.fastMode ?? false;
|
|
1741
|
+
const runCodexAppTurn = async (appClient, lease) => {
|
|
1742
|
+
const child = appClient.proc;
|
|
1743
|
+
if (!child)
|
|
1744
|
+
throw new Error('Codex AppServer process was not created');
|
|
1745
|
+
if (mainManaged)
|
|
1746
|
+
activeProcess = child;
|
|
1747
|
+
registerActiveProcess(agentLabel, child);
|
|
1748
|
+
if (!opts.internal)
|
|
1749
|
+
broadcast('agent_status', { running: true, agentId: agentLabel, cli, ...empTag });
|
|
1750
|
+
const processExit = { value: null };
|
|
1751
|
+
const idleMs = configuredPositiveMs(process.env["CODEX_APP_TURN_IDLE_MS"], DEFAULT_CODEX_APP_TURN_IDLE_MS);
|
|
1752
|
+
const absoluteMs = configuredPositiveMs(process.env["CODEX_APP_TURN_ABS_MS"], DEFAULT_CODEX_APP_TURN_ABS_MS);
|
|
1753
|
+
let idleTimer;
|
|
1754
|
+
let absoluteTimer;
|
|
1755
|
+
let watchdogCancel = null;
|
|
1756
|
+
let leaseCancel = null;
|
|
1757
|
+
const requestLeaseCancel = () => {
|
|
1758
|
+
if (!lease) {
|
|
1759
|
+
appClient.kill();
|
|
1760
|
+
return Promise.resolve();
|
|
1761
|
+
}
|
|
1762
|
+
leaseCancel ??= lease.cancel().catch((err) => {
|
|
1763
|
+
console.warn('[codex-app:turn] cancel failed:', err.message);
|
|
1764
|
+
});
|
|
1765
|
+
return leaseCancel;
|
|
1766
|
+
};
|
|
1767
|
+
const cancelHook = (_reason) => { void requestLeaseCancel(); };
|
|
1768
|
+
if (lease)
|
|
1769
|
+
cancelActiveCodexAppTurn = cancelHook;
|
|
1770
|
+
const watchdogTimeout = (kind) => {
|
|
1771
|
+
if (watchdogCancel)
|
|
1772
|
+
return;
|
|
1773
|
+
console.warn(`[codex-app:turn] watchdog stall (${kind}, idleMs=${idleMs}, absoluteMs=${absoluteMs})`);
|
|
1774
|
+
watchdogCancel = requestLeaseCancel();
|
|
1775
|
+
rejectTurn(new Error(`Codex AppServer turn ${kind} watchdog timeout`));
|
|
1776
|
+
};
|
|
1777
|
+
const resetIdleTimer = () => {
|
|
1778
|
+
clearTimeout(idleTimer);
|
|
1779
|
+
idleTimer = setTimeout(() => { watchdogTimeout('idle'); }, idleMs);
|
|
1780
|
+
};
|
|
1781
|
+
idleTimer = setTimeout(() => { watchdogTimeout('idle'); }, idleMs);
|
|
1782
|
+
absoluteTimer = setTimeout(() => { watchdogTimeout('absolute'); }, absoluteMs);
|
|
1783
|
+
markCodexProgress = resetIdleTimer;
|
|
1784
|
+
const scope = appClient.listenTurn({
|
|
1785
|
+
onNotification: handleNotification,
|
|
1786
|
+
onStderr: handleStderr,
|
|
1787
|
+
onExit: (code, signal) => {
|
|
1788
|
+
processExit.value = { code, signal };
|
|
1789
|
+
rejectTurn(new Error(`Codex AppServer exited (code=${code}, signal=${signal})`));
|
|
1790
|
+
},
|
|
1791
|
+
onError: rejectTurn,
|
|
1792
|
+
onInterruptFailed: (err) => {
|
|
1793
|
+
console.warn(`[codex-app:interrupt] ${err.message}`);
|
|
1794
|
+
},
|
|
1795
|
+
});
|
|
1663
1796
|
try {
|
|
1664
|
-
|
|
1665
|
-
|
|
1666
|
-
console.log(
|
|
1667
|
-
|
|
1668
|
-
|
|
1669
|
-
|
|
1670
|
-
|
|
1671
|
-
|
|
1672
|
-
|
|
1673
|
-
|
|
1674
|
-
|
|
1675
|
-
|
|
1797
|
+
if (lease) {
|
|
1798
|
+
ctx.sessionId = lease.threadId;
|
|
1799
|
+
console.log(`[codex-app:pool] thread=${lease.threadId.slice(0, 12)}... reused=${lease.reused} resumed=${lease.resumedThread}`);
|
|
1800
|
+
}
|
|
1801
|
+
else {
|
|
1802
|
+
const initResult = await appClient.initialize();
|
|
1803
|
+
if (process.env["DEBUG"])
|
|
1804
|
+
console.log('[codex-app:init]', JSON.stringify(initResult).slice(0, 200));
|
|
1805
|
+
if (isResume && resumeSessionId) {
|
|
1806
|
+
try {
|
|
1807
|
+
await appClient.resumeThread(resumeSessionId, { instructions: sysPrompt });
|
|
1808
|
+
console.log(`[codex-app:session] resumeThread OK: ${resumeSessionId.slice(0, 12)}...`);
|
|
1809
|
+
}
|
|
1810
|
+
catch (resumeErr) {
|
|
1811
|
+
const message = resumeErr.message || '';
|
|
1812
|
+
if (!isRecoverableResumeError(message))
|
|
1813
|
+
throw resumeErr;
|
|
1814
|
+
console.warn(`[codex-app:session] resumeThread FAILED (recoverable): ${message} — starting new thread`);
|
|
1815
|
+
if (empSid && opts.agentId)
|
|
1816
|
+
clearEmployeeSession.run(opts.agentId);
|
|
1817
|
+
await appClient.startThread({ instructions: sysPrompt, cwd: spawnCwd });
|
|
1676
1818
|
}
|
|
1819
|
+
}
|
|
1820
|
+
else {
|
|
1677
1821
|
await appClient.startThread({ instructions: sysPrompt, cwd: spawnCwd });
|
|
1678
1822
|
}
|
|
1823
|
+
ctx.sessionId = appClient.threadId;
|
|
1679
1824
|
}
|
|
1680
|
-
|
|
1681
|
-
|
|
1682
|
-
|
|
1683
|
-
|
|
1684
|
-
const useNativeResume = isResume && Boolean(resumeSessionId);
|
|
1685
|
-
const codexAppPrompt = (!useNativeResume && historyBlock)
|
|
1825
|
+
const shouldPrependHistory = lease
|
|
1826
|
+
? !lease.resumedThread
|
|
1827
|
+
: !(isResume && Boolean(resumeSessionId));
|
|
1828
|
+
const codexAppPrompt = (shouldPrependHistory && historyBlock)
|
|
1686
1829
|
? `${historyBlock}\n\n[User Message]\n${prompt}`
|
|
1687
1830
|
: prompt;
|
|
1688
|
-
|
|
1689
|
-
|
|
1690
|
-
|
|
1691
|
-
resolveTurn();
|
|
1692
|
-
});
|
|
1693
|
-
appClient.once('error', rejectTurn);
|
|
1694
|
-
});
|
|
1695
|
-
await appClient.startTurn(codexAppPrompt);
|
|
1696
|
-
try {
|
|
1697
|
-
await turnDone;
|
|
1698
|
-
turnCompleted = true;
|
|
1699
|
-
}
|
|
1700
|
-
catch (turnErr) {
|
|
1701
|
-
console.warn(`[codex-app:turn] error during turn: ${turnErr.message}`);
|
|
1702
|
-
}
|
|
1831
|
+
await Promise.race([appClient.startTurn(codexAppPrompt), turnDone]);
|
|
1832
|
+
await turnDone;
|
|
1833
|
+
turnCompleted = !turnReportedFailure;
|
|
1703
1834
|
flushCodexAppThinking();
|
|
1704
|
-
const persistedThreadId = appClient.threadId;
|
|
1835
|
+
const persistedThreadId = lease?.threadId ?? appClient.threadId;
|
|
1705
1836
|
if (persistedThreadId && persistMainSession(stripUndefined({
|
|
1706
1837
|
ownerGeneration,
|
|
1707
1838
|
forceNew,
|
|
@@ -1716,53 +1847,43 @@ export function spawnAgent(prompt, opts = {}) {
|
|
|
1716
1847
|
}))) {
|
|
1717
1848
|
console.log(`[jaw:session] saved ${cli} session=${persistedThreadId.slice(0, 12)}... (pre-shutdown)`);
|
|
1718
1849
|
}
|
|
1719
|
-
if (!codexAppSettled) {
|
|
1720
|
-
codexAppSettled = true;
|
|
1721
|
-
const smokeResult = detectSmokeResponse(ctx.fullText, ctx.toolLog, 0, cli);
|
|
1722
|
-
handleAgentExit({
|
|
1723
|
-
ctx, code: turnCompleted ? 0 : 1, cli, model, agentLabel, mainManaged, origin,
|
|
1724
|
-
resumeKey,
|
|
1725
|
-
prompt, opts, cfg, ownerGeneration, forceNew, empSid,
|
|
1726
|
-
isResume, wasKilled: false, wasSteer: false, smokeResult,
|
|
1727
|
-
effortDefault: '', costLine: '',
|
|
1728
|
-
resolve: resolve,
|
|
1729
|
-
activeProcesses,
|
|
1730
|
-
setActiveProcess: (v) => { activeProcess = v; },
|
|
1731
|
-
retryState: queueCtrl.retryState,
|
|
1732
|
-
fallbackState: queueCtrl.fallbackState,
|
|
1733
|
-
fallbackMaxRetries: FALLBACK_MAX_RETRIES,
|
|
1734
|
-
processQueue,
|
|
1735
|
-
}).catch((err) => {
|
|
1736
|
-
console.error(`[codex-app:handleAgentExit] ${err.message}`);
|
|
1737
|
-
});
|
|
1738
|
-
}
|
|
1739
|
-
await appClient.closeGracefully();
|
|
1740
1850
|
}
|
|
1741
1851
|
catch (err) {
|
|
1742
1852
|
console.error(`[codex-app:error] ${err.message}`);
|
|
1743
1853
|
if (ctx.stderrBuf.length < 4000)
|
|
1744
1854
|
ctx.stderrBuf += err.message;
|
|
1745
|
-
|
|
1855
|
+
if (!lease)
|
|
1856
|
+
appClient.kill();
|
|
1746
1857
|
}
|
|
1747
|
-
|
|
1748
|
-
|
|
1749
|
-
|
|
1750
|
-
|
|
1751
|
-
|
|
1752
|
-
|
|
1753
|
-
|
|
1754
|
-
|
|
1755
|
-
|
|
1756
|
-
|
|
1757
|
-
|
|
1858
|
+
finally {
|
|
1859
|
+
clearTimeout(idleTimer);
|
|
1860
|
+
clearTimeout(absoluteTimer);
|
|
1861
|
+
markCodexProgress = () => { };
|
|
1862
|
+
if (watchdogCancel)
|
|
1863
|
+
await watchdogCancel;
|
|
1864
|
+
if (cancelActiveCodexAppTurn === cancelHook)
|
|
1865
|
+
cancelActiveCodexAppTurn = null;
|
|
1866
|
+
scope.dispose();
|
|
1867
|
+
if (lease)
|
|
1868
|
+
lease.release();
|
|
1869
|
+
else {
|
|
1870
|
+
await appClient.closeGracefully();
|
|
1871
|
+
appClient.cleanup();
|
|
1872
|
+
cleanupEmployeeTmpDir(spawnCwd, settings["workingDir"], agentLabel);
|
|
1873
|
+
}
|
|
1874
|
+
}
|
|
1875
|
+
const exitCode = turnCompleted ? 0 : (processExit.value?.code ?? 1);
|
|
1876
|
+
opts.lifecycle?.onExit?.(exitCode);
|
|
1877
|
+
const killReason = consumeKillReason(child.pid);
|
|
1878
|
+
if (processExit.value && processExit.value.code !== 0 && !killReason) {
|
|
1879
|
+
console.warn(`[codex-app:unexpected-exit] code=${processExit.value.code} signal=${processExit.value.signal} threadId=${ctx.sessionId || 'none'}`);
|
|
1758
1880
|
}
|
|
1759
1881
|
const wasKilled = !!killReason;
|
|
1760
1882
|
const wasSteer = killReason === 'steer';
|
|
1761
1883
|
flushCodexAppThinking();
|
|
1762
|
-
const smokeResult = detectSmokeResponse(ctx.fullText, ctx.toolLog,
|
|
1763
|
-
|
|
1764
|
-
|
|
1765
|
-
ctx, code: codexAppCode, cli, model, agentLabel, mainManaged, origin,
|
|
1884
|
+
const smokeResult = detectSmokeResponse(ctx.fullText, ctx.toolLog, exitCode, cli);
|
|
1885
|
+
await handleAgentExit({
|
|
1886
|
+
ctx, code: exitCode, cli, model, agentLabel, mainManaged, origin,
|
|
1766
1887
|
resumeKey,
|
|
1767
1888
|
prompt, opts, cfg, ownerGeneration, forceNew, empSid,
|
|
1768
1889
|
isResume, wasKilled, wasSteer, smokeResult,
|
|
@@ -1777,8 +1898,42 @@ export function spawnAgent(prompt, opts = {}) {
|
|
|
1777
1898
|
}).catch((err) => {
|
|
1778
1899
|
console.error('[jaw:lifecycle] handleAgentExit failed (codex-app):', err.message);
|
|
1779
1900
|
});
|
|
1901
|
+
};
|
|
1902
|
+
if (opts.agentId) {
|
|
1903
|
+
const appClient = new CodexAppClient({
|
|
1904
|
+
binary: detected.path || 'codex', workDir: spawnCwd, env: spawnEnv,
|
|
1905
|
+
model, effort, fastMode: effectiveFastMode,
|
|
1906
|
+
});
|
|
1907
|
+
appClient.spawn();
|
|
1908
|
+
const child = appClient.proc;
|
|
1909
|
+
if (!child)
|
|
1910
|
+
throw new Error('Codex AppServer process was not created');
|
|
1911
|
+
void runCodexAppTurn(appClient, null);
|
|
1912
|
+
return { child, promise: resultPromise };
|
|
1913
|
+
}
|
|
1914
|
+
mainSpawnStarting = true;
|
|
1915
|
+
void acquireCodexAppRuntime({
|
|
1916
|
+
binary: detected.path || 'codex', env: spawnEnv,
|
|
1917
|
+
key: {
|
|
1918
|
+
scopeKey: `chat:${getActiveChatSession()}`,
|
|
1919
|
+
cwd: spawnCwd, model, effort, fastMode: effectiveFastMode,
|
|
1920
|
+
},
|
|
1921
|
+
storedThreadId: resumeSessionId || null,
|
|
1922
|
+
instructions: sysPrompt,
|
|
1923
|
+
forceNew,
|
|
1924
|
+
}).then(async (lease) => {
|
|
1925
|
+
mainSpawnStarting = false;
|
|
1926
|
+
await runCodexAppTurn(lease.client, lease);
|
|
1927
|
+
}).catch((err) => {
|
|
1928
|
+
mainSpawnStarting = false;
|
|
1929
|
+
console.error(`[codex-app:pool] acquire failed: ${err.message}`);
|
|
1930
|
+
clearLiveRun(liveScope);
|
|
1931
|
+
broadcast('agent_status', { running: false, agentId: agentLabel });
|
|
1932
|
+
broadcast('agent_done', { text: `❌ Codex AppServer acquire failed: ${err.message}`, error: true, origin }, 'public');
|
|
1933
|
+
resolve({ text: '', code: 1 });
|
|
1934
|
+
processQueue();
|
|
1780
1935
|
});
|
|
1781
|
-
return { child, promise: resultPromise };
|
|
1936
|
+
return { child: null, promise: resultPromise };
|
|
1782
1937
|
}
|
|
1783
1938
|
// ─── Standard CLI branch (claude/codex/opencode) ──────
|
|
1784
1939
|
// DIFF-B: Windows needs shell:true only when falling back to .cmd shims.
|