@straiffi/archon 1.10.12 → 1.11.0
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 +9 -2
- package/dist/client/assets/{ActivityView-BFn_Nhj4.js → ActivityView-BvXSn9Jw.js} +1 -1
- package/dist/client/assets/{GitHubActionsDialog-iZD86Yju.js → GitHubActionsDialog-BPZg_Wy3.js} +1 -1
- package/dist/client/assets/{VerificationDialog-CqKE8t1d.js → VerificationDialog-D3mOY3z9.js} +1 -1
- package/dist/client/assets/{architectureDiagram-3BPJPVTR-C8KefY67.js → architectureDiagram-3BPJPVTR-Bj7m5nzx.js} +1 -1
- package/dist/client/assets/{blockDiagram-GPEHLZMM-BO2Q_Osr.js → blockDiagram-GPEHLZMM-Dv4SrhZg.js} +1 -1
- package/dist/client/assets/{c4Diagram-AAUBKEIU-DGPkhbrK.js → c4Diagram-AAUBKEIU-BKGsMo_n.js} +1 -1
- package/dist/client/assets/channel-DmiHuOD2.js +1 -0
- package/dist/client/assets/{chunk-2J33WTMH-Dtb7Xu8C.js → chunk-2J33WTMH-oppoEflV.js} +1 -1
- package/dist/client/assets/{chunk-3OPIFGDE-Bnf4GbOF.js → chunk-3OPIFGDE-FoeHxEDL.js} +1 -1
- package/dist/client/assets/{chunk-5ZQYHXKU-BWGid3g7.js → chunk-5ZQYHXKU-DFo7Hn8f.js} +1 -1
- package/dist/client/assets/{chunk-727SXJPM-ScA8IRGP.js → chunk-727SXJPM-BbM0ijwZ.js} +1 -1
- package/dist/client/assets/{chunk-AQP2D5EJ-Bygg04Ip.js → chunk-AQP2D5EJ-hGswj21x.js} +1 -1
- package/dist/client/assets/{chunk-CSCIHK7Q-CxdDDtfN.js → chunk-CSCIHK7Q-k3Y3HBPl.js} +1 -1
- package/dist/client/assets/{chunk-KSCS5N6A-BgpZFsB5.js → chunk-KSCS5N6A-D-fMWFHX.js} +1 -1
- package/dist/client/assets/{chunk-L5ZTLDWV-CKSew0OL.js → chunk-L5ZTLDWV-Cp8034Xo.js} +1 -1
- package/dist/client/assets/{chunk-LZXEDZCA-DVG9Rx0K.js → chunk-LZXEDZCA-DCmWwuZY.js} +2 -2
- package/dist/client/assets/{chunk-ND2GUHAM-CHBqNmuF.js → chunk-ND2GUHAM-CPxoYLrb.js} +1 -1
- package/dist/client/assets/{chunk-NZK2D7GU-DvZYWn7V.js → chunk-NZK2D7GU-B1xsQ-Ge.js} +1 -1
- package/dist/client/assets/{chunk-O5CBEL6O-BL7lRTSe.js → chunk-O5CBEL6O-CP_QLulv.js} +1 -1
- package/dist/client/assets/{chunk-WU5MYG2G-C-il2wHZ.js → chunk-WU5MYG2G-CqDmmASz.js} +1 -1
- package/dist/client/assets/classDiagram-4FO5ZUOK-GuChK9KD.js +1 -0
- package/dist/client/assets/classDiagram-v2-Q7XG4LA2-ezsQe4jc.js +1 -0
- package/dist/client/assets/{dagre-BM42HDAG-B00l5tLi.js → dagre-BM42HDAG-I60HgRr5.js} +1 -1
- package/dist/client/assets/{diagram-2AECGRRQ-Tum6g1_5.js → diagram-2AECGRRQ-DH7489lu.js} +1 -1
- package/dist/client/assets/{diagram-5GNKFQAL-BK1GX5jc.js → diagram-5GNKFQAL-UG5kJveS.js} +1 -1
- package/dist/client/assets/{diagram-KO2AKTUF-BrzmD5NB.js → diagram-KO2AKTUF-DLPd9cl-.js} +1 -1
- package/dist/client/assets/{diagram-LMA3HP47-BhrlgXiJ.js → diagram-LMA3HP47-gfoMHIE-.js} +1 -1
- package/dist/client/assets/{diagram-OG6HWLK6-K-fWsJ3a.js → diagram-OG6HWLK6-D7zejHzo.js} +1 -1
- package/dist/client/assets/{erDiagram-TEJ5UH35-Der6PjHE.js → erDiagram-TEJ5UH35-DB1R9rUd.js} +1 -1
- package/dist/client/assets/{flowDiagram-I6XJVG4X-BVWgGhXe.js → flowDiagram-I6XJVG4X-rSasRun9.js} +1 -1
- package/dist/client/assets/{ganttDiagram-6RSMTGT7-DcoZ5ggj.js → ganttDiagram-6RSMTGT7-ickt48MT.js} +1 -1
- package/dist/client/assets/{gitGraphDiagram-PVQCEYII-BhhbMTBu.js → gitGraphDiagram-PVQCEYII-B2MWuej-.js} +1 -1
- package/dist/client/assets/index-4RQBXPuO.css +2 -0
- package/dist/client/assets/index-BN2UMUYo.js +276 -0
- package/dist/client/assets/{infoDiagram-5YYISTIA-Lwc-agyc.js → infoDiagram-5YYISTIA-ClB9-yBC.js} +1 -1
- package/dist/client/assets/{ishikawaDiagram-YF4QCWOH-B95U1Xcl.js → ishikawaDiagram-YF4QCWOH-CyUX0IyE.js} +1 -1
- package/dist/client/assets/{journeyDiagram-JHISSGLW-xFpigy5D.js → journeyDiagram-JHISSGLW-CvZv1SZ7.js} +1 -1
- package/dist/client/assets/{kanban-definition-UN3LZRKU-D3mudQnR.js → kanban-definition-UN3LZRKU-C3MgzQMY.js} +1 -1
- package/dist/client/assets/{line-DtTL3ZI2.js → line-Dpj7mkeR.js} +1 -1
- package/dist/client/assets/{mermaid-parser.core-Dau7K6zV.js → mermaid-parser.core-Ezn4UHHp.js} +1 -1
- package/dist/client/assets/{mermaid.core-B8qtvATu.js → mermaid.core-GVI7XZqR.js} +3 -3
- package/dist/client/assets/{mindmap-definition-RKZ34NQL-Cus04Yq3.js → mindmap-definition-RKZ34NQL-Bu2cgOo4.js} +1 -1
- package/dist/client/assets/{pieDiagram-4H26LBE5-BCMGpBnn.js → pieDiagram-4H26LBE5-_WS41t2_.js} +1 -1
- package/dist/client/assets/{quadrantDiagram-W4KKPZXB-CAmOr-PJ.js → quadrantDiagram-W4KKPZXB-Urvq-XqI.js} +1 -1
- package/dist/client/assets/{requirementDiagram-4Y6WPE33-kisD3jc4.js → requirementDiagram-4Y6WPE33-bkmWG0rM.js} +1 -1
- package/dist/client/assets/{sankeyDiagram-5OEKKPKP-CsCedmM0.js → sankeyDiagram-5OEKKPKP-DI0SArVz.js} +1 -1
- package/dist/client/assets/{sequenceDiagram-3UESZ5HK-B-dAi954.js → sequenceDiagram-3UESZ5HK-n7PKrHd3.js} +1 -1
- package/dist/client/assets/{stateDiagram-AJRCARHV-X0BnedIW.js → stateDiagram-AJRCARHV-CxnEzrQA.js} +1 -1
- package/dist/client/assets/stateDiagram-v2-BHNVJYJU-DXTMu4iJ.js +1 -0
- package/dist/client/assets/{timeline-definition-PNZ67QCA-DfFoSjhr.js → timeline-definition-PNZ67QCA-BFr88_A9.js} +1 -1
- package/dist/client/assets/{vennDiagram-CIIHVFJN-CKSCBwhG.js → vennDiagram-CIIHVFJN-BNYs6tfr.js} +1 -1
- package/dist/client/assets/{wardleyDiagram-YWT4CUSO-DNIBQmHO.js → wardleyDiagram-YWT4CUSO-CaGZd3fe.js} +1 -1
- package/dist/client/assets/{xychartDiagram-2RQKCTM6-FvB55TQN.js → xychartDiagram-2RQKCTM6-CMyDrx2a.js} +1 -1
- package/dist/client/index.html +2 -2
- package/dist/server/db.js +153 -26
- package/dist/server/db.js.map +1 -1
- package/dist/server/index.js +93 -36
- package/dist/server/index.js.map +1 -1
- package/dist/server/lib/activeTool.js +23 -0
- package/dist/server/lib/activeTool.js.map +1 -0
- package/dist/server/lib/agent.js +291 -67
- package/dist/server/lib/agent.js.map +1 -1
- package/dist/server/lib/agentCatalog.js +92 -4
- package/dist/server/lib/agentCatalog.js.map +1 -1
- package/dist/server/lib/agentProvider.js +8 -11
- package/dist/server/lib/agentProvider.js.map +1 -1
- package/dist/server/lib/agentRuns.js +26 -2
- package/dist/server/lib/agentRuns.js.map +1 -1
- package/dist/server/lib/automationCheckGate.js +6 -0
- package/dist/server/lib/automationCheckGate.js.map +1 -1
- package/dist/server/lib/buildExecutionEnvironment.js +82 -29
- package/dist/server/lib/buildExecutionEnvironment.js.map +1 -1
- package/dist/server/lib/buildFlow.js +5 -4
- package/dist/server/lib/buildFlow.js.map +1 -1
- package/dist/server/lib/buildSequences.js +7 -29
- package/dist/server/lib/buildSequences.js.map +1 -1
- package/dist/server/lib/buildTicketCommit.js +82 -11
- package/dist/server/lib/buildTicketCommit.js.map +1 -1
- package/dist/server/lib/bundleReviewOperations.js +6 -0
- package/dist/server/lib/bundleReviewOperations.js.map +1 -1
- package/dist/server/lib/chatOperations.js +109 -93
- package/dist/server/lib/chatOperations.js.map +1 -1
- package/dist/server/lib/chatSessionTitle.js +66 -0
- package/dist/server/lib/chatSessionTitle.js.map +1 -0
- package/dist/server/lib/chats.js +20 -4
- package/dist/server/lib/chats.js.map +1 -1
- package/dist/server/lib/checkAutoFix.js +65 -61
- package/dist/server/lib/checkAutoFix.js.map +1 -1
- package/dist/server/lib/codexAgentProvider.js +320 -0
- package/dist/server/lib/codexAgentProvider.js.map +1 -0
- package/dist/server/lib/codexAppServer.js +678 -0
- package/dist/server/lib/codexAppServer.js.map +1 -0
- package/dist/server/lib/codexCatalogDiscoveryExecutionEnvironment.js +302 -0
- package/dist/server/lib/codexCatalogDiscoveryExecutionEnvironment.js.map +1 -0
- package/dist/server/lib/codexDiscovery.js +137 -0
- package/dist/server/lib/codexDiscovery.js.map +1 -0
- package/dist/server/lib/config.js.map +1 -1
- package/dist/server/lib/dockerSandboxEnvironmentOperations.js +2 -2
- package/dist/server/lib/dockerSandboxEnvironmentOperations.js.map +1 -1
- package/dist/server/lib/dockerSandboxExecutionEnvironment.js +39 -10
- package/dist/server/lib/dockerSandboxExecutionEnvironment.js.map +1 -1
- package/dist/server/lib/dockerSandboxExecutionProvider.js +3 -1
- package/dist/server/lib/dockerSandboxExecutionProvider.js.map +1 -1
- package/dist/server/lib/dockerSandboxReleaseProfiles.js +8 -0
- package/dist/server/lib/dockerSandboxReleaseProfiles.js.map +1 -1
- package/dist/server/lib/executionCredentialCapabilities.js +39 -14
- package/dist/server/lib/executionCredentialCapabilities.js.map +1 -1
- package/dist/server/lib/executionEnvironment.js.map +1 -1
- package/dist/server/lib/executionEnvironmentContexts.js +1 -1
- package/dist/server/lib/executionEnvironmentContexts.js.map +1 -1
- package/dist/server/lib/executionEnvironmentLifecycle.js +1 -1
- package/dist/server/lib/executionEnvironmentLifecycle.js.map +1 -1
- package/dist/server/lib/executionEnvironmentReconciliation.js +7 -7
- package/dist/server/lib/executionEnvironmentReconciliation.js.map +1 -1
- package/dist/server/lib/executionEnvironmentRoutes.js +29 -25
- package/dist/server/lib/executionEnvironmentRoutes.js.map +1 -1
- package/dist/server/lib/executionEnvironmentValidation.js +205 -20
- package/dist/server/lib/executionEnvironmentValidation.js.map +1 -1
- package/dist/server/lib/executionEnvironmentValidationOperations.js +34 -29
- package/dist/server/lib/executionEnvironmentValidationOperations.js.map +1 -1
- package/dist/server/lib/executionEnvironments.js +59 -1
- package/dist/server/lib/executionEnvironments.js.map +1 -1
- package/dist/server/lib/executionProfiles.js +6 -3
- package/dist/server/lib/executionProfiles.js.map +1 -1
- package/dist/server/lib/executionRetryPredicates.js +2 -1
- package/dist/server/lib/executionRetryPredicates.js.map +1 -1
- package/dist/server/lib/executionRunAuthority.js +6 -1
- package/dist/server/lib/executionRunAuthority.js.map +1 -1
- package/dist/server/lib/genericToolCall.js +131 -9
- package/dist/server/lib/genericToolCall.js.map +1 -1
- package/dist/server/lib/hostExecutionEnvironment.js +5 -0
- package/dist/server/lib/hostExecutionEnvironment.js.map +1 -1
- package/dist/server/lib/lightweightPrompt.js +258 -18
- package/dist/server/lib/lightweightPrompt.js.map +1 -1
- package/dist/server/lib/mobileAccess.js +21 -13
- package/dist/server/lib/mobileAccess.js.map +1 -1
- package/dist/server/lib/modelResolutionErrors.js +4 -2
- package/dist/server/lib/modelResolutionErrors.js.map +1 -1
- package/dist/server/lib/models.js +15 -2
- package/dist/server/lib/models.js.map +1 -1
- package/dist/server/lib/oneShotAgent.js +11 -0
- package/dist/server/lib/oneShotAgent.js.map +1 -0
- package/dist/server/lib/projectAutoConfig.js +11 -5
- package/dist/server/lib/projectAutoConfig.js.map +1 -1
- package/dist/server/lib/projectMemory.js +3 -1
- package/dist/server/lib/projectMemory.js.map +1 -1
- package/dist/server/lib/projectMemoryScan.js +13 -3
- package/dist/server/lib/projectMemoryScan.js.map +1 -1
- package/dist/server/lib/projectMemoryTransfer.js +5 -2
- package/dist/server/lib/projectMemoryTransfer.js.map +1 -1
- package/dist/server/lib/promptSkills.js +1 -1
- package/dist/server/lib/promptSkills.js.map +1 -1
- package/dist/server/lib/run.js +2 -0
- package/dist/server/lib/run.js.map +1 -1
- package/dist/server/lib/skills.js +21 -4
- package/dist/server/lib/skills.js.map +1 -1
- package/dist/server/lib/specOperations.js +14 -10
- package/dist/server/lib/specOperations.js.map +1 -1
- package/dist/server/lib/specReviewOperations.js +20 -11
- package/dist/server/lib/specReviewOperations.js.map +1 -1
- package/dist/server/lib/specs.js +14 -4
- package/dist/server/lib/specs.js.map +1 -1
- package/dist/server/lib/ticketAutomationCommit.js +23 -7
- package/dist/server/lib/ticketAutomationCommit.js.map +1 -1
- package/dist/server/lib/ticketFollowUpOperations.js +7 -0
- package/dist/server/lib/ticketFollowUpOperations.js.map +1 -1
- package/dist/server/lib/ticketRunOperations.js +11 -1
- package/dist/server/lib/ticketRunOperations.js.map +1 -1
- package/dist/server/lib/ticketSettingsOperations.js +4 -1
- package/dist/server/lib/ticketSettingsOperations.js.map +1 -1
- package/dist/server/lib/toolUpgrade.js +1 -0
- package/dist/server/lib/toolUpgrade.js.map +1 -1
- package/dist/server/lib/transcriptRuns.js +4 -1
- package/dist/server/lib/transcriptRuns.js.map +1 -1
- package/dist/server/lib/types.js.map +1 -1
- package/dist/server/workers/build.js +9 -4
- package/dist/server/workers/build.js.map +1 -1
- package/dist/server/workers/chat.js +55 -11
- package/dist/server/workers/chat.js.map +1 -1
- package/dist/server/workers/followUp.js +6 -1
- package/dist/server/workers/followUp.js.map +1 -1
- package/dist/server/workers/plan.js +235 -68
- package/dist/server/workers/plan.js.map +1 -1
- package/dist/server/workers/planFollowUp.js +11 -4
- package/dist/server/workers/planFollowUp.js.map +1 -1
- package/dist/server/workers/review.js +15 -18
- package/dist/server/workers/review.js.map +1 -1
- package/dist/server/workers/specReview.js +7 -7
- package/dist/server/workers/specReview.js.map +1 -1
- package/dist/server/workers/specSession.js +8 -12
- package/dist/server/workers/specSession.js.map +1 -1
- package/package.json +1 -1
- package/dist/client/assets/channel-DXKn3TOv.js +0 -1
- package/dist/client/assets/classDiagram-4FO5ZUOK-U0fU20hT.js +0 -1
- package/dist/client/assets/classDiagram-v2-Q7XG4LA2-C6bQNSxL.js +0 -1
- package/dist/client/assets/index-B6BltHSr.css +0 -2
- package/dist/client/assets/index-CFOYm3j9.js +0 -276
- package/dist/client/assets/stateDiagram-v2-BHNVJYJU-6B8YH8Y2.js +0 -1
|
@@ -4,10 +4,12 @@ import db from '../db.js';
|
|
|
4
4
|
import config from '../lib/config.js';
|
|
5
5
|
import { JiraApiError } from '../lib/integrations/jira.js';
|
|
6
6
|
import { GitHubApiError } from '../lib/integrations/github.js';
|
|
7
|
-
import { formatGenericToolCall } from '../lib/genericToolCall.js';
|
|
7
|
+
import { formatCodexFileChange, formatCodexWebSearch, formatGenericToolCall } from '../lib/genericToolCall.js';
|
|
8
8
|
import { PlanningReferenceError, resolveExternalPlanningDescription } from '../lib/integrations/planning.js';
|
|
9
9
|
import { resolveExistingWorktreePath } from '../lib/git.js';
|
|
10
10
|
import { getModelProvider, normalizeModelId } from '../lib/models.js';
|
|
11
|
+
import { getAgentModelProvider, normalizeAgentModelId, requireExecutableAgent } from '../lib/agentCatalog.js';
|
|
12
|
+
import { codexAgentProvider } from '../lib/codexAgentProvider.js';
|
|
11
13
|
import { createOpencodeTaskSessionReader, parseOpencodeTaskEnvelope } from '../lib/opencodeTaskSessions.js';
|
|
12
14
|
import { hostOpencodeSessionOperations } from '../lib/opencodeSessionOperations.js';
|
|
13
15
|
import { markRetryableOpenCodeDatabaseLock, RetryableOpenCodeDatabaseLockError, retryOpenCodeDatabaseLocks } from '../lib/opencodeExecutionReliability.js';
|
|
@@ -81,9 +83,11 @@ const finalizePlanningInvocation = (invocation, status, evidence) => {
|
|
|
81
83
|
};
|
|
82
84
|
const activePlanProcesses = new Map();
|
|
83
85
|
const activePlannerProcesses = new Set();
|
|
86
|
+
const plannerProtocolInterrupts = new Map();
|
|
84
87
|
const createPlannerRecoveryTracker = () => {
|
|
85
88
|
let sawError = false;
|
|
86
89
|
let latestEvent = null;
|
|
90
|
+
let latestError = '';
|
|
87
91
|
let finalAnswerFragments = [];
|
|
88
92
|
return {
|
|
89
93
|
consume: (events) => {
|
|
@@ -92,6 +96,7 @@ const createPlannerRecoveryTracker = () => {
|
|
|
92
96
|
latestEvent = event.type;
|
|
93
97
|
if (event.type === 'error') {
|
|
94
98
|
sawError = true;
|
|
99
|
+
latestError = event.message?.trim() ?? '';
|
|
95
100
|
finalAnswerFragments = [];
|
|
96
101
|
shouldResetResponse = true;
|
|
97
102
|
continue;
|
|
@@ -106,6 +111,7 @@ const createPlannerRecoveryTracker = () => {
|
|
|
106
111
|
&& latestEvent === 'final_answer'
|
|
107
112
|
&& finalAnswerFragments.length > 0),
|
|
108
113
|
hasUnrecoveredError: () => latestEvent === 'error',
|
|
114
|
+
getUnrecoveredError: () => latestEvent === 'error' ? latestError : '',
|
|
109
115
|
getRecoveredResponse: () => finalAnswerFragments.join('\n\n'),
|
|
110
116
|
};
|
|
111
117
|
};
|
|
@@ -254,8 +260,18 @@ const formatPlannerWriteToolCall = (input) => {
|
|
|
254
260
|
lines.push('[[/archon-apply-patch]]');
|
|
255
261
|
return lines.join('\n');
|
|
256
262
|
};
|
|
257
|
-
const formatPlannerToolCall = (name, input) => {
|
|
263
|
+
const formatPlannerToolCall = (name, input, cwd) => {
|
|
258
264
|
const normalized = normalizeToolName(name);
|
|
265
|
+
if (normalized === 'filechange') {
|
|
266
|
+
const formatted = formatCodexFileChange(input, cwd);
|
|
267
|
+
if (formatted !== null) {
|
|
268
|
+
return formatted;
|
|
269
|
+
}
|
|
270
|
+
return formatGenericToolCall(name, input);
|
|
271
|
+
}
|
|
272
|
+
if (normalized === 'websearch') {
|
|
273
|
+
return formatCodexWebSearch(input);
|
|
274
|
+
}
|
|
259
275
|
if (normalized === 'edit') {
|
|
260
276
|
const formatted = formatPlannerEditToolCall(input);
|
|
261
277
|
if (formatted !== null) {
|
|
@@ -367,25 +383,39 @@ const parseClaudePlannerStreamJsonLine = (line) => {
|
|
|
367
383
|
}
|
|
368
384
|
return emptyParsedPlannerStreamLine();
|
|
369
385
|
};
|
|
370
|
-
const formatPlannerOpencodeToolUse = (event) => {
|
|
386
|
+
const formatPlannerOpencodeToolUse = (event, cwd) => {
|
|
371
387
|
const toolName = event.part?.tool;
|
|
372
388
|
if (!toolName) {
|
|
373
389
|
return null;
|
|
374
390
|
}
|
|
375
|
-
return formatPlannerToolCall(toolName, event.part?.state?.input);
|
|
391
|
+
return formatPlannerToolCall(toolName, event.part?.state?.input, cwd);
|
|
376
392
|
};
|
|
377
393
|
const formatPlannerStepTitle = (event) => {
|
|
378
394
|
const title = event.part?.title?.trim();
|
|
379
395
|
return title || null;
|
|
380
396
|
};
|
|
381
|
-
const parseOpencodePlannerJsonEvent = (event) => {
|
|
397
|
+
const parseOpencodePlannerJsonEvent = (event, cwd) => {
|
|
382
398
|
const providerSessionId = event.sessionID?.trim()
|
|
383
399
|
|| event.sessionId?.trim()
|
|
384
400
|
|| event.part?.sessionID?.trim()
|
|
385
401
|
|| event.part?.sessionId?.trim()
|
|
386
402
|
|| null;
|
|
403
|
+
if (event.type === 'plan' && event.part?.type === 'text' && event.part.text) {
|
|
404
|
+
return {
|
|
405
|
+
logFragment: event.part.text,
|
|
406
|
+
responseFragment: null,
|
|
407
|
+
subagentEvents: [],
|
|
408
|
+
providerSessionId,
|
|
409
|
+
concatenateFragments: event.part.metadata?.codex?.delta === true,
|
|
410
|
+
replaceFragment: event.part.metadata?.codex?.snapshot === true,
|
|
411
|
+
fragmentGroup: event.part.metadata?.codex?.fragmentGroup
|
|
412
|
+
?? event.part.metadata?.codex?.itemId
|
|
413
|
+
?? null,
|
|
414
|
+
};
|
|
415
|
+
}
|
|
387
416
|
if (event.type === 'text' && event.part?.type === 'text' && event.part.text) {
|
|
388
|
-
const
|
|
417
|
+
const concatenateFragments = event.part.metadata?.codex?.delta === true;
|
|
418
|
+
const text = concatenateFragments ? event.part.text : event.part.text.trim();
|
|
389
419
|
const phase = event.part.metadata?.openai?.phase;
|
|
390
420
|
return {
|
|
391
421
|
logFragment: text || null,
|
|
@@ -396,15 +426,24 @@ const parseOpencodePlannerJsonEvent = (event) => {
|
|
|
396
426
|
recoveryEvents: text && phase === 'final_answer'
|
|
397
427
|
? [{ type: 'final_answer', text }]
|
|
398
428
|
: [],
|
|
429
|
+
concatenateFragments,
|
|
430
|
+
fragmentGroup: event.part.metadata?.codex?.fragmentGroup
|
|
431
|
+
?? event.part.metadata?.codex?.itemId
|
|
432
|
+
?? null,
|
|
399
433
|
};
|
|
400
434
|
}
|
|
401
435
|
if (event.type === 'reasoning' && event.part?.type === 'reasoning') {
|
|
402
|
-
const
|
|
436
|
+
const concatenateFragments = event.part.metadata?.codex?.delta === true;
|
|
437
|
+
const text = concatenateFragments ? event.part.text ?? '' : event.part.text?.trim() ?? '';
|
|
403
438
|
return {
|
|
404
439
|
logFragment: text || null,
|
|
405
440
|
responseFragment: null,
|
|
406
441
|
subagentEvents: [],
|
|
407
442
|
providerSessionId,
|
|
443
|
+
concatenateFragments,
|
|
444
|
+
fragmentGroup: event.part.metadata?.codex?.fragmentGroup
|
|
445
|
+
?? event.part.metadata?.codex?.itemId
|
|
446
|
+
?? null,
|
|
408
447
|
};
|
|
409
448
|
}
|
|
410
449
|
if (event.type === 'tool' || event.type === 'tool_use' || event.type === 'tool_result') {
|
|
@@ -416,6 +455,7 @@ const parseOpencodePlannerJsonEvent = (event) => {
|
|
|
416
455
|
const envelope = parseOpencodeTaskEnvelope(rawOutput);
|
|
417
456
|
const output = envelope?.result ?? rawOutput;
|
|
418
457
|
const taskStatus = event.part?.state?.status?.toLowerCase() ?? envelope?.state?.toLowerCase();
|
|
458
|
+
const isTerminal = Boolean(taskStatus && taskStatus !== 'running' && taskStatus !== 'pending');
|
|
419
459
|
const childSessionId = envelope?.childSessionId
|
|
420
460
|
?? (typeof event.part?.state?.metadata?.sessionID === 'string' ? event.part.state.metadata.sessionID : null)
|
|
421
461
|
?? (typeof event.part?.state?.metadata?.sessionId === 'string' ? event.part.state.metadata.sessionId : null);
|
|
@@ -431,13 +471,15 @@ const parseOpencodePlannerJsonEvent = (event) => {
|
|
|
431
471
|
sessionId: childSessionId,
|
|
432
472
|
}]
|
|
433
473
|
: []),
|
|
434
|
-
...(output
|
|
474
|
+
...(output || isTerminal
|
|
435
475
|
? [{
|
|
436
|
-
kind:
|
|
476
|
+
kind: isTerminal ? 'complete' : 'fragment',
|
|
437
477
|
callId: event.part?.callID ?? null,
|
|
438
|
-
text: output,
|
|
478
|
+
...(output ? { text: output } : {}),
|
|
439
479
|
sessionId: childSessionId,
|
|
440
|
-
status: taskStatus === 'error' || taskStatus === 'failed'
|
|
480
|
+
status: taskStatus === 'error' || taskStatus === 'failed'
|
|
481
|
+
? 'error'
|
|
482
|
+
: taskStatus === 'stopped' ? 'stopped' : 'done',
|
|
441
483
|
}]
|
|
442
484
|
: []),
|
|
443
485
|
],
|
|
@@ -448,7 +490,7 @@ const parseOpencodePlannerJsonEvent = (event) => {
|
|
|
448
490
|
return { ...emptyParsedPlannerStreamLine(), providerSessionId };
|
|
449
491
|
}
|
|
450
492
|
return {
|
|
451
|
-
logFragment: formatPlannerOpencodeToolUse(event),
|
|
493
|
+
logFragment: formatPlannerOpencodeToolUse(event, cwd),
|
|
452
494
|
responseFragment: null,
|
|
453
495
|
subagentEvents: [],
|
|
454
496
|
providerSessionId,
|
|
@@ -474,12 +516,12 @@ const parseOpencodePlannerJsonEvent = (event) => {
|
|
|
474
516
|
responseFragment: null,
|
|
475
517
|
subagentEvents: [],
|
|
476
518
|
providerSessionId,
|
|
477
|
-
recoveryEvents: [{ type: 'error' }],
|
|
519
|
+
recoveryEvents: [{ type: 'error', message: text }],
|
|
478
520
|
};
|
|
479
521
|
}
|
|
480
522
|
return { ...emptyParsedPlannerStreamLine(), providerSessionId };
|
|
481
523
|
};
|
|
482
|
-
const parseOpencodePlannerJsonLine = (line) => {
|
|
524
|
+
const parseOpencodePlannerJsonLine = (line, cwd) => {
|
|
483
525
|
const trimmedLine = line.trim();
|
|
484
526
|
if (!trimmedLine) {
|
|
485
527
|
return emptyParsedPlannerStreamLine();
|
|
@@ -510,6 +552,9 @@ const parseOpencodePlannerJsonLine = (line) => {
|
|
|
510
552
|
const recoveryEvents = [];
|
|
511
553
|
let providerSessionId = null;
|
|
512
554
|
let hasFinalAnswer = false;
|
|
555
|
+
let concatenateFragments;
|
|
556
|
+
let replaceFragment;
|
|
557
|
+
let fragmentGroup;
|
|
513
558
|
for (const jsonObject of jsonObjects) {
|
|
514
559
|
let event;
|
|
515
560
|
try {
|
|
@@ -518,7 +563,7 @@ const parseOpencodePlannerJsonLine = (line) => {
|
|
|
518
563
|
catch {
|
|
519
564
|
continue;
|
|
520
565
|
}
|
|
521
|
-
const parsedEvent = parseOpencodePlannerJsonEvent(event);
|
|
566
|
+
const parsedEvent = parseOpencodePlannerJsonEvent(event, cwd);
|
|
522
567
|
const eventRecoveryEvents = parsedEvent.recoveryEvents ?? [];
|
|
523
568
|
if (eventRecoveryEvents.some(recoveryEvent => recoveryEvent.type === 'error')) {
|
|
524
569
|
responseFragments.length = 0;
|
|
@@ -533,6 +578,11 @@ const parseOpencodePlannerJsonLine = (line) => {
|
|
|
533
578
|
recoveryEvents.push(...eventRecoveryEvents);
|
|
534
579
|
providerSessionId = providerSessionId ?? parsedEvent.providerSessionId;
|
|
535
580
|
hasFinalAnswer ||= parsedEvent.hasFinalAnswer === true;
|
|
581
|
+
if (jsonObjects.length === 1) {
|
|
582
|
+
concatenateFragments = parsedEvent.concatenateFragments;
|
|
583
|
+
replaceFragment = parsedEvent.replaceFragment;
|
|
584
|
+
fragmentGroup = parsedEvent.fragmentGroup;
|
|
585
|
+
}
|
|
536
586
|
}
|
|
537
587
|
if (remainder) {
|
|
538
588
|
const envelope = parseOpencodeTaskEnvelope(remainder);
|
|
@@ -557,6 +607,9 @@ const parseOpencodePlannerJsonLine = (line) => {
|
|
|
557
607
|
providerSessionId,
|
|
558
608
|
recoveryEvents,
|
|
559
609
|
hasFinalAnswer,
|
|
610
|
+
concatenateFragments,
|
|
611
|
+
replaceFragment,
|
|
612
|
+
fragmentGroup,
|
|
560
613
|
};
|
|
561
614
|
};
|
|
562
615
|
const attachPlannerTranscriptRuns = (error, transcriptRuns) => {
|
|
@@ -950,12 +1003,10 @@ const resolvePlannerCwd = (project, branch) => {
|
|
|
950
1003
|
}
|
|
951
1004
|
return resolveExistingWorktreePath(branch, project) ?? project.repo_path;
|
|
952
1005
|
};
|
|
953
|
-
export const updatePlanningSessionId = (ticketId, sessionId, io, sessionOperations) => {
|
|
954
|
-
|
|
955
|
-
const resolvedTool = resolveTicketTool(existing, config.tool ?? 'opencode');
|
|
956
|
-
db.prepare('UPDATE tickets SET planning_session_id = ?, tool = ?, updated_at = CURRENT_TIMESTAMP WHERE id = ?').run(sessionId, resolvedTool, ticketId);
|
|
1006
|
+
export const updatePlanningSessionId = (ticketId, sessionId, tool, io, sessionOperations) => {
|
|
1007
|
+
db.prepare('UPDATE tickets SET planning_session_id = ?, tool = ?, updated_at = CURRENT_TIMESTAMP WHERE id = ?').run(sessionId, tool, ticketId);
|
|
957
1008
|
const ticket = getTicket(ticketId);
|
|
958
|
-
if (ticket &&
|
|
1009
|
+
if (ticket && tool === 'opencode') {
|
|
959
1010
|
if (sessionOperations) {
|
|
960
1011
|
void storeTicketUsageSnapshot(ticket.id, sessionId, sessionOperations);
|
|
961
1012
|
}
|
|
@@ -1001,9 +1052,15 @@ const killPlannerProcess = (proc, signal) => {
|
|
|
1001
1052
|
}
|
|
1002
1053
|
};
|
|
1003
1054
|
export const stopPlannerProcesses = async (children) => {
|
|
1004
|
-
|
|
1005
|
-
|
|
1006
|
-
|
|
1055
|
+
await Promise.all(children.map(async (child) => {
|
|
1056
|
+
const protocolInterrupt = plannerProtocolInterrupts.get(child);
|
|
1057
|
+
if (protocolInterrupt) {
|
|
1058
|
+
await protocolInterrupt().catch(() => killPlannerProcess(child, 'SIGTERM'));
|
|
1059
|
+
}
|
|
1060
|
+
else {
|
|
1061
|
+
killPlannerProcess(child, 'SIGTERM');
|
|
1062
|
+
}
|
|
1063
|
+
}));
|
|
1007
1064
|
const deadline = Date.now() + PLANNER_KILL_GRACE_MS;
|
|
1008
1065
|
while (children.some(isPlannerProcessAlive) && Date.now() < deadline) {
|
|
1009
1066
|
await new Promise(resolve => setTimeout(resolve, 100));
|
|
@@ -1013,7 +1070,7 @@ export const stopPlannerProcesses = async (children) => {
|
|
|
1013
1070
|
}
|
|
1014
1071
|
};
|
|
1015
1072
|
const runPlannerPromptOnce = (tool, model, variant, prompt, cwd, options = {}) => {
|
|
1016
|
-
const resolvedModel =
|
|
1073
|
+
const resolvedModel = normalizeAgentModelId(tool, model);
|
|
1017
1074
|
const finalPrompt = tool === 'claude'
|
|
1018
1075
|
? appendClaudeHeadlessPlanPrompt(prompt)
|
|
1019
1076
|
: prompt;
|
|
@@ -1025,10 +1082,10 @@ const runPlannerPromptOnce = (tool, model, variant, prompt, cwd, options = {}) =
|
|
|
1025
1082
|
let spawnTimestamp = null;
|
|
1026
1083
|
let sessionLookupTimer = null;
|
|
1027
1084
|
let hasResolvedSessionId = Boolean(sessionTracking?.resumeSessionId);
|
|
1028
|
-
const [cmd, args] = tool === 'claude'
|
|
1085
|
+
const [cmd, args, stdio] = tool === 'claude'
|
|
1029
1086
|
? (() => {
|
|
1030
1087
|
if (!sessionTracking) {
|
|
1031
|
-
return ['claude', [...buildClaudeHeadlessPlanArgs(), '--print', '--verbose', '--output-format', 'stream-json', finalPrompt]];
|
|
1088
|
+
return ['claude', [...buildClaudeHeadlessPlanArgs(), '--print', '--verbose', '--output-format', 'stream-json', finalPrompt], ['ignore', 'pipe', 'pipe']];
|
|
1032
1089
|
}
|
|
1033
1090
|
sessionId = sessionTracking.resumeSessionId || randomUUID();
|
|
1034
1091
|
return [
|
|
@@ -1043,22 +1100,38 @@ const runPlannerPromptOnce = (tool, model, variant, prompt, cwd, options = {}) =
|
|
|
1043
1100
|
sessionId,
|
|
1044
1101
|
finalPrompt,
|
|
1045
1102
|
],
|
|
1103
|
+
['ignore', 'pipe', 'pipe'],
|
|
1046
1104
|
];
|
|
1047
1105
|
})()
|
|
1048
|
-
:
|
|
1049
|
-
|
|
1050
|
-
|
|
1051
|
-
|
|
1052
|
-
|
|
1053
|
-
|
|
1054
|
-
|
|
1055
|
-
|
|
1056
|
-
|
|
1057
|
-
|
|
1058
|
-
|
|
1059
|
-
|
|
1060
|
-
|
|
1061
|
-
|
|
1106
|
+
: tool === 'codex'
|
|
1107
|
+
? (() => {
|
|
1108
|
+
const invocation = codexAgentProvider.buildStreamingInvocation({
|
|
1109
|
+
cwd: cwd ?? process.cwd(),
|
|
1110
|
+
prompt: finalPrompt,
|
|
1111
|
+
model: resolvedModel || null,
|
|
1112
|
+
variant,
|
|
1113
|
+
skills: options.skills,
|
|
1114
|
+
mode: 'plan',
|
|
1115
|
+
resumeSessionId: sessionTracking?.resumeSessionId ?? null,
|
|
1116
|
+
sessionId: randomUUID(),
|
|
1117
|
+
});
|
|
1118
|
+
return [invocation.command, [...invocation.args], invocation.stdio];
|
|
1119
|
+
})()
|
|
1120
|
+
: [
|
|
1121
|
+
'opencode',
|
|
1122
|
+
[
|
|
1123
|
+
'run',
|
|
1124
|
+
'--agent',
|
|
1125
|
+
'plan',
|
|
1126
|
+
'--format',
|
|
1127
|
+
'json',
|
|
1128
|
+
...(sessionTracking?.resumeSessionId ? ['--session', sessionTracking.resumeSessionId] : []),
|
|
1129
|
+
...(resolvedModel ? ['--model', resolvedModel] : []),
|
|
1130
|
+
...(variant ? ['--variant', variant] : []),
|
|
1131
|
+
finalPrompt,
|
|
1132
|
+
],
|
|
1133
|
+
['ignore', 'pipe', 'pipe'],
|
|
1134
|
+
];
|
|
1062
1135
|
return new Promise((resolve, reject) => {
|
|
1063
1136
|
let settled = false;
|
|
1064
1137
|
let completionForced = false;
|
|
@@ -1118,7 +1191,7 @@ const runPlannerPromptOnce = (tool, model, variant, prompt, cwd, options = {}) =
|
|
|
1118
1191
|
}
|
|
1119
1192
|
if (sessionTracking && !hasResolvedSessionId) {
|
|
1120
1193
|
hasResolvedSessionId = true;
|
|
1121
|
-
updatePlanningSessionId(sessionTracking.ticketId, normalized, sessionTracking.io, opencodeSessionOperations ?? undefined);
|
|
1194
|
+
updatePlanningSessionId(sessionTracking.ticketId, normalized, tool, sessionTracking.io, opencodeSessionOperations ?? undefined);
|
|
1122
1195
|
}
|
|
1123
1196
|
};
|
|
1124
1197
|
const attemptOpencodeSessionLookup = async () => {
|
|
@@ -1140,6 +1213,7 @@ const runPlannerPromptOnce = (tool, model, variant, prompt, cwd, options = {}) =
|
|
|
1140
1213
|
spawnTimestamp = Date.now();
|
|
1141
1214
|
}
|
|
1142
1215
|
let child;
|
|
1216
|
+
let providerStdout = null;
|
|
1143
1217
|
let placementFailure = Promise.resolve(null);
|
|
1144
1218
|
try {
|
|
1145
1219
|
if (options.executionProvider) {
|
|
@@ -1148,7 +1222,7 @@ const runPlannerPromptOnce = (tool, model, variant, prompt, cwd, options = {}) =
|
|
|
1148
1222
|
target: options.executionTarget ?? null,
|
|
1149
1223
|
command: cmd,
|
|
1150
1224
|
args,
|
|
1151
|
-
stdio
|
|
1225
|
+
stdio,
|
|
1152
1226
|
launcherEnvironment: options.executionLauncherEnvironment ?? createHostLauncherEnvironment(),
|
|
1153
1227
|
runtimeEnvironment: options.executionRuntimeEnvironment ?? createLegacyHostRuntimeEnvironment(cwd ?? process.cwd(), cwd ? { PWD: cwd } : {}),
|
|
1154
1228
|
detached: process.platform !== 'win32',
|
|
@@ -1164,7 +1238,7 @@ const runPlannerPromptOnce = (tool, model, variant, prompt, cwd, options = {}) =
|
|
|
1164
1238
|
}
|
|
1165
1239
|
else {
|
|
1166
1240
|
child = spawn(cmd, args, {
|
|
1167
|
-
stdio
|
|
1241
|
+
stdio,
|
|
1168
1242
|
env: cwd ? createWorkspaceProcessEnvironment(cwd, { PWD: cwd }) : process.env,
|
|
1169
1243
|
detached: process.platform !== 'win32',
|
|
1170
1244
|
...(cwd ? { cwd } : {}),
|
|
@@ -1178,6 +1252,28 @@ const runPlannerPromptOnce = (tool, model, variant, prompt, cwd, options = {}) =
|
|
|
1178
1252
|
return;
|
|
1179
1253
|
}
|
|
1180
1254
|
activePlannerProcesses.add(child);
|
|
1255
|
+
if (tool === 'codex') {
|
|
1256
|
+
const connection = codexAgentProvider.connectStreamingInvocation?.(child, {
|
|
1257
|
+
cwd: cwd ?? process.cwd(),
|
|
1258
|
+
prompt: finalPrompt,
|
|
1259
|
+
model: resolvedModel || null,
|
|
1260
|
+
variant,
|
|
1261
|
+
skills: options.skills,
|
|
1262
|
+
mode: 'plan',
|
|
1263
|
+
resumeSessionId: sessionTracking?.resumeSessionId ?? null,
|
|
1264
|
+
sessionId: randomUUID(),
|
|
1265
|
+
}, {
|
|
1266
|
+
runtimeEnvironmentKind: options.executionRuntimeEnvironment?.kind ?? 'host',
|
|
1267
|
+
});
|
|
1268
|
+
if (connection) {
|
|
1269
|
+
providerStdout = connection.stdout;
|
|
1270
|
+
plannerProtocolInterrupts.set(child, connection.interrupt);
|
|
1271
|
+
void connection.sessionReady.then(bindResolvedProviderSession).catch(() => { });
|
|
1272
|
+
if (options.cancellationState?.stopRequested) {
|
|
1273
|
+
void connection.interrupt().catch(() => killPlannerProcess(child, 'SIGTERM'));
|
|
1274
|
+
}
|
|
1275
|
+
}
|
|
1276
|
+
}
|
|
1181
1277
|
if (options.cancellationState) {
|
|
1182
1278
|
options.cancellationState.researchChildren.add(child);
|
|
1183
1279
|
if (options.cancellationState.stopRequested) {
|
|
@@ -1224,6 +1320,9 @@ const runPlannerPromptOnce = (tool, model, variant, prompt, cwd, options = {}) =
|
|
|
1224
1320
|
let usageSnapshot = EMPTY_CHAT_USAGE_SNAPSHOT;
|
|
1225
1321
|
let remainder = '';
|
|
1226
1322
|
let insideHiddenBlock = false;
|
|
1323
|
+
let concatenatingLogGroup;
|
|
1324
|
+
let concatenatingResponseGroup;
|
|
1325
|
+
const logIndexesByGroup = new Map();
|
|
1227
1326
|
const startTime = Date.now();
|
|
1228
1327
|
let firstFinalAnswerTime = null;
|
|
1229
1328
|
const emitProgress = () => {
|
|
@@ -1236,25 +1335,27 @@ const runPlannerPromptOnce = (tool, model, variant, prompt, cwd, options = {}) =
|
|
|
1236
1335
|
};
|
|
1237
1336
|
const isHiddenOpenTag = /^\s*<archon-[a-z0-9-]+>\s*$/i;
|
|
1238
1337
|
const isHiddenCloseTag = /^\s*<\/archon-[a-z0-9-]+>\s*$/i;
|
|
1239
|
-
child.stdout
|
|
1338
|
+
const outputStream = providerStdout ?? child.stdout;
|
|
1339
|
+
outputStream?.on('data', (chunk) => {
|
|
1240
1340
|
stdoutChunks.push(chunk);
|
|
1241
1341
|
lastStdoutAt = Date.now();
|
|
1242
1342
|
const text = remainder + chunk.toString();
|
|
1243
1343
|
const lines = text.split('\n');
|
|
1244
1344
|
remainder = lines.pop() ?? '';
|
|
1245
1345
|
for (const line of lines) {
|
|
1246
|
-
if (tool === 'claude') {
|
|
1346
|
+
if (tool === 'claude' || tool === 'codex') {
|
|
1247
1347
|
usageSnapshot = mergeUsageFromJsonLine(usageSnapshot, line);
|
|
1248
1348
|
}
|
|
1249
1349
|
const parsedLine = tool === 'claude'
|
|
1250
1350
|
? parseClaudePlannerStreamJsonLine(line)
|
|
1251
|
-
: parseOpencodePlannerJsonLine(line);
|
|
1351
|
+
: parseOpencodePlannerJsonLine(line, cwd);
|
|
1252
1352
|
const { logFragment, responseFragment, subagentEvents, providerSessionId } = parsedLine;
|
|
1253
|
-
if (tool === 'opencode' && recoveryTracker.consume(parsedLine.recoveryEvents)) {
|
|
1353
|
+
if ((tool === 'opencode' || tool === 'codex') && recoveryTracker.consume(parsedLine.recoveryEvents)) {
|
|
1254
1354
|
responseLines.length = 0;
|
|
1355
|
+
concatenatingResponseGroup = undefined;
|
|
1255
1356
|
firstFinalAnswerTime = null;
|
|
1256
1357
|
}
|
|
1257
|
-
if (tool === 'opencode' && firstFinalAnswerTime === null && parsedLine.hasFinalAnswer) {
|
|
1358
|
+
if ((tool === 'opencode' || tool === 'codex') && firstFinalAnswerTime === null && parsedLine.hasFinalAnswer) {
|
|
1258
1359
|
firstFinalAnswerTime = Date.now();
|
|
1259
1360
|
}
|
|
1260
1361
|
subagentTracker?.handle(subagentEvents);
|
|
@@ -1268,11 +1369,35 @@ const runPlannerPromptOnce = (tool, model, variant, prompt, cwd, options = {}) =
|
|
|
1268
1369
|
insideHiddenBlock = false;
|
|
1269
1370
|
}
|
|
1270
1371
|
if (logFragment !== null) {
|
|
1271
|
-
|
|
1372
|
+
if (parsedLine.replaceFragment && parsedLine.fragmentGroup) {
|
|
1373
|
+
const index = logIndexesByGroup.get(parsedLine.fragmentGroup);
|
|
1374
|
+
if (index === undefined) {
|
|
1375
|
+
logIndexesByGroup.set(parsedLine.fragmentGroup, logLines.push(logFragment) - 1);
|
|
1376
|
+
}
|
|
1377
|
+
else {
|
|
1378
|
+
logLines[index] = logFragment;
|
|
1379
|
+
}
|
|
1380
|
+
}
|
|
1381
|
+
else if (parsedLine.concatenateFragments && concatenatingLogGroup === parsedLine.fragmentGroup && logLines.length > 0) {
|
|
1382
|
+
logLines[logLines.length - 1] += logFragment;
|
|
1383
|
+
}
|
|
1384
|
+
else {
|
|
1385
|
+
const index = logLines.push(logFragment) - 1;
|
|
1386
|
+
if (parsedLine.fragmentGroup) {
|
|
1387
|
+
logIndexesByGroup.set(parsedLine.fragmentGroup, index);
|
|
1388
|
+
}
|
|
1389
|
+
}
|
|
1390
|
+
concatenatingLogGroup = parsedLine.concatenateFragments ? parsedLine.fragmentGroup ?? null : undefined;
|
|
1272
1391
|
}
|
|
1273
1392
|
const isHiddenTagLine = isHiddenOpenTag.test(line) || isHiddenCloseTag.test(line);
|
|
1274
1393
|
if (responseFragment !== null && !isHiddenTagLine && !insideHiddenBlock) {
|
|
1275
|
-
responseLines.
|
|
1394
|
+
if (parsedLine.concatenateFragments && concatenatingResponseGroup === parsedLine.fragmentGroup && responseLines.length > 0) {
|
|
1395
|
+
responseLines[responseLines.length - 1] += responseFragment;
|
|
1396
|
+
}
|
|
1397
|
+
else {
|
|
1398
|
+
responseLines.push(responseFragment);
|
|
1399
|
+
}
|
|
1400
|
+
concatenatingResponseGroup = parsedLine.concatenateFragments ? parsedLine.fragmentGroup ?? null : undefined;
|
|
1276
1401
|
}
|
|
1277
1402
|
if (logFragment !== null || responseFragment !== null) {
|
|
1278
1403
|
emitProgress();
|
|
@@ -1282,6 +1407,7 @@ const runPlannerPromptOnce = (tool, model, variant, prompt, cwd, options = {}) =
|
|
|
1282
1407
|
child.stderr?.on('data', (chunk) => stderrChunks.push(chunk));
|
|
1283
1408
|
child.on('close', async (code) => {
|
|
1284
1409
|
activePlannerProcesses.delete(child);
|
|
1410
|
+
plannerProtocolInterrupts.delete(child);
|
|
1285
1411
|
options.cancellationState?.researchChildren.delete(child);
|
|
1286
1412
|
clearWatchdogTimer();
|
|
1287
1413
|
const placementError = await placementFailure;
|
|
@@ -1290,18 +1416,19 @@ const runPlannerPromptOnce = (tool, model, variant, prompt, cwd, options = {}) =
|
|
|
1290
1416
|
return;
|
|
1291
1417
|
}
|
|
1292
1418
|
if (remainder.trim()) {
|
|
1293
|
-
if (tool === 'claude') {
|
|
1419
|
+
if (tool === 'claude' || tool === 'codex') {
|
|
1294
1420
|
usageSnapshot = mergeUsageFromJsonLine(usageSnapshot, remainder);
|
|
1295
1421
|
}
|
|
1296
1422
|
const parsedLine = tool === 'claude'
|
|
1297
1423
|
? parseClaudePlannerStreamJsonLine(remainder)
|
|
1298
|
-
: parseOpencodePlannerJsonLine(remainder);
|
|
1424
|
+
: parseOpencodePlannerJsonLine(remainder, cwd);
|
|
1299
1425
|
const { logFragment, responseFragment, subagentEvents, providerSessionId } = parsedLine;
|
|
1300
|
-
if (tool === 'opencode' && recoveryTracker.consume(parsedLine.recoveryEvents)) {
|
|
1426
|
+
if ((tool === 'opencode' || tool === 'codex') && recoveryTracker.consume(parsedLine.recoveryEvents)) {
|
|
1301
1427
|
responseLines.length = 0;
|
|
1428
|
+
concatenatingResponseGroup = undefined;
|
|
1302
1429
|
firstFinalAnswerTime = null;
|
|
1303
1430
|
}
|
|
1304
|
-
if (tool === 'opencode' && firstFinalAnswerTime === null && parsedLine.hasFinalAnswer) {
|
|
1431
|
+
if ((tool === 'opencode' || tool === 'codex') && firstFinalAnswerTime === null && parsedLine.hasFinalAnswer) {
|
|
1305
1432
|
firstFinalAnswerTime = Date.now();
|
|
1306
1433
|
}
|
|
1307
1434
|
subagentTracker?.handle(subagentEvents);
|
|
@@ -1309,11 +1436,35 @@ const runPlannerPromptOnce = (tool, model, variant, prompt, cwd, options = {}) =
|
|
|
1309
1436
|
bindResolvedProviderSession(providerSessionId);
|
|
1310
1437
|
}
|
|
1311
1438
|
if (logFragment !== null) {
|
|
1312
|
-
|
|
1439
|
+
if (parsedLine.replaceFragment && parsedLine.fragmentGroup) {
|
|
1440
|
+
const index = logIndexesByGroup.get(parsedLine.fragmentGroup);
|
|
1441
|
+
if (index === undefined) {
|
|
1442
|
+
logIndexesByGroup.set(parsedLine.fragmentGroup, logLines.push(logFragment) - 1);
|
|
1443
|
+
}
|
|
1444
|
+
else {
|
|
1445
|
+
logLines[index] = logFragment;
|
|
1446
|
+
}
|
|
1447
|
+
}
|
|
1448
|
+
else if (parsedLine.concatenateFragments && concatenatingLogGroup === parsedLine.fragmentGroup && logLines.length > 0) {
|
|
1449
|
+
logLines[logLines.length - 1] += logFragment;
|
|
1450
|
+
}
|
|
1451
|
+
else {
|
|
1452
|
+
const index = logLines.push(logFragment) - 1;
|
|
1453
|
+
if (parsedLine.fragmentGroup) {
|
|
1454
|
+
logIndexesByGroup.set(parsedLine.fragmentGroup, index);
|
|
1455
|
+
}
|
|
1456
|
+
}
|
|
1457
|
+
concatenatingLogGroup = parsedLine.concatenateFragments ? parsedLine.fragmentGroup ?? null : undefined;
|
|
1313
1458
|
}
|
|
1314
1459
|
const remainderIsHiddenTagLine = isHiddenOpenTag.test(remainder) || isHiddenCloseTag.test(remainder);
|
|
1315
1460
|
if (responseFragment !== null && !remainderIsHiddenTagLine && !insideHiddenBlock) {
|
|
1316
|
-
responseLines.
|
|
1461
|
+
if (parsedLine.concatenateFragments && concatenatingResponseGroup === parsedLine.fragmentGroup && responseLines.length > 0) {
|
|
1462
|
+
responseLines[responseLines.length - 1] += responseFragment;
|
|
1463
|
+
}
|
|
1464
|
+
else {
|
|
1465
|
+
responseLines.push(responseFragment);
|
|
1466
|
+
}
|
|
1467
|
+
concatenatingResponseGroup = parsedLine.concatenateFragments ? parsedLine.fragmentGroup ?? null : undefined;
|
|
1317
1468
|
}
|
|
1318
1469
|
}
|
|
1319
1470
|
opencodeSubagentMonitor?.refresh();
|
|
@@ -1321,9 +1472,10 @@ const runPlannerPromptOnce = (tool, model, variant, prompt, cwd, options = {}) =
|
|
|
1321
1472
|
const errorOutput = Buffer.concat(stderrChunks).toString().trim();
|
|
1322
1473
|
const recoveredResponse = recoveryTracker.getRecoveredResponse();
|
|
1323
1474
|
const parsedResponse = responseLines.join('\n\n').trim();
|
|
1324
|
-
const
|
|
1475
|
+
const isStructuredStream = tool === 'opencode' || tool === 'codex';
|
|
1476
|
+
const streamedOutput = isStructuredStream && recoveryTracker.hasRecoveredFinalAnswer()
|
|
1325
1477
|
? recoveredResponse
|
|
1326
|
-
:
|
|
1478
|
+
: isStructuredStream
|
|
1327
1479
|
? parsedResponse || (rawOutput.startsWith('{') ? '' : rawOutput)
|
|
1328
1480
|
: !rawOutput.startsWith('{')
|
|
1329
1481
|
? rawOutput
|
|
@@ -1379,7 +1531,7 @@ const runPlannerPromptOnce = (tool, model, variant, prompt, cwd, options = {}) =
|
|
|
1379
1531
|
const fallbackError = code === 0
|
|
1380
1532
|
? 'Planner did not return a usable plan.'
|
|
1381
1533
|
: `Process exited with code ${code}`;
|
|
1382
|
-
const error = new Error(output || errorOutput || fallbackError);
|
|
1534
|
+
const error = new Error(output || errorOutput || recoveryTracker.getUnrecoveredError() || fallbackError);
|
|
1383
1535
|
const retryableError = tool === 'opencode' && stdoutChunks.length === 0
|
|
1384
1536
|
? markRetryableOpenCodeDatabaseLock(error)
|
|
1385
1537
|
: error;
|
|
@@ -1393,6 +1545,7 @@ const runPlannerPromptOnce = (tool, model, variant, prompt, cwd, options = {}) =
|
|
|
1393
1545
|
});
|
|
1394
1546
|
child.on('error', err => {
|
|
1395
1547
|
activePlannerProcesses.delete(child);
|
|
1548
|
+
plannerProtocolInterrupts.delete(child);
|
|
1396
1549
|
options.cancellationState?.researchChildren.delete(child);
|
|
1397
1550
|
clearWatchdogTimer();
|
|
1398
1551
|
if (sessionLookupTimer && hasResolvedSessionId) {
|
|
@@ -1702,11 +1855,12 @@ export const prepareLinkedPlanningResearch = async (taskDescription, options = {
|
|
|
1702
1855
|
if (linkedProjects.length === 0) {
|
|
1703
1856
|
return [];
|
|
1704
1857
|
}
|
|
1705
|
-
const tool = options.tool ?? config.tool ?? 'opencode';
|
|
1858
|
+
const tool = requireExecutableAgent(options.tool ?? config.tool ?? 'opencode');
|
|
1706
1859
|
let decision;
|
|
1707
1860
|
const selectionInvocation = createPlanningInvocation(options, 'Linked Research Selection', 'research-selection');
|
|
1708
1861
|
try {
|
|
1709
1862
|
const { output } = await runPlannerPrompt(tool, options.model ?? null, options.variant ?? null, buildLinkedProjectSelectionPrompt(taskDescription, project, linkedProjects), cwd, {
|
|
1863
|
+
skills: options.skills,
|
|
1710
1864
|
agentRunParent: resolvePlannerAgentRunParent(options),
|
|
1711
1865
|
executionContext: options.executionContext,
|
|
1712
1866
|
cancellationState: options.cancellationState,
|
|
@@ -1738,6 +1892,7 @@ export const prepareLinkedPlanningResearch = async (taskDescription, options = {
|
|
|
1738
1892
|
const legacyInvocation = createPlanningInvocation(options, `Linked Research: ${linkedProject.name}`, 'research');
|
|
1739
1893
|
try {
|
|
1740
1894
|
const { output } = await runPlannerPrompt(tool, options.model ?? null, options.variant ?? null, prependSkillPromptBlock(buildLinkedProjectResearchPrompt(project, linkedProject, request), options.skills ?? []), linkedProject.repo_path, {
|
|
1895
|
+
skills: options.skills,
|
|
1741
1896
|
agentRunParent: resolvePlannerAgentRunParent(options),
|
|
1742
1897
|
cancellationState: options.cancellationState,
|
|
1743
1898
|
...(legacyInvocation ? { mainRun: legacyInvocation } : {}),
|
|
@@ -1800,6 +1955,7 @@ export const prepareLinkedPlanningResearch = async (taskDescription, options = {
|
|
|
1800
1955
|
skills: options.skills ?? [],
|
|
1801
1956
|
target: executionTarget,
|
|
1802
1957
|
workload: 'plan',
|
|
1958
|
+
signal: options.cancellationState?.abortController?.signal,
|
|
1803
1959
|
});
|
|
1804
1960
|
const invocationId = createAgentRun({
|
|
1805
1961
|
executionRunId: childContext.runId,
|
|
@@ -1821,6 +1977,7 @@ export const prepareLinkedPlanningResearch = async (taskDescription, options = {
|
|
|
1821
1977
|
role: invocationRun.role,
|
|
1822
1978
|
};
|
|
1823
1979
|
const { output } = await runPlannerPrompt(tool, options.model ?? null, options.variant ?? null, prependSkillPromptBlock(buildLinkedProjectResearchPrompt(project, linkedProject, request), options.skills ?? []), resolvedTarget.workspacePath, {
|
|
1980
|
+
skills: options.skills,
|
|
1824
1981
|
agentRunParent: options.agentRunParent
|
|
1825
1982
|
? { parentType: 'planning', parentId: linkedProject.id, io: options.agentRunParent.io }
|
|
1826
1983
|
: undefined,
|
|
@@ -1867,7 +2024,7 @@ export const prepareLinkedPlanningResearch = async (taskDescription, options = {
|
|
|
1867
2024
|
return linkedResearch.filter((result) => result !== null);
|
|
1868
2025
|
};
|
|
1869
2026
|
export const generatePlanText = (title, description, options = {}) => {
|
|
1870
|
-
const tool = options.tool ?? config.tool ?? 'opencode';
|
|
2027
|
+
const tool = requireExecutableAgent(options.tool ?? config.tool ?? 'opencode');
|
|
1871
2028
|
const project = options.projectId ? getProjectById(options.projectId) : null;
|
|
1872
2029
|
return (async () => {
|
|
1873
2030
|
const invocation = createPlanningInvocation(options, 'Ticket Planning', 'planning');
|
|
@@ -1882,6 +2039,7 @@ export const generatePlanText = (title, description, options = {}) => {
|
|
|
1882
2039
|
});
|
|
1883
2040
|
const { output: plannerOutput, responseTiming: plannerTiming, usageSnapshot, transcriptRuns } = await runPlannerPrompt(tool, options.model ?? null, options.variant ?? null, prependSkillPromptBlock(buildSingleTicketPrompt(title, description, linkedResearchContext, projectMemoryBlock, Boolean(project?.memory_enabled), Boolean(options.ticketId)), options.skills ?? []), options.cwd ?? resolvePlannerCwd(project, options.branch), {
|
|
1884
2041
|
onProgress: options.onProgress,
|
|
2042
|
+
skills: options.skills,
|
|
1885
2043
|
...(options.ticketId && options.io
|
|
1886
2044
|
? {
|
|
1887
2045
|
sessionTracking: {
|
|
@@ -1949,7 +2107,7 @@ export const generatePlanText = (title, description, options = {}) => {
|
|
|
1949
2107
|
})();
|
|
1950
2108
|
};
|
|
1951
2109
|
export const generatePlanningTicketOutline = async (description, options = {}) => {
|
|
1952
|
-
const tool = options.tool ?? config.tool ?? 'opencode';
|
|
2110
|
+
const tool = requireExecutableAgent(options.tool ?? config.tool ?? 'opencode');
|
|
1953
2111
|
const project = options.projectId ? getProjectById(options.projectId) : null;
|
|
1954
2112
|
const invocation = createPlanningInvocation(options, 'Planning Outline', 'planning-outline');
|
|
1955
2113
|
try {
|
|
@@ -1963,6 +2121,7 @@ export const generatePlanningTicketOutline = async (description, options = {}) =
|
|
|
1963
2121
|
...(invocation ? { invocation: { parentType: invocation.parentType, parentId: invocation.parentId, agentRunId: invocation.id } } : {}),
|
|
1964
2122
|
});
|
|
1965
2123
|
const { output } = await runPlannerPrompt(tool, options.model ?? null, options.variant ?? null, prependSkillPromptBlock(buildPlanningAgentOutlinePrompt(description, linkedResearchContext, projectMemoryBlock), options.skills ?? []), options.cwd ?? resolvePlannerCwd(project, options.branch), {
|
|
2124
|
+
skills: options.skills,
|
|
1966
2125
|
agentRunParent: resolvePlannerAgentRunParent(options),
|
|
1967
2126
|
executionContext: options.executionContext,
|
|
1968
2127
|
...plannerExecutionOptions(options),
|
|
@@ -1978,7 +2137,7 @@ export const generatePlanningTicketOutline = async (description, options = {}) =
|
|
|
1978
2137
|
}
|
|
1979
2138
|
};
|
|
1980
2139
|
export const expandPlanningTicketOutline = async (description, outline, options = {}) => {
|
|
1981
|
-
const tool = options.tool ?? config.tool ?? 'opencode';
|
|
2140
|
+
const tool = requireExecutableAgent(options.tool ?? config.tool ?? 'opencode');
|
|
1982
2141
|
const project = options.projectId ? getProjectById(options.projectId) : null;
|
|
1983
2142
|
const invocation = createPlanningInvocation(options, 'Planning Expansion', 'planning-expansion');
|
|
1984
2143
|
try {
|
|
@@ -1992,6 +2151,7 @@ export const expandPlanningTicketOutline = async (description, outline, options
|
|
|
1992
2151
|
...(invocation ? { invocation: { parentType: invocation.parentType, parentId: invocation.parentId, agentRunId: invocation.id } } : {}),
|
|
1993
2152
|
});
|
|
1994
2153
|
const { output } = await runPlannerPrompt(tool, options.model ?? null, options.variant ?? null, prependSkillPromptBlock(buildPlanningAgentExpansionPrompt(description, outline, linkedResearchContext, projectMemoryBlock), options.skills ?? []), options.cwd ?? resolvePlannerCwd(project, options.branch), {
|
|
2154
|
+
skills: options.skills,
|
|
1995
2155
|
agentRunParent: resolvePlannerAgentRunParent(options),
|
|
1996
2156
|
executionContext: options.executionContext,
|
|
1997
2157
|
...plannerExecutionOptions(options),
|
|
@@ -2056,7 +2216,7 @@ export const startPlan = (ticket, io, options = {}) => {
|
|
|
2056
2216
|
};
|
|
2057
2217
|
const targetBundleId = options.targetBundleId === undefined ? ticket.worktree_bundle_id : options.targetBundleId;
|
|
2058
2218
|
const targetBranch = options.branch === undefined ? resolveTicketBranch(ticket) : options.branch;
|
|
2059
|
-
const runTool = resolveTicketTool(ticket, config.tool ?? 'opencode');
|
|
2219
|
+
const runTool = requireExecutableAgent(resolveTicketTool(ticket, config.tool ?? 'opencode'));
|
|
2060
2220
|
const runSkills = options.skills ?? ticket.skills ?? [];
|
|
2061
2221
|
const executionRun = createExecutionRun({
|
|
2062
2222
|
projectId: project.id,
|
|
@@ -2087,7 +2247,11 @@ export const startPlan = (ticket, io, options = {}) => {
|
|
|
2087
2247
|
projectId: executionRun.project_id,
|
|
2088
2248
|
kind: executionRun.kind,
|
|
2089
2249
|
};
|
|
2090
|
-
const cancellationState = {
|
|
2250
|
+
const cancellationState = {
|
|
2251
|
+
researchChildren: new Set(),
|
|
2252
|
+
stopRequested: false,
|
|
2253
|
+
abortController: new AbortController(),
|
|
2254
|
+
};
|
|
2091
2255
|
activePlanProcesses.set(ticket.id, cancellationState);
|
|
2092
2256
|
let queuedJob;
|
|
2093
2257
|
try {
|
|
@@ -2153,6 +2317,7 @@ export const startPlan = (ticket, io, options = {}) => {
|
|
|
2153
2317
|
skills: runSkills,
|
|
2154
2318
|
target: executionTarget,
|
|
2155
2319
|
workload: 'plan',
|
|
2320
|
+
signal: cancellationState.abortController?.signal,
|
|
2156
2321
|
});
|
|
2157
2322
|
const planningSessionId = options.providerContinuation === 'fresh' ? null : ticket.planning_session_id;
|
|
2158
2323
|
if (planningSessionId) {
|
|
@@ -2163,7 +2328,7 @@ export const startPlan = (ticket, io, options = {}) => {
|
|
|
2163
2328
|
parentId: ticket.id,
|
|
2164
2329
|
sessionId: planningSessionId,
|
|
2165
2330
|
agent: runTool,
|
|
2166
|
-
modelProvider: runTool
|
|
2331
|
+
modelProvider: getAgentModelProvider(runTool, ticket.model),
|
|
2167
2332
|
authority: workloadEnvironment.runAuthority,
|
|
2168
2333
|
});
|
|
2169
2334
|
}
|
|
@@ -2202,7 +2367,7 @@ export const startPlan = (ticket, io, options = {}) => {
|
|
|
2202
2367
|
}, io);
|
|
2203
2368
|
return;
|
|
2204
2369
|
}
|
|
2205
|
-
const resolvedTool = resolveTicketTool(ticket, config.tool ?? 'opencode');
|
|
2370
|
+
const resolvedTool = requireExecutableAgent(resolveTicketTool(ticket, config.tool ?? 'opencode'));
|
|
2206
2371
|
if (resolvedTool === 'opencode') {
|
|
2207
2372
|
const freshTicket = getTicket(ticket.id);
|
|
2208
2373
|
if (freshTicket?.planning_session_id) {
|
|
@@ -2215,7 +2380,7 @@ export const startPlan = (ticket, io, options = {}) => {
|
|
|
2215
2380
|
}
|
|
2216
2381
|
}
|
|
2217
2382
|
}
|
|
2218
|
-
else if (resolvedTool === 'claude' && planned.usageSnapshot) {
|
|
2383
|
+
else if ((resolvedTool === 'claude' || resolvedTool === 'codex') && planned.usageSnapshot) {
|
|
2219
2384
|
const freshTicket = getTicket(ticket.id);
|
|
2220
2385
|
if (freshTicket) {
|
|
2221
2386
|
storeTicketUsageSnapshotDirect(freshTicket.id, planned.usageSnapshot);
|
|
@@ -2409,6 +2574,7 @@ export const stopPlan = async (ticketId) => {
|
|
|
2409
2574
|
return false;
|
|
2410
2575
|
}
|
|
2411
2576
|
state.stopRequested = true;
|
|
2577
|
+
state.abortController?.abort();
|
|
2412
2578
|
const children = [...state.researchChildren];
|
|
2413
2579
|
await stopPlannerProcesses(children);
|
|
2414
2580
|
return true;
|
|
@@ -2416,6 +2582,7 @@ export const stopPlan = async (ticketId) => {
|
|
|
2416
2582
|
export const stopAllPlanAgents = async () => {
|
|
2417
2583
|
for (const state of activePlanProcesses.values()) {
|
|
2418
2584
|
state.stopRequested = true;
|
|
2585
|
+
state.abortController?.abort();
|
|
2419
2586
|
}
|
|
2420
2587
|
await stopPlannerProcesses([...activePlannerProcesses]);
|
|
2421
2588
|
};
|