@straiffi/archon 1.7.2 → 1.7.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/client/assets/ActivityView-DTEenQas.js +1 -0
- package/dist/client/assets/GitHubActionsDialog-BKWHonUS.js +1 -0
- package/dist/client/assets/TestsDialog-cBaoffCs.js +4 -0
- package/dist/client/assets/{architectureDiagram-3BPJPVTR-Do9nbC8v.js → architectureDiagram-3BPJPVTR-BzzGotac.js} +1 -1
- package/dist/client/assets/{blockDiagram-GPEHLZMM-DGGOLHF8.js → blockDiagram-GPEHLZMM-DIcqLHKg.js} +1 -1
- package/dist/client/assets/{c4Diagram-AAUBKEIU-Bz7tQybs.js → c4Diagram-AAUBKEIU-Hc1Sqmhs.js} +1 -1
- package/dist/client/assets/channel-Cym17waa.js +1 -0
- package/dist/client/assets/{chunk-2J33WTMH-CJO-GmWJ.js → chunk-2J33WTMH-CWSwjsgk.js} +1 -1
- package/dist/client/assets/{chunk-3OPIFGDE-DPAVagpC.js → chunk-3OPIFGDE-BnX3DljN.js} +1 -1
- package/dist/client/assets/{chunk-5ZQYHXKU-Cof75Mu7.js → chunk-5ZQYHXKU-EyyJlI-d.js} +1 -1
- package/dist/client/assets/{chunk-727SXJPM-COuPqQ8_.js → chunk-727SXJPM-Ci6CfxWj.js} +1 -1
- package/dist/client/assets/{chunk-AQP2D5EJ-CFj5KabW.js → chunk-AQP2D5EJ-RKZNsJTm.js} +1 -1
- package/dist/client/assets/{chunk-CSCIHK7Q-C4M6w5cT.js → chunk-CSCIHK7Q-DBf0Euoj.js} +1 -1
- package/dist/client/assets/{chunk-KSCS5N6A-ByaiwVue.js → chunk-KSCS5N6A-BmLQI_2S.js} +1 -1
- package/dist/client/assets/{chunk-L5ZTLDWV-Cx5jeot9.js → chunk-L5ZTLDWV-DKwVAb8G.js} +1 -1
- package/dist/client/assets/{chunk-LZXEDZCA-DmGtztud.js → chunk-LZXEDZCA-axotKkbz.js} +2 -2
- package/dist/client/assets/{chunk-ND2GUHAM-i3yuspqL.js → chunk-ND2GUHAM-BBlJ4nXC.js} +1 -1
- package/dist/client/assets/{chunk-NZK2D7GU-CQ4E_jP4.js → chunk-NZK2D7GU-BKJGoZZt.js} +1 -1
- package/dist/client/assets/{chunk-O5CBEL6O-D2g4VDCd.js → chunk-O5CBEL6O-C-Ghigo1.js} +1 -1
- package/dist/client/assets/{chunk-WU5MYG2G-exIu-zQ2.js → chunk-WU5MYG2G-CCzVWYcd.js} +1 -1
- package/dist/client/assets/classDiagram-4FO5ZUOK-BcigvvIC.js +1 -0
- package/dist/client/assets/classDiagram-v2-Q7XG4LA2-3AdSuE0N.js +1 -0
- package/dist/client/assets/{dagre-BM42HDAG-DvF75yLZ.js → dagre-BM42HDAG-rwIdPcjI.js} +1 -1
- package/dist/client/assets/{diagram-2AECGRRQ-DFv0HxLL.js → diagram-2AECGRRQ-DJWxOQsg.js} +1 -1
- package/dist/client/assets/{diagram-5GNKFQAL-C_LRir0-.js → diagram-5GNKFQAL-C-mQeFtd.js} +1 -1
- package/dist/client/assets/{diagram-KO2AKTUF-DGZxRDRy.js → diagram-KO2AKTUF-BAu6u4sR.js} +1 -1
- package/dist/client/assets/{diagram-LMA3HP47-UXt0uti4.js → diagram-LMA3HP47-U6CbvBn0.js} +1 -1
- package/dist/client/assets/{diagram-OG6HWLK6-CFbZS4n5.js → diagram-OG6HWLK6-DNTwFcs1.js} +1 -1
- package/dist/client/assets/{erDiagram-TEJ5UH35-CfAwZDdf.js → erDiagram-TEJ5UH35-DaHX6Xw5.js} +1 -1
- package/dist/client/assets/{flowDiagram-I6XJVG4X-Cdgi5z3n.js → flowDiagram-I6XJVG4X-B9hKqL2l.js} +1 -1
- package/dist/client/assets/{ganttDiagram-6RSMTGT7-DOrkFkhu.js → ganttDiagram-6RSMTGT7-BQ1HPHVO.js} +1 -1
- package/dist/client/assets/{gitGraphDiagram-PVQCEYII-cEox0peD.js → gitGraphDiagram-PVQCEYII-BBRcsmMK.js} +1 -1
- package/dist/client/assets/index-CEMaJCPS.js +273 -0
- package/dist/client/assets/index-lWftq65U.css +2 -0
- package/dist/client/assets/{infoDiagram-5YYISTIA-gm51u2Nn.js → infoDiagram-5YYISTIA-DUoNiSGC.js} +1 -1
- package/dist/client/assets/{ishikawaDiagram-YF4QCWOH-CjnoOIja.js → ishikawaDiagram-YF4QCWOH-DJN1y2w8.js} +1 -1
- package/dist/client/assets/{journeyDiagram-JHISSGLW-Dlg4DsiO.js → journeyDiagram-JHISSGLW-BxLLMT70.js} +1 -1
- package/dist/client/assets/{kanban-definition-UN3LZRKU-BU0XZaSd.js → kanban-definition-UN3LZRKU-BdCPistJ.js} +1 -1
- package/dist/client/assets/{line-Bert22-_.js → line-4mIgXsZd.js} +1 -1
- package/dist/client/assets/{mermaid-parser.core-BvQSGDmL.js → mermaid-parser.core-Pu1QGWJ-.js} +1 -1
- package/dist/client/assets/{mermaid.core--qSAHJRj.js → mermaid.core-DnH9DrgZ.js} +3 -3
- package/dist/client/assets/{mindmap-definition-RKZ34NQL-BgFIvWWD.js → mindmap-definition-RKZ34NQL-DqE4ba3C.js} +1 -1
- package/dist/client/assets/{pieDiagram-4H26LBE5-DGcbXD0M.js → pieDiagram-4H26LBE5-Crjy9ejf.js} +1 -1
- package/dist/client/assets/{quadrantDiagram-W4KKPZXB-ClkBUeia.js → quadrantDiagram-W4KKPZXB-BUSZ2VB7.js} +1 -1
- package/dist/client/assets/{requirementDiagram-4Y6WPE33-B8CwGToU.js → requirementDiagram-4Y6WPE33-CBhFKEoV.js} +1 -1
- package/dist/client/assets/{sankeyDiagram-5OEKKPKP-DTk3jL6B.js → sankeyDiagram-5OEKKPKP-CgdbY41v.js} +1 -1
- package/dist/client/assets/{sequenceDiagram-3UESZ5HK-BQVrcnKf.js → sequenceDiagram-3UESZ5HK-hkp_H7AE.js} +1 -1
- package/dist/client/assets/{stateDiagram-AJRCARHV-DD4yMZPB.js → stateDiagram-AJRCARHV-C6x45RWp.js} +1 -1
- package/dist/client/assets/stateDiagram-v2-BHNVJYJU-DVzPjRPN.js +1 -0
- package/dist/client/assets/{timeline-definition-PNZ67QCA-BnCBVqcd.js → timeline-definition-PNZ67QCA-CjnZWttQ.js} +1 -1
- package/dist/client/assets/{vennDiagram-CIIHVFJN-BDmLMNXS.js → vennDiagram-CIIHVFJN-DU5ZyYju.js} +1 -1
- package/dist/client/assets/{wardleyDiagram-YWT4CUSO-DSLuQiEv.js → wardleyDiagram-YWT4CUSO-CaCEnCB0.js} +1 -1
- package/dist/client/assets/{xychartDiagram-2RQKCTM6-DAq_LA4r.js → xychartDiagram-2RQKCTM6-Ce3xa37U.js} +1 -1
- package/dist/client/index.html +2 -2
- package/dist/server/db.js +471 -39
- package/dist/server/db.js.map +1 -1
- package/dist/server/index.js +1256 -214
- package/dist/server/index.js.map +1 -1
- package/dist/server/lib/agent.js +228 -71
- package/dist/server/lib/agent.js.map +1 -1
- package/dist/server/lib/agentRuns.js +205 -38
- package/dist/server/lib/agentRuns.js.map +1 -1
- package/dist/server/lib/automationProgression.js +464 -0
- package/dist/server/lib/automationProgression.js.map +1 -0
- package/dist/server/lib/automationReconciliation.js +498 -0
- package/dist/server/lib/automationReconciliation.js.map +1 -0
- package/dist/server/lib/automationStageDetails.js +232 -0
- package/dist/server/lib/automationStageDetails.js.map +1 -0
- package/dist/server/lib/buildOpenQuestionOperations.js +223 -0
- package/dist/server/lib/buildOpenQuestionOperations.js.map +1 -0
- package/dist/server/lib/buildOpenQuestions.js +44 -0
- package/dist/server/lib/buildOpenQuestions.js.map +1 -1
- package/dist/server/lib/buildSequences.js +130 -46
- package/dist/server/lib/buildSequences.js.map +1 -1
- package/dist/server/lib/bundleReviewOperations.js +82 -9
- package/dist/server/lib/bundleReviewOperations.js.map +1 -1
- package/dist/server/lib/chatOperations.js +31 -0
- package/dist/server/lib/chatOperations.js.map +1 -1
- package/dist/server/lib/executionReconciliation.js +518 -0
- package/dist/server/lib/executionReconciliation.js.map +1 -0
- package/dist/server/lib/executionRunRetention.js +141 -0
- package/dist/server/lib/executionRunRetention.js.map +1 -0
- package/dist/server/lib/executionRuns.js +1264 -0
- package/dist/server/lib/executionRuns.js.map +1 -0
- package/dist/server/lib/git.js +385 -6
- package/dist/server/lib/git.js.map +1 -1
- package/dist/server/lib/integrations/github.js +43 -0
- package/dist/server/lib/integrations/github.js.map +1 -1
- package/dist/server/lib/integrations/githubActions.js +1 -0
- package/dist/server/lib/integrations/githubActions.js.map +1 -1
- package/dist/server/lib/integrations/githubActionsSessions.js +337 -114
- package/dist/server/lib/integrations/githubActionsSessions.js.map +1 -1
- package/dist/server/lib/projectMemorySelections.js +7 -3
- package/dist/server/lib/projectMemorySelections.js.map +1 -1
- package/dist/server/lib/shutdown.js +2 -2
- package/dist/server/lib/shutdown.js.map +1 -1
- package/dist/server/lib/specArtifact.js +3 -0
- package/dist/server/lib/specArtifact.js.map +1 -1
- package/dist/server/lib/specFormatting.js +1 -1
- package/dist/server/lib/specFormatting.js.map +1 -1
- package/dist/server/lib/specOperations.js +31 -0
- package/dist/server/lib/specOperations.js.map +1 -1
- package/dist/server/lib/specReviewContext.js +44 -14
- package/dist/server/lib/specReviewContext.js.map +1 -1
- package/dist/server/lib/specReviewDraft.js +3 -2
- package/dist/server/lib/specReviewDraft.js.map +1 -1
- package/dist/server/lib/specReviewOperations.js +44 -7
- package/dist/server/lib/specReviewOperations.js.map +1 -1
- package/dist/server/lib/specReviewValidation.js +217 -0
- package/dist/server/lib/specReviewValidation.js.map +1 -0
- package/dist/server/lib/specReviews.js +30 -2
- package/dist/server/lib/specReviews.js.map +1 -1
- package/dist/server/lib/specs.js +18 -1
- package/dist/server/lib/specs.js.map +1 -1
- package/dist/server/lib/stageSnapshots.js +197 -0
- package/dist/server/lib/stageSnapshots.js.map +1 -0
- package/dist/server/lib/testSessions.js +164 -19
- package/dist/server/lib/testSessions.js.map +1 -1
- package/dist/server/lib/ticketAutomation.js +80 -4
- package/dist/server/lib/ticketAutomation.js.map +1 -1
- package/dist/server/lib/ticketAutomationCommit.js +466 -91
- package/dist/server/lib/ticketAutomationCommit.js.map +1 -1
- package/dist/server/lib/ticketFollowUpOperations.js +214 -20
- package/dist/server/lib/ticketFollowUpOperations.js.map +1 -1
- package/dist/server/lib/ticketRunOperations.js +51 -6
- package/dist/server/lib/ticketRunOperations.js.map +1 -1
- package/dist/server/lib/ticketUndo.js +77 -168
- package/dist/server/lib/ticketUndo.js.map +1 -1
- package/dist/server/lib/ticketWorkflowOperations.js +132 -28
- package/dist/server/lib/ticketWorkflowOperations.js.map +1 -1
- package/dist/server/lib/tickets.js +41 -27
- package/dist/server/lib/tickets.js.map +1 -1
- package/dist/server/lib/transcriptRuns.js +3 -3
- package/dist/server/lib/transcriptRuns.js.map +1 -1
- package/dist/server/lib/turnExecutionErrors.js +12 -0
- package/dist/server/lib/turnExecutionErrors.js.map +1 -0
- package/dist/server/lib/types.js +57 -1
- package/dist/server/lib/types.js.map +1 -1
- package/dist/server/workers/build.js +596 -184
- package/dist/server/workers/build.js.map +1 -1
- package/dist/server/workers/chat.js +261 -130
- package/dist/server/workers/chat.js.map +1 -1
- package/dist/server/workers/followUp.js +716 -203
- package/dist/server/workers/followUp.js.map +1 -1
- package/dist/server/workers/plan.js +527 -188
- package/dist/server/workers/plan.js.map +1 -1
- package/dist/server/workers/planFollowUp.js +231 -69
- package/dist/server/workers/planFollowUp.js.map +1 -1
- package/dist/server/workers/review.js +790 -297
- package/dist/server/workers/review.js.map +1 -1
- package/dist/server/workers/specReview.js +211 -45
- package/dist/server/workers/specReview.js.map +1 -1
- package/dist/server/workers/specSession.js +425 -252
- package/dist/server/workers/specSession.js.map +1 -1
- package/package.json +1 -1
- package/dist/client/assets/GitHubActionsDialog-DAD5REmY.js +0 -1
- package/dist/client/assets/TestsDialog-B5NVrroq.js +0 -4
- package/dist/client/assets/TicketChangesModal-By-_gTGd.js +0 -1
- package/dist/client/assets/channel-Dd5Len0X.js +0 -1
- package/dist/client/assets/classDiagram-4FO5ZUOK-B7KUg6r8.js +0 -1
- package/dist/client/assets/classDiagram-v2-Q7XG4LA2-CQm-z5c4.js +0 -1
- package/dist/client/assets/index-BHq6-Eir.js +0 -270
- package/dist/client/assets/index-BxTc5qQT.css +0 -2
- package/dist/client/assets/stateDiagram-v2-BHNVJYJU-C8yO6POT.js +0 -1
package/dist/server/lib/agent.js
CHANGED
|
@@ -11,7 +11,7 @@ import { appendClaudeHeadlessPlanPrompt, buildClaudeHeadlessPlanArgs } from './p
|
|
|
11
11
|
import { formatGenericToolCall } from './genericToolCall.js';
|
|
12
12
|
import { getSpecSession, updateSpecSessionResumeId, updateSpecSessionStatus, updateSpecSessionTitle, updateSpecSessionUsageSnapshot } from './specs.js';
|
|
13
13
|
import { updateSpecReviewRunStatus, updateSpecReviewRunStreaming, updateSpecReviewRunUsage } from './specReviews.js';
|
|
14
|
-
import { createAgentRun, emitAgentRunsUpdated, finalizeAgentRun, getNextAgentRunIndex, listAgentRunsForParent, updateAgentRunLabel, updateAgentRunSessionId, updateAgentRunStatus } from './agentRuns.js';
|
|
14
|
+
import { createAgentRun, emitAgentRunsUpdated, finalizeAgentRun, getNextAgentRunIndex, listAgentRunsForExecutionRun, listAgentRunsForParent, updateAgentRunLabel, updateAgentRunSessionId, updateAgentRunStatus } from './agentRuns.js';
|
|
15
15
|
import { resolveOpencodeDbPath } from './runtimePaths.js';
|
|
16
16
|
import { markTicketDescriptionVisibleInBundle } from './ticketMessages.js';
|
|
17
17
|
import { getTicket } from './tickets.js';
|
|
@@ -1320,12 +1320,19 @@ const appendOpencodeTranscriptLine = ({ parsed, logLines, responseLines, recover
|
|
|
1320
1320
|
}
|
|
1321
1321
|
return shouldResetResponse;
|
|
1322
1322
|
};
|
|
1323
|
-
export const createSubagentRunTracker = ({ parentType, parentId, io, mainRun, }) => {
|
|
1323
|
+
export const createSubagentRunTracker = ({ parentType, parentId, io, mainRun, executionContext, deferMainFinalization = false, }) => {
|
|
1324
1324
|
const trackedRuns = [];
|
|
1325
|
-
let nextRunIndex = Math.max(getNextAgentRunIndex(parentType, parentId), mainRun ? mainRun.runIndex + 1 : 1);
|
|
1325
|
+
let nextRunIndex = Math.max(executionContext ? getNextAgentRunIndex(executionContext.runId) : getNextAgentRunIndex(parentType, parentId), mainRun ? mainRun.runIndex + 1 : 1);
|
|
1326
1326
|
const emitUpdate = () => {
|
|
1327
1327
|
emitAgentRunsUpdated(io, parentType, parentId);
|
|
1328
1328
|
};
|
|
1329
|
+
const updateMain = (log, response) => {
|
|
1330
|
+
if (!mainRun) {
|
|
1331
|
+
return;
|
|
1332
|
+
}
|
|
1333
|
+
updateAgentRunStatus(mainRun.id, 'running', log, response);
|
|
1334
|
+
emitUpdate();
|
|
1335
|
+
};
|
|
1329
1336
|
const findRun = (callId, sessionId) => {
|
|
1330
1337
|
if (callId) {
|
|
1331
1338
|
const callRun = trackedRuns.find(run => run.callId === callId);
|
|
@@ -1368,11 +1375,12 @@ export const createSubagentRunTracker = ({ parentType, parentId, io, mainRun, })
|
|
|
1368
1375
|
emitUpdate();
|
|
1369
1376
|
continue;
|
|
1370
1377
|
}
|
|
1371
|
-
const runIndex = Math.max(getNextAgentRunIndex(parentType, parentId), nextRunIndex);
|
|
1378
|
+
const runIndex = Math.max(executionContext ? getNextAgentRunIndex(executionContext.runId) : getNextAgentRunIndex(parentType, parentId), nextRunIndex);
|
|
1372
1379
|
const id = createAgentRun({
|
|
1380
|
+
...(executionContext ? { executionRunId: executionContext.runId } : {}),
|
|
1373
1381
|
parentType,
|
|
1374
1382
|
parentId,
|
|
1375
|
-
runIndex,
|
|
1383
|
+
...(!executionContext ? { runIndex } : {}),
|
|
1376
1384
|
label: event.label?.trim() || 'Subagent',
|
|
1377
1385
|
role: 'subagent',
|
|
1378
1386
|
});
|
|
@@ -1468,18 +1476,26 @@ export const createSubagentRunTracker = ({ parentType, parentId, io, mainRun, })
|
|
|
1468
1476
|
run.status = status;
|
|
1469
1477
|
finalizeAgentRun(run.id, status, run.response || null);
|
|
1470
1478
|
}
|
|
1471
|
-
|
|
1479
|
+
if (mainRun) {
|
|
1480
|
+
updateMain(parentLog, parentResponse);
|
|
1481
|
+
if (!deferMainFinalization) {
|
|
1482
|
+
finalizeAgentRun(mainRun.id, status, parentResponse);
|
|
1483
|
+
}
|
|
1484
|
+
}
|
|
1485
|
+
if (!mainRun) {
|
|
1486
|
+
emitUpdate();
|
|
1487
|
+
}
|
|
1472
1488
|
const trackedIds = new Set(trackedRuns.map(run => run.id));
|
|
1473
|
-
const persistedRuns =
|
|
1489
|
+
const persistedRuns = (executionContext
|
|
1490
|
+
? listAgentRunsForExecutionRun(executionContext.runId)
|
|
1491
|
+
: listAgentRunsForParent(parentType, parentId))
|
|
1474
1492
|
.filter(run => trackedIds.has(run.id) || run.id === mainRun?.id);
|
|
1475
|
-
const persistedIds = new Set(persistedRuns.map(run => run.id));
|
|
1476
1493
|
const timestamp = new Date().toISOString();
|
|
1477
1494
|
for (const run of trackedRuns) {
|
|
1478
|
-
|
|
1479
|
-
|
|
1480
|
-
}
|
|
1481
|
-
persistedRuns.push({
|
|
1495
|
+
const persistedRun = persistedRuns.find(candidate => candidate.id === run.id);
|
|
1496
|
+
const snapshotRun = {
|
|
1482
1497
|
id: run.id,
|
|
1498
|
+
execution_run_id: persistedRun?.execution_run_id ?? executionContext?.runId ?? null,
|
|
1483
1499
|
parent_type: parentType,
|
|
1484
1500
|
parent_id: parentId,
|
|
1485
1501
|
run_index: run.runIndex,
|
|
@@ -1489,15 +1505,25 @@ export const createSubagentRunTracker = ({ parentType, parentId, io, mainRun, })
|
|
|
1489
1505
|
agent_log: run.log || null,
|
|
1490
1506
|
streaming_response: null,
|
|
1491
1507
|
response_text: run.response || null,
|
|
1508
|
+
failure_message: persistedRun?.failure_message ?? null,
|
|
1492
1509
|
session_id: run.sessionId,
|
|
1493
|
-
|
|
1494
|
-
|
|
1495
|
-
|
|
1510
|
+
completed_at: persistedRun?.completed_at ?? timestamp,
|
|
1511
|
+
created_at: persistedRun?.created_at ?? run.createdAt,
|
|
1512
|
+
updated_at: persistedRun?.updated_at ?? timestamp,
|
|
1513
|
+
};
|
|
1514
|
+
const persistedRunIndex = persistedRuns.findIndex(candidate => candidate.id === run.id);
|
|
1515
|
+
if (persistedRunIndex >= 0) {
|
|
1516
|
+
persistedRuns[persistedRunIndex] = snapshotRun;
|
|
1517
|
+
}
|
|
1518
|
+
else {
|
|
1519
|
+
persistedRuns.push(snapshotRun);
|
|
1520
|
+
}
|
|
1496
1521
|
}
|
|
1497
1522
|
if (mainRun) {
|
|
1498
1523
|
const persistedMainRun = persistedRuns.find(run => run.id === mainRun.id);
|
|
1499
1524
|
const mainSnapshotRun = {
|
|
1500
1525
|
id: mainRun.id,
|
|
1526
|
+
execution_run_id: persistedMainRun?.execution_run_id ?? null,
|
|
1501
1527
|
parent_type: parentType,
|
|
1502
1528
|
parent_id: parentId,
|
|
1503
1529
|
run_index: mainRun.runIndex,
|
|
@@ -1507,7 +1533,9 @@ export const createSubagentRunTracker = ({ parentType, parentId, io, mainRun, })
|
|
|
1507
1533
|
agent_log: parentLog,
|
|
1508
1534
|
streaming_response: null,
|
|
1509
1535
|
response_text: parentResponse,
|
|
1536
|
+
failure_message: persistedMainRun?.failure_message ?? null,
|
|
1510
1537
|
session_id: persistedMainRun?.session_id ?? null,
|
|
1538
|
+
completed_at: persistedMainRun?.completed_at ?? timestamp,
|
|
1511
1539
|
created_at: persistedMainRun?.created_at ?? timestamp,
|
|
1512
1540
|
updated_at: persistedMainRun?.updated_at ?? timestamp,
|
|
1513
1541
|
};
|
|
@@ -1522,6 +1550,7 @@ export const createSubagentRunTracker = ({ parentType, parentId, io, mainRun, })
|
|
|
1522
1550
|
else {
|
|
1523
1551
|
persistedRuns.push({
|
|
1524
1552
|
id: `${parentType}:${parentId}:main`,
|
|
1553
|
+
execution_run_id: null,
|
|
1525
1554
|
parent_type: parentType,
|
|
1526
1555
|
parent_id: parentId,
|
|
1527
1556
|
run_index: 0,
|
|
@@ -1531,14 +1560,22 @@ export const createSubagentRunTracker = ({ parentType, parentId, io, mainRun, })
|
|
|
1531
1560
|
agent_log: parentLog,
|
|
1532
1561
|
streaming_response: null,
|
|
1533
1562
|
response_text: parentResponse,
|
|
1563
|
+
failure_message: null,
|
|
1534
1564
|
session_id: null,
|
|
1565
|
+
completed_at: timestamp,
|
|
1535
1566
|
created_at: timestamp,
|
|
1536
1567
|
updated_at: timestamp,
|
|
1537
1568
|
});
|
|
1538
1569
|
}
|
|
1539
1570
|
return createTranscriptRunSnapshots(persistedRuns.sort((left, right) => left.run_index - right.run_index));
|
|
1540
1571
|
};
|
|
1541
|
-
|
|
1572
|
+
const setMainSessionId = (sessionId) => {
|
|
1573
|
+
const normalized = sessionId?.trim();
|
|
1574
|
+
if (mainRun && normalized) {
|
|
1575
|
+
updateAgentRunSessionId(mainRun.id, normalized);
|
|
1576
|
+
}
|
|
1577
|
+
};
|
|
1578
|
+
return { applySnapshot, handle, finalize, setMainSessionId, updateMain };
|
|
1542
1579
|
};
|
|
1543
1580
|
export const reconstructOpencodeSubagentTranscript = (parts, cwd) => {
|
|
1544
1581
|
let log = '';
|
|
@@ -1729,6 +1766,22 @@ const untrackChatProcess = (chatSessionId, state) => {
|
|
|
1729
1766
|
state.metadataRefresher?.stop();
|
|
1730
1767
|
state.metadataRefresher = null;
|
|
1731
1768
|
};
|
|
1769
|
+
export const registerChatProcessPlaceholder = (chatSessionId) => {
|
|
1770
|
+
const state = {
|
|
1771
|
+
child: null,
|
|
1772
|
+
researchChildren: new Set(),
|
|
1773
|
+
stopRequested: false,
|
|
1774
|
+
metadataRefresher: null,
|
|
1775
|
+
};
|
|
1776
|
+
activeChatProcesses.set(chatSessionId, state);
|
|
1777
|
+
return state;
|
|
1778
|
+
};
|
|
1779
|
+
export const untrackChatProcessById = (chatSessionId) => {
|
|
1780
|
+
const state = activeChatProcesses.get(chatSessionId);
|
|
1781
|
+
if (state) {
|
|
1782
|
+
untrackChatProcess(chatSessionId, state);
|
|
1783
|
+
}
|
|
1784
|
+
};
|
|
1732
1785
|
const untrackSpecProcess = (specSessionId, state) => {
|
|
1733
1786
|
if (activeSpecProcesses.get(specSessionId) === state) {
|
|
1734
1787
|
activeSpecProcesses.delete(specSessionId);
|
|
@@ -1744,6 +1797,7 @@ const untrackSpecProcess = (specSessionId, state) => {
|
|
|
1744
1797
|
export const registerSpecProcessPlaceholder = (specSessionId) => {
|
|
1745
1798
|
const state = {
|
|
1746
1799
|
child: null,
|
|
1800
|
+
researchChildren: new Set(),
|
|
1747
1801
|
stopRequested: false,
|
|
1748
1802
|
metadataRefresher: null,
|
|
1749
1803
|
};
|
|
@@ -1820,11 +1874,14 @@ export const stopReviewAgent = async (ticketId) => {
|
|
|
1820
1874
|
};
|
|
1821
1875
|
export const stopChatAgent = async (chatSessionId) => {
|
|
1822
1876
|
const state = activeChatProcesses.get(chatSessionId);
|
|
1823
|
-
if (!state
|
|
1877
|
+
if (!state) {
|
|
1824
1878
|
return false;
|
|
1825
1879
|
}
|
|
1826
1880
|
state.stopRequested = true;
|
|
1827
1881
|
state.metadataRefresher?.stop();
|
|
1882
|
+
if (!state.child) {
|
|
1883
|
+
return true;
|
|
1884
|
+
}
|
|
1828
1885
|
killProcess(state.child, 'SIGTERM');
|
|
1829
1886
|
await waitForProcessExit(state.child, 5000);
|
|
1830
1887
|
if (isProcessAlive(state.child)) {
|
|
@@ -1840,20 +1897,22 @@ export const stopSpecAgent = async (specSessionId) => {
|
|
|
1840
1897
|
}
|
|
1841
1898
|
state.stopRequested = true;
|
|
1842
1899
|
state.metadataRefresher?.stop();
|
|
1843
|
-
|
|
1844
|
-
|
|
1845
|
-
|
|
1846
|
-
|
|
1847
|
-
|
|
1848
|
-
if (!state.child) {
|
|
1900
|
+
const children = [...state.researchChildren];
|
|
1901
|
+
if (state.child) {
|
|
1902
|
+
children.push(state.child);
|
|
1903
|
+
}
|
|
1904
|
+
if (children.length === 0) {
|
|
1849
1905
|
return true;
|
|
1850
1906
|
}
|
|
1851
|
-
|
|
1852
|
-
|
|
1853
|
-
|
|
1854
|
-
|
|
1855
|
-
|
|
1907
|
+
for (const child of children) {
|
|
1908
|
+
killProcess(child, 'SIGTERM');
|
|
1909
|
+
}
|
|
1910
|
+
await Promise.all(children.map(child => waitForProcessExit(child, 5000)));
|
|
1911
|
+
const aliveChildren = children.filter(isProcessAlive);
|
|
1912
|
+
for (const child of aliveChildren) {
|
|
1913
|
+
killProcess(child, 'SIGKILL');
|
|
1856
1914
|
}
|
|
1915
|
+
await Promise.all(aliveChildren.map(child => waitForProcessExit(child, 1000)));
|
|
1857
1916
|
return true;
|
|
1858
1917
|
};
|
|
1859
1918
|
export const stopSpecReviewAgent = async (specReviewRunId) => {
|
|
@@ -1871,7 +1930,7 @@ export const stopSpecReviewAgent = async (specReviewRunId) => {
|
|
|
1871
1930
|
}
|
|
1872
1931
|
return true;
|
|
1873
1932
|
};
|
|
1874
|
-
export const runAgent = ({ ticketId, tool, prompt, cwd, io, model, variant = null, resumeSessionId = null, sessionField = 'session_id', trackBuildProcess = false, reviewProcessState, emitSuccessUpdate = true, opencodeAgentMode, runStream, }) => {
|
|
1933
|
+
export const runAgent = ({ ticketId, tool, prompt, cwd, io, model, variant = null, resumeSessionId = null, sessionField = 'session_id', trackBuildProcess = false, reviewProcessState, emitSuccessUpdate = true, opencodeAgentMode, runStream, executionContext, persistSessionIdToTicket = false, }) => {
|
|
1875
1934
|
const resolvedModel = resolveAgentModel(tool, model);
|
|
1876
1935
|
const subagentTracker = createSubagentRunTracker({
|
|
1877
1936
|
parentType: 'ticket',
|
|
@@ -1887,6 +1946,7 @@ export const runAgent = ({ ticketId, tool, prompt, cwd, io, model, variant = nul
|
|
|
1887
1946
|
},
|
|
1888
1947
|
}
|
|
1889
1948
|
: {}),
|
|
1949
|
+
executionContext,
|
|
1890
1950
|
});
|
|
1891
1951
|
const writeRunStatus = (status, log, streamingResponse = null, options = {}) => {
|
|
1892
1952
|
if (runStream) {
|
|
@@ -1900,6 +1960,9 @@ export const runAgent = ({ ticketId, tool, prompt, cwd, io, model, variant = nul
|
|
|
1900
1960
|
if (runStream) {
|
|
1901
1961
|
updateAgentRunSessionId(runStream.runId, sessionId);
|
|
1902
1962
|
emitAgentRunsUpdated(io, 'ticket', ticketId);
|
|
1963
|
+
if (persistSessionIdToTicket) {
|
|
1964
|
+
updateSessionId(ticketId, sessionId, sessionField, io);
|
|
1965
|
+
}
|
|
1903
1966
|
return;
|
|
1904
1967
|
}
|
|
1905
1968
|
updateSessionId(ticketId, sessionId, sessionField, io);
|
|
@@ -1978,12 +2041,21 @@ export const runAgent = ({ ticketId, tool, prompt, cwd, io, model, variant = nul
|
|
|
1978
2041
|
if (tool === 'opencode') {
|
|
1979
2042
|
spawnTimestamp = Date.now();
|
|
1980
2043
|
}
|
|
1981
|
-
|
|
1982
|
-
|
|
1983
|
-
|
|
1984
|
-
|
|
1985
|
-
|
|
1986
|
-
|
|
2044
|
+
let child;
|
|
2045
|
+
try {
|
|
2046
|
+
child = spawn(cmd, args, {
|
|
2047
|
+
cwd,
|
|
2048
|
+
stdio: tool === 'claude' ? ['pipe', 'pipe', 'pipe'] : ['ignore', 'pipe', 'pipe'],
|
|
2049
|
+
env: { ...process.env, PWD: cwd },
|
|
2050
|
+
detached: process.platform !== 'win32',
|
|
2051
|
+
});
|
|
2052
|
+
}
|
|
2053
|
+
catch (error) {
|
|
2054
|
+
const resolvedError = error instanceof Error ? error : new Error(String(error));
|
|
2055
|
+
const transcriptRuns = subagentTracker.finalize('error', resolvedError.message, null);
|
|
2056
|
+
rejectOnce(attachTranscriptRunsToError(resolvedError, transcriptRuns));
|
|
2057
|
+
return;
|
|
2058
|
+
}
|
|
1987
2059
|
reviewChild = child;
|
|
1988
2060
|
if (tool === 'claude') {
|
|
1989
2061
|
const claudePrompt = opencodeAgentMode === 'plan'
|
|
@@ -2195,12 +2267,15 @@ export const runAgent = ({ ticketId, tool, prompt, cwd, io, model, variant = nul
|
|
|
2195
2267
|
});
|
|
2196
2268
|
});
|
|
2197
2269
|
};
|
|
2198
|
-
export const runChatAgent = ({ chatSessionId, tool, prompt, files = [], cwd, io, model, variant = null, resumeSessionId = null, opencodeAgentMode = 'build', }) => {
|
|
2270
|
+
export const runChatAgent = ({ chatSessionId, tool, prompt, files = [], cwd, io, model, variant = null, resumeSessionId = null, opencodeAgentMode = 'build', executionContext, mainRun, }) => {
|
|
2199
2271
|
const resolvedModel = resolveAgentModel(tool, model);
|
|
2200
2272
|
const subagentTracker = createSubagentRunTracker({
|
|
2201
2273
|
parentType: 'chat',
|
|
2202
2274
|
parentId: chatSessionId,
|
|
2203
2275
|
io,
|
|
2276
|
+
executionContext,
|
|
2277
|
+
mainRun,
|
|
2278
|
+
deferMainFinalization: true,
|
|
2204
2279
|
});
|
|
2205
2280
|
return new Promise((resolve, reject) => {
|
|
2206
2281
|
let sessionId = null;
|
|
@@ -2211,11 +2286,7 @@ export const runChatAgent = ({ chatSessionId, tool, prompt, files = [], cwd, io,
|
|
|
2211
2286
|
let startTime = null;
|
|
2212
2287
|
let firstFinalAnswerTime = null;
|
|
2213
2288
|
let usageSnapshot = EMPTY_CHAT_USAGE_SNAPSHOT;
|
|
2214
|
-
const chatState =
|
|
2215
|
-
child: null,
|
|
2216
|
-
stopRequested: false,
|
|
2217
|
-
metadataRefresher: null,
|
|
2218
|
-
};
|
|
2289
|
+
const chatState = activeChatProcesses.get(chatSessionId) ?? registerChatProcessPlaceholder(chatSessionId);
|
|
2219
2290
|
const settle = (handler) => (value) => {
|
|
2220
2291
|
if (settled) {
|
|
2221
2292
|
return;
|
|
@@ -2228,6 +2299,16 @@ export const runChatAgent = ({ chatSessionId, tool, prompt, files = [], cwd, io,
|
|
|
2228
2299
|
};
|
|
2229
2300
|
const resolveOnce = settle(resolve);
|
|
2230
2301
|
const rejectOnce = settle(reject);
|
|
2302
|
+
if (chatState.stopRequested) {
|
|
2303
|
+
const transcriptRuns = subagentTracker.finalize('stopped', null, null);
|
|
2304
|
+
resolveOnce(withTranscriptRuns({
|
|
2305
|
+
completionStatus: 'stopped',
|
|
2306
|
+
finalResponse: null,
|
|
2307
|
+
usageSnapshot,
|
|
2308
|
+
responseTiming: null,
|
|
2309
|
+
}, transcriptRuns));
|
|
2310
|
+
return;
|
|
2311
|
+
}
|
|
2231
2312
|
const [cmd, args] = tool === 'claude'
|
|
2232
2313
|
? (() => {
|
|
2233
2314
|
sessionId = resumeSessionId || randomUUID();
|
|
@@ -2238,8 +2319,10 @@ export const runChatAgent = ({ chatSessionId, tool, prompt, files = [], cwd, io,
|
|
|
2238
2319
|
})()
|
|
2239
2320
|
: ['opencode', ['run', ...(opencodeAgentMode === 'plan' ? ['--agent', 'plan'] : []), '--format', 'json', '--thinking', ...(resumeSessionId ? ['--session', resumeSessionId] : []), ...(resolvedModel ? ['--model', resolvedModel] : []), ...(variant ? ['--variant', variant] : []), ...files.flatMap(filePath => ['--file', filePath]), ...(files.length > 0 ? ['--'] : []), prompt]];
|
|
2240
2321
|
updateChatSessionStatus(chatSessionId, 'running', null, io);
|
|
2322
|
+
subagentTracker.updateMain(null, null);
|
|
2241
2323
|
if (tool === 'claude' && sessionId) {
|
|
2242
2324
|
updateChatSessionId(chatSessionId, tool, sessionId, io);
|
|
2325
|
+
subagentTracker.setMainSessionId(sessionId);
|
|
2243
2326
|
}
|
|
2244
2327
|
if (tool === 'opencode') {
|
|
2245
2328
|
spawnTimestamp = Date.now();
|
|
@@ -2257,12 +2340,21 @@ export const runChatAgent = ({ chatSessionId, tool, prompt, files = [], cwd, io,
|
|
|
2257
2340
|
}
|
|
2258
2341
|
}
|
|
2259
2342
|
}
|
|
2260
|
-
|
|
2261
|
-
|
|
2262
|
-
|
|
2263
|
-
|
|
2264
|
-
|
|
2265
|
-
|
|
2343
|
+
let child;
|
|
2344
|
+
try {
|
|
2345
|
+
child = spawn(cmd, args, {
|
|
2346
|
+
cwd,
|
|
2347
|
+
stdio: tool === 'claude' ? ['pipe', 'pipe', 'pipe'] : ['ignore', 'pipe', 'pipe'],
|
|
2348
|
+
env: { ...process.env, PWD: cwd },
|
|
2349
|
+
detached: process.platform !== 'win32',
|
|
2350
|
+
});
|
|
2351
|
+
}
|
|
2352
|
+
catch (error) {
|
|
2353
|
+
const resolvedError = error instanceof Error ? error : new Error(String(error));
|
|
2354
|
+
const transcriptRuns = subagentTracker.finalize('error', resolvedError.message, null);
|
|
2355
|
+
rejectOnce(attachTranscriptRunsToError(resolvedError, transcriptRuns));
|
|
2356
|
+
return;
|
|
2357
|
+
}
|
|
2266
2358
|
chatState.child = child;
|
|
2267
2359
|
activeChatProcesses.set(chatSessionId, chatState);
|
|
2268
2360
|
if (tool === 'claude') {
|
|
@@ -2281,6 +2373,7 @@ export const runChatAgent = ({ chatSessionId, tool, prompt, files = [], cwd, io,
|
|
|
2281
2373
|
discoverParentSession: false,
|
|
2282
2374
|
onParentSessionId: discoveredSessionId => {
|
|
2283
2375
|
updateChatSessionId(chatSessionId, 'opencode', discoveredSessionId, io);
|
|
2376
|
+
subagentTracker.setMainSessionId(discoveredSessionId);
|
|
2284
2377
|
},
|
|
2285
2378
|
});
|
|
2286
2379
|
opencodeSubagentMonitor.start();
|
|
@@ -2291,7 +2384,10 @@ export const runChatAgent = ({ chatSessionId, tool, prompt, files = [], cwd, io,
|
|
|
2291
2384
|
let remainder = '';
|
|
2292
2385
|
const stderrChunks = [];
|
|
2293
2386
|
const progressUpdater = createThrottledProgressUpdater(() => {
|
|
2294
|
-
|
|
2387
|
+
const log = logLines.join('\n\n');
|
|
2388
|
+
const response = responseLines.join('\n\n');
|
|
2389
|
+
updateChatSessionStatus(chatSessionId, 'running', log, io, response);
|
|
2390
|
+
subagentTracker.updateMain(log, response);
|
|
2295
2391
|
});
|
|
2296
2392
|
child.stdout?.on('data', (chunk) => {
|
|
2297
2393
|
const text = remainder + chunk.toString();
|
|
@@ -2398,7 +2494,10 @@ export const runChatAgent = ({ chatSessionId, tool, prompt, files = [], cwd, io,
|
|
|
2398
2494
|
let remainder = '';
|
|
2399
2495
|
const stderrChunks = [];
|
|
2400
2496
|
const progressUpdater = createThrottledProgressUpdater(() => {
|
|
2401
|
-
|
|
2497
|
+
const log = logLines.join('\n\n');
|
|
2498
|
+
const response = responseLines.join('\n\n');
|
|
2499
|
+
updateChatSessionStatus(chatSessionId, 'running', log, io, response);
|
|
2500
|
+
subagentTracker.updateMain(log, response);
|
|
2402
2501
|
});
|
|
2403
2502
|
child.stdout?.on('data', (chunk) => {
|
|
2404
2503
|
const text = remainder + chunk.toString();
|
|
@@ -2540,12 +2639,15 @@ export const runChatAgent = ({ chatSessionId, tool, prompt, files = [], cwd, io,
|
|
|
2540
2639
|
});
|
|
2541
2640
|
});
|
|
2542
2641
|
};
|
|
2543
|
-
export const runSpecAgent = ({ specSessionId, tool, prompt, files = [], cwd, io, model, variant = null, resumeSessionId = null, }) => {
|
|
2642
|
+
export const runSpecAgent = ({ specSessionId, tool, prompt, files = [], cwd, io, model, variant = null, resumeSessionId = null, executionContext, mainRun, }) => {
|
|
2544
2643
|
const resolvedModel = resolveAgentModel(tool, model);
|
|
2545
2644
|
const subagentTracker = createSubagentRunTracker({
|
|
2546
2645
|
parentType: 'spec',
|
|
2547
2646
|
parentId: specSessionId,
|
|
2548
2647
|
io,
|
|
2648
|
+
executionContext,
|
|
2649
|
+
mainRun,
|
|
2650
|
+
deferMainFinalization: true,
|
|
2549
2651
|
});
|
|
2550
2652
|
return new Promise((resolve, reject) => {
|
|
2551
2653
|
let sessionId = null;
|
|
@@ -2556,11 +2658,7 @@ export const runSpecAgent = ({ specSessionId, tool, prompt, files = [], cwd, io,
|
|
|
2556
2658
|
let startTime = null;
|
|
2557
2659
|
let firstFinalAnswerTime = null;
|
|
2558
2660
|
let usageSnapshot = EMPTY_CHAT_USAGE_SNAPSHOT;
|
|
2559
|
-
const specState =
|
|
2560
|
-
child: null,
|
|
2561
|
-
stopRequested: false,
|
|
2562
|
-
metadataRefresher: null,
|
|
2563
|
-
};
|
|
2661
|
+
const specState = activeSpecProcesses.get(specSessionId) ?? registerSpecProcessPlaceholder(specSessionId);
|
|
2564
2662
|
const settle = (handler) => (value) => {
|
|
2565
2663
|
if (settled) {
|
|
2566
2664
|
return;
|
|
@@ -2573,6 +2671,16 @@ export const runSpecAgent = ({ specSessionId, tool, prompt, files = [], cwd, io,
|
|
|
2573
2671
|
};
|
|
2574
2672
|
const resolveOnce = settle(resolve);
|
|
2575
2673
|
const rejectOnce = settle(reject);
|
|
2674
|
+
if (specState.stopRequested) {
|
|
2675
|
+
const transcriptRuns = subagentTracker.finalize('stopped', null, null);
|
|
2676
|
+
resolveOnce(withTranscriptRuns({
|
|
2677
|
+
completionStatus: 'stopped',
|
|
2678
|
+
finalResponse: null,
|
|
2679
|
+
usageSnapshot,
|
|
2680
|
+
responseTiming: null,
|
|
2681
|
+
}, transcriptRuns));
|
|
2682
|
+
return;
|
|
2683
|
+
}
|
|
2576
2684
|
const [cmd, args] = tool === 'claude'
|
|
2577
2685
|
? (() => {
|
|
2578
2686
|
sessionId = resumeSessionId || randomUUID();
|
|
@@ -2583,8 +2691,10 @@ export const runSpecAgent = ({ specSessionId, tool, prompt, files = [], cwd, io,
|
|
|
2583
2691
|
})()
|
|
2584
2692
|
: ['opencode', ['run', '--agent', 'plan', '--format', 'json', '--thinking', ...(resumeSessionId ? ['--session', resumeSessionId] : []), ...(resolvedModel ? ['--model', resolvedModel] : []), ...(variant ? ['--variant', variant] : []), ...files.flatMap(filePath => ['--file', filePath]), ...(files.length > 0 ? ['--'] : []), prompt]];
|
|
2585
2693
|
updateSpecSessionStatusLocal(specSessionId, 'running', null, io);
|
|
2694
|
+
subagentTracker.updateMain(null, null);
|
|
2586
2695
|
if (tool === 'claude' && sessionId) {
|
|
2587
2696
|
updateSpecSessionIdLocal(specSessionId, tool, sessionId, io);
|
|
2697
|
+
subagentTracker.setMainSessionId(sessionId);
|
|
2588
2698
|
}
|
|
2589
2699
|
if (tool === 'opencode') {
|
|
2590
2700
|
spawnTimestamp = Date.now();
|
|
@@ -2602,12 +2712,21 @@ export const runSpecAgent = ({ specSessionId, tool, prompt, files = [], cwd, io,
|
|
|
2602
2712
|
}
|
|
2603
2713
|
}
|
|
2604
2714
|
}
|
|
2605
|
-
|
|
2606
|
-
|
|
2607
|
-
|
|
2608
|
-
|
|
2609
|
-
|
|
2610
|
-
|
|
2715
|
+
let child;
|
|
2716
|
+
try {
|
|
2717
|
+
child = spawn(cmd, args, {
|
|
2718
|
+
cwd,
|
|
2719
|
+
stdio: tool === 'claude' ? ['pipe', 'pipe', 'pipe'] : ['ignore', 'pipe', 'pipe'],
|
|
2720
|
+
env: { ...process.env, PWD: cwd },
|
|
2721
|
+
detached: process.platform !== 'win32',
|
|
2722
|
+
});
|
|
2723
|
+
}
|
|
2724
|
+
catch (error) {
|
|
2725
|
+
const resolvedError = error instanceof Error ? error : new Error(String(error));
|
|
2726
|
+
const transcriptRuns = subagentTracker.finalize('error', resolvedError.message, null);
|
|
2727
|
+
rejectOnce(attachTranscriptRunsToError(resolvedError, transcriptRuns));
|
|
2728
|
+
return;
|
|
2729
|
+
}
|
|
2611
2730
|
specState.child = child;
|
|
2612
2731
|
activeSpecProcesses.set(specSessionId, specState);
|
|
2613
2732
|
if (tool === 'claude') {
|
|
@@ -2623,6 +2742,7 @@ export const runSpecAgent = ({ specSessionId, tool, prompt, files = [], cwd, io,
|
|
|
2623
2742
|
discoverParentSession: false,
|
|
2624
2743
|
onParentSessionId: discoveredSessionId => {
|
|
2625
2744
|
updateSpecSessionIdLocal(specSessionId, 'opencode', discoveredSessionId, io);
|
|
2745
|
+
subagentTracker.setMainSessionId(discoveredSessionId);
|
|
2626
2746
|
},
|
|
2627
2747
|
});
|
|
2628
2748
|
opencodeSubagentMonitor.start();
|
|
@@ -2633,7 +2753,10 @@ export const runSpecAgent = ({ specSessionId, tool, prompt, files = [], cwd, io,
|
|
|
2633
2753
|
let remainder = '';
|
|
2634
2754
|
const stderrChunks = [];
|
|
2635
2755
|
const progressUpdater = createThrottledProgressUpdater(() => {
|
|
2636
|
-
|
|
2756
|
+
const log = logLines.join('\n\n');
|
|
2757
|
+
const response = responseLines.join('\n\n');
|
|
2758
|
+
updateSpecSessionStatusLocal(specSessionId, 'running', log, io, response);
|
|
2759
|
+
subagentTracker.updateMain(log, response);
|
|
2637
2760
|
});
|
|
2638
2761
|
child.stdout?.on('data', (chunk) => {
|
|
2639
2762
|
const text = remainder + chunk.toString();
|
|
@@ -2740,7 +2863,10 @@ export const runSpecAgent = ({ specSessionId, tool, prompt, files = [], cwd, io,
|
|
|
2740
2863
|
let remainder = '';
|
|
2741
2864
|
const stderrChunks = [];
|
|
2742
2865
|
const progressUpdater = createThrottledProgressUpdater(() => {
|
|
2743
|
-
|
|
2866
|
+
const log = logLines.join('\n\n');
|
|
2867
|
+
const response = responseLines.join('\n\n');
|
|
2868
|
+
updateSpecSessionStatusLocal(specSessionId, 'running', log, io, response);
|
|
2869
|
+
subagentTracker.updateMain(log, response);
|
|
2744
2870
|
});
|
|
2745
2871
|
child.stdout?.on('data', (chunk) => {
|
|
2746
2872
|
const text = remainder + chunk.toString();
|
|
@@ -2893,15 +3019,24 @@ export const runSpecAgent = ({ specSessionId, tool, prompt, files = [], cwd, io,
|
|
|
2893
3019
|
* updateSpecReviewRunStatus / updateSpecReviewRunStreaming / updateSpecReviewRunUsage —
|
|
2894
3020
|
* the spec_sessions row is never touched by this path.
|
|
2895
3021
|
*/
|
|
2896
|
-
export const runSpecReviewAgent = ({ specReviewRunId, tool, prompt, files = [], cwd, io, model, variant = null, }) => {
|
|
3022
|
+
export const runSpecReviewAgent = ({ specReviewRunId, specSessionId, tool, prompt, files = [], cwd, io, model, variant = null, executionContext, }) => {
|
|
2897
3023
|
const resolvedModel = resolveAgentModel(tool, model);
|
|
3024
|
+
const subagentTracker = createSubagentRunTracker({
|
|
3025
|
+
parentType: 'spec',
|
|
3026
|
+
parentId: specSessionId,
|
|
3027
|
+
io,
|
|
3028
|
+
executionContext,
|
|
3029
|
+
});
|
|
2898
3030
|
return new Promise((resolve, reject) => {
|
|
3031
|
+
let spawnTimestamp = null;
|
|
3032
|
+
let opencodeSubagentMonitor = null;
|
|
2899
3033
|
let settled = false;
|
|
2900
3034
|
let startTime = null;
|
|
2901
3035
|
let firstFinalAnswerTime = null;
|
|
2902
3036
|
let usageSnapshot = EMPTY_CHAT_USAGE_SNAPSHOT;
|
|
2903
3037
|
const reviewState = {
|
|
2904
3038
|
child: null,
|
|
3039
|
+
researchChildren: new Set(),
|
|
2905
3040
|
stopRequested: false,
|
|
2906
3041
|
metadataRefresher: null,
|
|
2907
3042
|
};
|
|
@@ -2910,14 +3045,12 @@ export const runSpecReviewAgent = ({ specReviewRunId, tool, prompt, files = [],
|
|
|
2910
3045
|
return;
|
|
2911
3046
|
}
|
|
2912
3047
|
settled = true;
|
|
3048
|
+
opencodeSubagentMonitor?.stop();
|
|
2913
3049
|
untrackSpecReviewProcess(specReviewRunId, reviewState);
|
|
2914
3050
|
handler(value);
|
|
2915
3051
|
};
|
|
2916
3052
|
const resolveOnce = settle(resolve);
|
|
2917
3053
|
const rejectOnce = settle(reject);
|
|
2918
|
-
const emitReviewUpdated = () => {
|
|
2919
|
-
io.emit('spec-review:updated', { spec_review_run_id: specReviewRunId });
|
|
2920
|
-
};
|
|
2921
3054
|
const [cmd, args] = tool === 'claude'
|
|
2922
3055
|
? [
|
|
2923
3056
|
'claude',
|
|
@@ -2925,7 +3058,6 @@ export const runSpecReviewAgent = ({ specReviewRunId, tool, prompt, files = [],
|
|
|
2925
3058
|
]
|
|
2926
3059
|
: ['opencode', ['run', '--agent', 'plan', '--format', 'json', '--thinking', ...(resolvedModel ? ['--model', resolvedModel] : []), ...(variant ? ['--variant', variant] : []), ...files.flatMap(filePath => ['--file', filePath]), ...(files.length > 0 ? ['--'] : []), prompt]];
|
|
2927
3060
|
updateSpecReviewRunStreaming(specReviewRunId, null);
|
|
2928
|
-
emitReviewUpdated();
|
|
2929
3061
|
const child = spawn(cmd, args, {
|
|
2930
3062
|
cwd,
|
|
2931
3063
|
stdio: tool === 'claude' ? ['pipe', 'pipe', 'pipe'] : ['ignore', 'pipe', 'pipe'],
|
|
@@ -2938,6 +3070,16 @@ export const runSpecReviewAgent = ({ specReviewRunId, tool, prompt, files = [],
|
|
|
2938
3070
|
writeClaudeStdin(child, buildClaudeStdinMessage(appendClaudeHeadlessPlanPrompt(prompt), files, cwd));
|
|
2939
3071
|
}
|
|
2940
3072
|
startTime = Date.now();
|
|
3073
|
+
if (tool === 'opencode') {
|
|
3074
|
+
spawnTimestamp = startTime;
|
|
3075
|
+
opencodeSubagentMonitor = createOpencodeSubagentMonitor({
|
|
3076
|
+
initialParentSessionId: null,
|
|
3077
|
+
spawnTimestamp,
|
|
3078
|
+
cwd,
|
|
3079
|
+
tracker: subagentTracker,
|
|
3080
|
+
});
|
|
3081
|
+
opencodeSubagentMonitor.start();
|
|
3082
|
+
}
|
|
2941
3083
|
if (tool === 'claude') {
|
|
2942
3084
|
const logLines = [];
|
|
2943
3085
|
const responseLines = [];
|
|
@@ -2952,7 +3094,8 @@ export const runSpecReviewAgent = ({ specReviewRunId, tool, prompt, files = [],
|
|
|
2952
3094
|
remainder = lines.pop() ?? '';
|
|
2953
3095
|
for (const line of lines) {
|
|
2954
3096
|
usageSnapshot = mergeUsageFromJsonLine(usageSnapshot, line);
|
|
2955
|
-
const { logFragment, responseFragment } = parseClaudeStreamJsonLine(line);
|
|
3097
|
+
const { logFragment, responseFragment, subagentEvents } = parseClaudeStreamJsonLine(line);
|
|
3098
|
+
subagentTracker.handle(subagentEvents);
|
|
2956
3099
|
if (logFragment !== null) {
|
|
2957
3100
|
logLines.push(logFragment);
|
|
2958
3101
|
}
|
|
@@ -2969,7 +3112,8 @@ export const runSpecReviewAgent = ({ specReviewRunId, tool, prompt, files = [],
|
|
|
2969
3112
|
progressUpdater.cancel();
|
|
2970
3113
|
if (remainder.trim()) {
|
|
2971
3114
|
usageSnapshot = mergeUsageFromJsonLine(usageSnapshot, remainder);
|
|
2972
|
-
const { logFragment, responseFragment } = parseClaudeStreamJsonLine(remainder);
|
|
3115
|
+
const { logFragment, responseFragment, subagentEvents } = parseClaudeStreamJsonLine(remainder);
|
|
3116
|
+
subagentTracker.handle(subagentEvents);
|
|
2973
3117
|
if (logFragment !== null) {
|
|
2974
3118
|
logLines.push(logFragment);
|
|
2975
3119
|
}
|
|
@@ -2982,6 +3126,7 @@ export const runSpecReviewAgent = ({ specReviewRunId, tool, prompt, files = [],
|
|
|
2982
3126
|
const finalResponse = responseLines.join('\n\n') || errOutput;
|
|
2983
3127
|
if (reviewState.stopRequested) {
|
|
2984
3128
|
updateSpecReviewRunStreaming(specReviewRunId, finalResponse || null);
|
|
3129
|
+
subagentTracker.finalize('stopped', finalLog || null, finalResponse || null);
|
|
2985
3130
|
resolveOnce({
|
|
2986
3131
|
completionStatus: 'stopped',
|
|
2987
3132
|
finalResponse,
|
|
@@ -2993,6 +3138,7 @@ export const runSpecReviewAgent = ({ specReviewRunId, tool, prompt, files = [],
|
|
|
2993
3138
|
const modelError = isModelResolutionError(finalLog);
|
|
2994
3139
|
if (code === 0 && !modelError) {
|
|
2995
3140
|
updateSpecReviewRunStreaming(specReviewRunId, finalResponse || null);
|
|
3141
|
+
subagentTracker.finalize('done', finalLog || null, finalResponse || null);
|
|
2996
3142
|
resolveOnce({
|
|
2997
3143
|
completionStatus: 'done',
|
|
2998
3144
|
finalResponse,
|
|
@@ -3001,10 +3147,12 @@ export const runSpecReviewAgent = ({ specReviewRunId, tool, prompt, files = [],
|
|
|
3001
3147
|
});
|
|
3002
3148
|
return;
|
|
3003
3149
|
}
|
|
3150
|
+
subagentTracker.finalize('error', finalLog || null, finalResponse || null);
|
|
3004
3151
|
rejectOnce(new Error(`Agent exited with code ${code ?? 'null'}\n${finalLog}${errOutput !== finalLog && errOutput ? '\n\n' + errOutput : ''}`));
|
|
3005
3152
|
});
|
|
3006
3153
|
child.on('error', err => {
|
|
3007
3154
|
progressUpdater.cancel();
|
|
3155
|
+
subagentTracker.finalize(reviewState.stopRequested ? 'stopped' : 'error', getErrorMessage(err), null);
|
|
3008
3156
|
rejectOnce(err instanceof Error ? err : new Error(getErrorMessage(err)));
|
|
3009
3157
|
});
|
|
3010
3158
|
return;
|
|
@@ -3039,7 +3187,9 @@ export const runSpecReviewAgent = ({ specReviewRunId, tool, prompt, files = [],
|
|
|
3039
3187
|
}
|
|
3040
3188
|
}
|
|
3041
3189
|
const parsed = parseOpencodeJsonLine(line, cwd);
|
|
3042
|
-
const { logFragment, responseFragment } = parsed;
|
|
3190
|
+
const { logFragment, responseFragment, subagentEvents, providerSessionId } = parsed;
|
|
3191
|
+
opencodeSubagentMonitor?.setParentSessionId(providerSessionId);
|
|
3192
|
+
subagentTracker.handle(subagentEvents);
|
|
3043
3193
|
if (appendOpencodeTranscriptLine({ parsed, logLines, responseLines, recoveryTracker })) {
|
|
3044
3194
|
firstFinalAnswerTime = null;
|
|
3045
3195
|
}
|
|
@@ -3051,9 +3201,12 @@ export const runSpecReviewAgent = ({ specReviewRunId, tool, prompt, files = [],
|
|
|
3051
3201
|
child.stderr?.on('data', (chunk) => stderrChunks.push(chunk));
|
|
3052
3202
|
child.on('close', code => {
|
|
3053
3203
|
progressUpdater.cancel();
|
|
3204
|
+
opencodeSubagentMonitor?.refresh();
|
|
3054
3205
|
if (remainder.trim()) {
|
|
3055
3206
|
usageSnapshot = mergeUsageFromJsonLine(usageSnapshot, remainder);
|
|
3056
3207
|
const parsed = parseOpencodeJsonLine(remainder, cwd);
|
|
3208
|
+
opencodeSubagentMonitor?.setParentSessionId(parsed.providerSessionId);
|
|
3209
|
+
subagentTracker.handle(parsed.subagentEvents);
|
|
3057
3210
|
if (appendOpencodeTranscriptLine({ parsed, logLines, responseLines, recoveryTracker })) {
|
|
3058
3211
|
firstFinalAnswerTime = null;
|
|
3059
3212
|
}
|
|
@@ -3066,6 +3219,7 @@ export const runSpecReviewAgent = ({ specReviewRunId, tool, prompt, files = [],
|
|
|
3066
3219
|
: responseLines.join('\n\n') || stderrOutput;
|
|
3067
3220
|
if (reviewState.stopRequested) {
|
|
3068
3221
|
updateSpecReviewRunStreaming(specReviewRunId, finalResponse || null);
|
|
3222
|
+
subagentTracker.finalize('stopped', log || null, finalResponse || null);
|
|
3069
3223
|
resolveOnce({
|
|
3070
3224
|
completionStatus: 'stopped',
|
|
3071
3225
|
finalResponse,
|
|
@@ -3077,6 +3231,7 @@ export const runSpecReviewAgent = ({ specReviewRunId, tool, prompt, files = [],
|
|
|
3077
3231
|
const modelError = isModelResolutionError(log);
|
|
3078
3232
|
if (isSuccessfulOpencodeExit(code, modelError, recoveryTracker)) {
|
|
3079
3233
|
updateSpecReviewRunStreaming(specReviewRunId, finalResponse || null);
|
|
3234
|
+
subagentTracker.finalize('done', log || null, finalResponse || null);
|
|
3080
3235
|
resolveOnce({
|
|
3081
3236
|
completionStatus: 'done',
|
|
3082
3237
|
finalResponse,
|
|
@@ -3085,10 +3240,12 @@ export const runSpecReviewAgent = ({ specReviewRunId, tool, prompt, files = [],
|
|
|
3085
3240
|
});
|
|
3086
3241
|
return;
|
|
3087
3242
|
}
|
|
3243
|
+
subagentTracker.finalize('error', log || null, finalResponse || null);
|
|
3088
3244
|
rejectOnce(new Error(`Agent exited with code ${code ?? 'null'}\n${log}${stderrOutput !== log && stderrOutput ? '\n\n' + stderrOutput : ''}`));
|
|
3089
3245
|
});
|
|
3090
3246
|
child.on('error', err => {
|
|
3091
3247
|
progressUpdater.cancel();
|
|
3248
|
+
subagentTracker.finalize(reviewState.stopRequested ? 'stopped' : 'error', getErrorMessage(err), null);
|
|
3092
3249
|
rejectOnce(err instanceof Error ? err : new Error(getErrorMessage(err)));
|
|
3093
3250
|
});
|
|
3094
3251
|
});
|