@straiffi/archon 1.8.7 → 1.8.9
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-D4Qh96zr.js → ActivityView-gBeoYQdD.js} +1 -1
- package/dist/client/assets/{GitHubActionsDialog-Bg03OmVv.js → GitHubActionsDialog-fc1Vwafm.js} +1 -1
- package/dist/client/assets/RepositoryGraphDialog-DCOjwUR3.js +1 -0
- package/dist/client/assets/VerificationDialog-CIObj1Rw.js +4 -0
- package/dist/client/assets/{architectureDiagram-3BPJPVTR-2lxabjSl.js → architectureDiagram-3BPJPVTR-B1tJZe1S.js} +1 -1
- package/dist/client/assets/{blockDiagram-GPEHLZMM-C80HvJmb.js → blockDiagram-GPEHLZMM-D_90AQ2Z.js} +1 -1
- package/dist/client/assets/{c4Diagram-AAUBKEIU-BM3k_lKz.js → c4Diagram-AAUBKEIU-DSyJfqly.js} +1 -1
- package/dist/client/assets/channel-DFw1f2Rh.js +1 -0
- package/dist/client/assets/{chunk-2J33WTMH-BTk3lX07.js → chunk-2J33WTMH-B9RStQGj.js} +1 -1
- package/dist/client/assets/{chunk-3OPIFGDE-DAxdBZ_4.js → chunk-3OPIFGDE-CHKuJYq0.js} +1 -1
- package/dist/client/assets/{chunk-5ZQYHXKU-BYm9s62a.js → chunk-5ZQYHXKU-Cznw7LTJ.js} +1 -1
- package/dist/client/assets/{chunk-727SXJPM-iVUM8xuV.js → chunk-727SXJPM-ix6OeZwJ.js} +1 -1
- package/dist/client/assets/{chunk-AQP2D5EJ-DVM7riMJ.js → chunk-AQP2D5EJ-DrPJIcE7.js} +1 -1
- package/dist/client/assets/{chunk-CSCIHK7Q-_D1FzP9B.js → chunk-CSCIHK7Q-BSEHTnBR.js} +1 -1
- package/dist/client/assets/{chunk-KSCS5N6A-D3XouAHf.js → chunk-KSCS5N6A-MdDdaLn8.js} +1 -1
- package/dist/client/assets/{chunk-L5ZTLDWV-B7NYWgT4.js → chunk-L5ZTLDWV-D_5xeDG1.js} +1 -1
- package/dist/client/assets/{chunk-LZXEDZCA-Dgkkbb6A.js → chunk-LZXEDZCA-Bz8_Fyt2.js} +2 -2
- package/dist/client/assets/{chunk-ND2GUHAM-CzO1oVCi.js → chunk-ND2GUHAM-DCINKlk8.js} +1 -1
- package/dist/client/assets/{chunk-NZK2D7GU-re0VVZne.js → chunk-NZK2D7GU-rGPgryKx.js} +1 -1
- package/dist/client/assets/{chunk-O5CBEL6O-BwsS59iy.js → chunk-O5CBEL6O-BHB8UIYA.js} +1 -1
- package/dist/client/assets/{chunk-WU5MYG2G-CLyh-xCA.js → chunk-WU5MYG2G-Bz5BJWjF.js} +1 -1
- package/dist/client/assets/classDiagram-4FO5ZUOK-Dt0kmMzQ.js +1 -0
- package/dist/client/assets/classDiagram-v2-Q7XG4LA2-BuxhA4Gw.js +1 -0
- package/dist/client/assets/{dagre-BM42HDAG-x71fYlqQ.js → dagre-BM42HDAG-B4TXLkOG.js} +1 -1
- package/dist/client/assets/{diagram-2AECGRRQ-CMdwzuYj.js → diagram-2AECGRRQ-CxMup1wq.js} +1 -1
- package/dist/client/assets/{diagram-5GNKFQAL-B3l6I4qJ.js → diagram-5GNKFQAL-CTfP_wnS.js} +1 -1
- package/dist/client/assets/{diagram-KO2AKTUF-BNhypLBW.js → diagram-KO2AKTUF-31NKNt4r.js} +1 -1
- package/dist/client/assets/{diagram-LMA3HP47-CmrhbiDt.js → diagram-LMA3HP47-Cxo7yvjc.js} +1 -1
- package/dist/client/assets/{diagram-OG6HWLK6-CRobDMLl.js → diagram-OG6HWLK6-ChgSAMLv.js} +1 -1
- package/dist/client/assets/{erDiagram-TEJ5UH35-CqO7K0TS.js → erDiagram-TEJ5UH35-u6msywL_.js} +1 -1
- package/dist/client/assets/{flowDiagram-I6XJVG4X-CuLTJZU0.js → flowDiagram-I6XJVG4X-CimeXkDN.js} +1 -1
- package/dist/client/assets/{ganttDiagram-6RSMTGT7-Bm7v1eRG.js → ganttDiagram-6RSMTGT7-DOu5sDUI.js} +1 -1
- package/dist/client/assets/{gitGraphDiagram-PVQCEYII-CNHZr-5i.js → gitGraphDiagram-PVQCEYII-zIToibUf.js} +1 -1
- package/dist/client/assets/index-C-VHd0Pr.js +274 -0
- package/dist/client/assets/index-D3xlEyeM.css +2 -0
- package/dist/client/assets/{infoDiagram-5YYISTIA-z27pUr2X.js → infoDiagram-5YYISTIA-CAtWGGJI.js} +1 -1
- package/dist/client/assets/{ishikawaDiagram-YF4QCWOH-CDocZ0jf.js → ishikawaDiagram-YF4QCWOH-7N-C7DEt.js} +1 -1
- package/dist/client/assets/{journeyDiagram-JHISSGLW-CgP31lsU.js → journeyDiagram-JHISSGLW-D7VUypFG.js} +1 -1
- package/dist/client/assets/{kanban-definition-UN3LZRKU-DxTm1_fc.js → kanban-definition-UN3LZRKU-AmbDmzSD.js} +1 -1
- package/dist/client/assets/{line-hrZ7m44_.js → line-qf4UZ8vh.js} +1 -1
- package/dist/client/assets/{mermaid-parser.core-BThJAIK-.js → mermaid-parser.core-BssCd1kF.js} +1 -1
- package/dist/client/assets/{mermaid.core-CfVyP_kK.js → mermaid.core-DzeMqg9Y.js} +3 -3
- package/dist/client/assets/{mindmap-definition-RKZ34NQL-CuISnLgW.js → mindmap-definition-RKZ34NQL-dEnNQcDm.js} +1 -1
- package/dist/client/assets/{pieDiagram-4H26LBE5-DnWAdd44.js → pieDiagram-4H26LBE5-VjMue0a-.js} +1 -1
- package/dist/client/assets/{quadrantDiagram-W4KKPZXB-Cb-RVl5A.js → quadrantDiagram-W4KKPZXB-DQFdm-0f.js} +1 -1
- package/dist/client/assets/{requirementDiagram-4Y6WPE33-DrXg_gCS.js → requirementDiagram-4Y6WPE33-CHIaXlsy.js} +1 -1
- package/dist/client/assets/{sankeyDiagram-5OEKKPKP-DzZjp_ZP.js → sankeyDiagram-5OEKKPKP-D-kzGaKb.js} +1 -1
- package/dist/client/assets/{sequenceDiagram-3UESZ5HK-CQJ3PhQD.js → sequenceDiagram-3UESZ5HK-CiDmlD8k.js} +1 -1
- package/dist/client/assets/{stateDiagram-AJRCARHV-B16j9pg1.js → stateDiagram-AJRCARHV-BKlnnFdT.js} +1 -1
- package/dist/client/assets/stateDiagram-v2-BHNVJYJU-DhJxc4em.js +1 -0
- package/dist/client/assets/{timeline-definition-PNZ67QCA-bUG3mZQt.js → timeline-definition-PNZ67QCA-D-BK07Un.js} +1 -1
- package/dist/client/assets/{vennDiagram-CIIHVFJN-DALCJcZD.js → vennDiagram-CIIHVFJN-CB9_GqSx.js} +1 -1
- package/dist/client/assets/{wardleyDiagram-YWT4CUSO-DPQd3l9A.js → wardleyDiagram-YWT4CUSO-BEuNfyLT.js} +1 -1
- package/dist/client/assets/{xychartDiagram-2RQKCTM6-BIv1FqXG.js → xychartDiagram-2RQKCTM6-CSS5WMrZ.js} +1 -1
- package/dist/client/index.html +2 -2
- package/dist/server/db.js +481 -27
- package/dist/server/db.js.map +1 -1
- package/dist/server/index.js +113 -54
- package/dist/server/index.js.map +1 -1
- package/dist/server/lib/activeAutomationChild.js +1 -0
- package/dist/server/lib/activeAutomationChild.js.map +1 -1
- package/dist/server/lib/agent.js +127 -15
- package/dist/server/lib/agent.js.map +1 -1
- package/dist/server/lib/agentRuns.js +12 -0
- package/dist/server/lib/agentRuns.js.map +1 -1
- package/dist/server/lib/agentSpawnPermits.js +37 -0
- package/dist/server/lib/agentSpawnPermits.js.map +1 -0
- package/dist/server/lib/automationCheckGate.js +9 -1
- package/dist/server/lib/automationCheckGate.js.map +1 -1
- package/dist/server/lib/automationProgression.js +19 -5
- package/dist/server/lib/automationProgression.js.map +1 -1
- package/dist/server/lib/automationReviewGate.js +1 -0
- package/dist/server/lib/automationReviewGate.js.map +1 -1
- package/dist/server/lib/buildCompletionContinuation.js +144 -4
- package/dist/server/lib/buildCompletionContinuation.js.map +1 -1
- package/dist/server/lib/buildSequences.js +13 -1
- package/dist/server/lib/buildSequences.js.map +1 -1
- package/dist/server/lib/bundleActivity.js +19 -0
- package/dist/server/lib/bundleActivity.js.map +1 -1
- package/dist/server/lib/chatOperations.js +81 -2
- package/dist/server/lib/chatOperations.js.map +1 -1
- package/dist/server/lib/checkAutoFix.js +604 -0
- package/dist/server/lib/checkAutoFix.js.map +1 -0
- package/dist/server/lib/checkAutoFixDetails.js +83 -0
- package/dist/server/lib/checkAutoFixDetails.js.map +1 -0
- package/dist/server/lib/checkAutoFixPolicy.js +59 -0
- package/dist/server/lib/checkAutoFixPolicy.js.map +1 -0
- package/dist/server/lib/checkRepair.js +149 -54
- package/dist/server/lib/checkRepair.js.map +1 -1
- package/dist/server/lib/checkRepairDispatch.js +91 -0
- package/dist/server/lib/checkRepairDispatch.js.map +1 -0
- package/dist/server/lib/checkRepairEvidence.js +84 -0
- package/dist/server/lib/checkRepairEvidence.js.map +1 -0
- package/dist/server/lib/checkRepairParent.js +21 -0
- package/dist/server/lib/checkRepairParent.js.map +1 -0
- package/dist/server/lib/checkRepairReconciliation.js +14 -5
- package/dist/server/lib/checkRepairReconciliation.js.map +1 -1
- package/dist/server/lib/checkRunner.js +27 -8
- package/dist/server/lib/checkRunner.js.map +1 -1
- package/dist/server/lib/checkRuns.js +63 -4
- package/dist/server/lib/checkRuns.js.map +1 -1
- package/dist/server/lib/executionReconciliation.js +387 -8
- package/dist/server/lib/executionReconciliation.js.map +1 -1
- package/dist/server/lib/executionRuns.js +24 -1
- package/dist/server/lib/executionRuns.js.map +1 -1
- package/dist/server/lib/git.js +302 -11
- package/dist/server/lib/git.js.map +1 -1
- package/dist/server/lib/integrations/github.js +138 -65
- package/dist/server/lib/integrations/github.js.map +1 -1
- package/dist/server/lib/integrations/importedIssueImages.js +10 -15
- package/dist/server/lib/integrations/importedIssueImages.js.map +1 -1
- package/dist/server/lib/postBuildCheckRuns.js +200 -5
- package/dist/server/lib/postBuildCheckRuns.js.map +1 -1
- package/dist/server/lib/postBuildChecks.js +83 -13
- package/dist/server/lib/postBuildChecks.js.map +1 -1
- package/dist/server/lib/projects.js +25 -1
- package/dist/server/lib/projects.js.map +1 -1
- package/dist/server/lib/queue.js +9 -3
- package/dist/server/lib/queue.js.map +1 -1
- package/dist/server/lib/repositoryGraphQueries.js +5 -3
- package/dist/server/lib/repositoryGraphQueries.js.map +1 -1
- package/dist/server/lib/repositoryGraphScan.js +13 -2
- package/dist/server/lib/repositoryGraphScan.js.map +1 -1
- package/dist/server/lib/repositoryGraphStore.js +61 -1
- package/dist/server/lib/repositoryGraphStore.js.map +1 -1
- package/dist/server/lib/specArtifact.js +10 -1
- package/dist/server/lib/specArtifact.js.map +1 -1
- package/dist/server/lib/specDraft.js +10 -2
- package/dist/server/lib/specDraft.js.map +1 -1
- package/dist/server/lib/specExport.js +70 -6
- package/dist/server/lib/specExport.js.map +1 -1
- package/dist/server/lib/specFormatting.js +3 -2
- package/dist/server/lib/specFormatting.js.map +1 -1
- package/dist/server/lib/specRepositoryEvidenceFormatting.js +75 -0
- package/dist/server/lib/specRepositoryEvidenceFormatting.js.map +1 -0
- package/dist/server/lib/specRepositoryImpact.js +447 -0
- package/dist/server/lib/specRepositoryImpact.js.map +1 -0
- package/dist/server/lib/specRepositoryImpactLimits.js +6 -0
- package/dist/server/lib/specRepositoryImpactLimits.js.map +1 -0
- package/dist/server/lib/specReviewContext.js +15 -5
- package/dist/server/lib/specReviewContext.js.map +1 -1
- package/dist/server/lib/specReviewValidation.js +1 -1
- package/dist/server/lib/specReviewValidation.js.map +1 -1
- package/dist/server/lib/specSections.js +28 -3
- package/dist/server/lib/specSections.js.map +1 -1
- package/dist/server/lib/specSnapshotEvidence.js +162 -0
- package/dist/server/lib/specSnapshotEvidence.js.map +1 -0
- package/dist/server/lib/specSnapshotEvidenceSerialization.js +202 -0
- package/dist/server/lib/specSnapshotEvidenceSerialization.js.map +1 -0
- package/dist/server/lib/specs.js +31 -5
- package/dist/server/lib/specs.js.map +1 -1
- package/dist/server/lib/ticketAutomationCommit.js +3 -1
- package/dist/server/lib/ticketAutomationCommit.js.map +1 -1
- package/dist/server/lib/ticketFollowUpOperations.js +16 -12
- package/dist/server/lib/ticketFollowUpOperations.js.map +1 -1
- package/dist/server/lib/ticketRunOperations.js +13 -1
- package/dist/server/lib/ticketRunOperations.js.map +1 -1
- package/dist/server/lib/ticketWorkflowOperations.js +5 -2
- package/dist/server/lib/ticketWorkflowOperations.js.map +1 -1
- package/dist/server/lib/types.js +1 -0
- package/dist/server/lib/types.js.map +1 -1
- package/dist/server/workers/build.js +46 -148
- package/dist/server/workers/build.js.map +1 -1
- package/dist/server/workers/chat.js +141 -31
- package/dist/server/workers/chat.js.map +1 -1
- package/dist/server/workers/followUp.js +210 -48
- package/dist/server/workers/followUp.js.map +1 -1
- package/dist/server/workers/specReview.js +17 -4
- package/dist/server/workers/specReview.js.map +1 -1
- package/dist/server/workers/specSession.js +127 -22
- package/dist/server/workers/specSession.js.map +1 -1
- package/package.json +1 -1
- package/dist/client/assets/RepositoryGraphDialog-CS_hOqPw.js +0 -1
- package/dist/client/assets/VerificationDialog-BYH-Ek8n.js +0 -4
- package/dist/client/assets/channel-HjENOCZ0.js +0 -1
- package/dist/client/assets/classDiagram-4FO5ZUOK-DnhdaVrK.js +0 -1
- package/dist/client/assets/classDiagram-v2-Q7XG4LA2-C-BjeSGJ.js +0 -1
- package/dist/client/assets/index-Bs5SQZhz.css +0 -2
- package/dist/client/assets/index-LGNsdNYM.js +0 -274
- package/dist/client/assets/stateDiagram-v2-BHNVJYJU-vNiFfHwm.js +0 -1
|
@@ -1,7 +1,8 @@
|
|
|
1
1
|
import db from '../db.js';
|
|
2
|
-
import { formatAgentErrorForTranscript, getAgentErrorTranscriptRuns, runAgent } from '../lib/agent.js';
|
|
2
|
+
import { formatAgentErrorForTranscript, getAgentErrorTranscriptRuns, isAgentContinuationRejectedError, registerBuildProcessPlaceholder, runAgent, untrackBuildProcessById } from '../lib/agent.js';
|
|
3
|
+
import { acquireAgentSpawnPermit } from '../lib/agentSpawnPermits.js';
|
|
3
4
|
import { createAgentRun, emitAgentRunsUpdated, getAgentRun, terminalizeAgentRunsForExecutionRun } from '../lib/agentRuns.js';
|
|
4
|
-
import { getExecutionRun, withExecutionRunTransaction } from '../lib/executionRuns.js';
|
|
5
|
+
import { appendLifecycleEvent, getExecutionRun, withExecutionRunTransaction } from '../lib/executionRuns.js';
|
|
5
6
|
import config from '../lib/config.js';
|
|
6
7
|
import { failBuildOpenQuestionBatch, filterResolvedBuildOpenQuestionsForBatch, listBuildOpenQuestionsForBundle, reconcileBuildOpenQuestions, setBuildOpenQuestionBatchStatus, } from '../lib/buildOpenQuestions.js';
|
|
7
8
|
import { advanceBuildChain } from '../lib/buildChains.js';
|
|
@@ -24,6 +25,7 @@ import { getRequiredCheckPolicyPromptBlock } from '../lib/requiredCheckPolicyPro
|
|
|
24
25
|
import { clearTicketStreamingResponse, createTicketMessage, markTicketDescriptionVisibleInBundle, } from '../lib/ticketMessages.js';
|
|
25
26
|
import { captureStageSuccess } from '../lib/ticketUndo.js';
|
|
26
27
|
import { runPostBuildChecks } from '../lib/postBuildChecks.js';
|
|
28
|
+
import { finalizePostBuildCheckTicket, markPostBuildCheckFinalizationComplete, persistPendingPostBuildFinalization } from '../lib/postBuildCheckRuns.js';
|
|
27
29
|
import { beginTicketThinkingRun, bindTicketThinkingMessage } from '../lib/thinkingState.js';
|
|
28
30
|
import { autoParkTicketIfStale, getTicket, listTickets, resolveTicketBranch, resolveTicketContextKey, resolveTicketTool, resolveTicketWorkerKey } from '../lib/tickets.js';
|
|
29
31
|
import { decideReviewFollowUpAutomation, clearAutomationPause, depthAtLeast, getBundleAutomationState, resolveAutomationConfig, } from '../lib/ticketAutomation.js';
|
|
@@ -67,9 +69,6 @@ const updateStatus = (ticketId, status, log, io, operation) => {
|
|
|
67
69
|
const clearBuildCompletion = (ticketId) => {
|
|
68
70
|
db.prepare('UPDATE tickets SET build_completed_at = NULL, auto_park_dismissed_at = NULL, updated_at = CURRENT_TIMESTAMP WHERE id = ?').run(ticketId);
|
|
69
71
|
};
|
|
70
|
-
const markBuildCompleted = (ticketId) => {
|
|
71
|
-
db.prepare('UPDATE tickets SET build_completed_at = CURRENT_TIMESTAMP, updated_at = CURRENT_TIMESTAMP WHERE id = ?').run(ticketId);
|
|
72
|
-
};
|
|
73
72
|
const emitBundleTickets = (projectId, bundleId, io) => {
|
|
74
73
|
for (const bundleTicket of listTickets(projectId).filter(ticket => ticket.worktree_bundle_id === bundleId)) {
|
|
75
74
|
const refreshed = getTicket(bundleTicket.id);
|
|
@@ -195,7 +194,7 @@ Use the review findings as the source of truth unless the follow-up instruction
|
|
|
195
194
|
|
|
196
195
|
${getProjectMemorySuggestionPromptRules(memoryEnabled, 'follow_up')}` : ''}`;
|
|
197
196
|
};
|
|
198
|
-
const runReviewFollowUpCompletionAutomation = async (ticket, project, io, executionContext, initiation) => {
|
|
197
|
+
const runReviewFollowUpCompletionAutomation = async (ticket, project, io, executionContext, initiation, releaseOwnerQueue) => {
|
|
199
198
|
if (!ticket.worktree_bundle_id || !ticket.project_id) {
|
|
200
199
|
return false;
|
|
201
200
|
}
|
|
@@ -263,6 +262,7 @@ const runReviewFollowUpCompletionAutomation = async (ticket, project, io, execut
|
|
|
263
262
|
broadcaster: io,
|
|
264
263
|
initiation,
|
|
265
264
|
pausedStageRunId: executionContext.runId,
|
|
265
|
+
releaseOwnerQueue,
|
|
266
266
|
});
|
|
267
267
|
return true;
|
|
268
268
|
}
|
|
@@ -280,6 +280,7 @@ const runReviewFollowUpCompletionAutomation = async (ticket, project, io, execut
|
|
|
280
280
|
broadcaster: io,
|
|
281
281
|
initiation,
|
|
282
282
|
pausedStageRunId: executionContext.runId,
|
|
283
|
+
releaseOwnerQueue,
|
|
283
284
|
});
|
|
284
285
|
return true;
|
|
285
286
|
}
|
|
@@ -287,6 +288,20 @@ const runReviewFollowUpCompletionAutomation = async (ticket, project, io, execut
|
|
|
287
288
|
return false;
|
|
288
289
|
}
|
|
289
290
|
};
|
|
291
|
+
export const completeSuccessfulReviewPostFinalization = async ({ ticket, project, executionContext, initiation, io, releaseOwnerQueue, memorySuggestions, }) => {
|
|
292
|
+
if (project.memory_enabled && memorySuggestions.length > 0) {
|
|
293
|
+
persistProjectMemorySuggestions(project.id, ticket.id, 'follow_up', memorySuggestions);
|
|
294
|
+
}
|
|
295
|
+
const completedTicket = getTicket(ticket.id) ?? ticket;
|
|
296
|
+
captureStageSuccess(ticket.id, 'review');
|
|
297
|
+
const handled = await runReviewFollowUpCompletionAutomation(completedTicket, project, io, executionContext, initiation, releaseOwnerQueue);
|
|
298
|
+
if (!handled) {
|
|
299
|
+
const completed = autoParkTicketIfStale(ticket.id);
|
|
300
|
+
if (completed) {
|
|
301
|
+
io.emit('ticket:updated', completed);
|
|
302
|
+
}
|
|
303
|
+
}
|
|
304
|
+
};
|
|
290
305
|
export const isFollowUpRunning = (ticket) => {
|
|
291
306
|
const jobKey = resolveTicketWorkerKey(ticket, 'follow_up');
|
|
292
307
|
return !jobKey || isRunning(jobKey);
|
|
@@ -399,11 +414,18 @@ export function startFollowUp(ticket, io, instruction, mode = 'build', options =
|
|
|
399
414
|
updateStatus(ticket.id, 'running', null, io, operation);
|
|
400
415
|
}
|
|
401
416
|
const activityKind = ticket.state === 'build' ? 'build_follow_up' : 'review_follow_up';
|
|
417
|
+
const hasBuildCancellationHandle = mode !== 'plan' && (ticket.state === 'build' || ticket.state === 'review');
|
|
418
|
+
if (hasBuildCancellationHandle) {
|
|
419
|
+
registerBuildProcessPlaceholder(ticket.id);
|
|
420
|
+
}
|
|
402
421
|
let queuedJob;
|
|
403
422
|
try {
|
|
404
|
-
queuedJob = enqueue(jobKey, async () => {
|
|
423
|
+
queuedJob = enqueue(jobKey, async (releaseQueueOwnership) => {
|
|
405
424
|
const scheduledRun = getExecutionRun(executionContext.projectId, executionContext.runId);
|
|
406
425
|
if (!scheduledRun || !['queued', 'running', 'waiting'].includes(scheduledRun.status)) {
|
|
426
|
+
if (hasBuildCancellationHandle) {
|
|
427
|
+
untrackBuildProcessById(ticket.id);
|
|
428
|
+
}
|
|
407
429
|
if (options.buildOpenQuestionBatchId
|
|
408
430
|
&& scheduledRun
|
|
409
431
|
&& ['failed', 'cancelled', 'interrupted'].includes(scheduledRun.status)) {
|
|
@@ -414,6 +436,7 @@ export function startFollowUp(ticket, io, instruction, mode = 'build', options =
|
|
|
414
436
|
registerBundleActivity(ticket, activityKind);
|
|
415
437
|
let buildOpenQuestionBatchCompleted = false;
|
|
416
438
|
let sequenceHasNextBuild = false;
|
|
439
|
+
let postBuildContinuationHasNextBuild = false;
|
|
417
440
|
try {
|
|
418
441
|
withExecutionRunTransaction(transaction => {
|
|
419
442
|
const operation = ticket.state === 'review' && mode !== 'plan' ? 'follow_up' : null;
|
|
@@ -438,6 +461,9 @@ export function startFollowUp(ticket, io, instruction, mode = 'build', options =
|
|
|
438
461
|
}
|
|
439
462
|
const cwd = ticket.bundle?.kind === 'project_root' ? project.repo_path : resolveWorktreePath(branch, project);
|
|
440
463
|
await options.trustedOrchestration?.beforeStart(executionContext);
|
|
464
|
+
const spawnPermitId = options.trustedOrchestration
|
|
465
|
+
? acquireAgentSpawnPermit(executionContext.runId)
|
|
466
|
+
: undefined;
|
|
441
467
|
const runTicket = { ...ticket, ...runConfig };
|
|
442
468
|
const tool = resolveTicketTool(runTicket, config.tool ?? 'opencode');
|
|
443
469
|
const isBuildTicket = ticket.state === 'build';
|
|
@@ -454,17 +480,21 @@ export function startFollowUp(ticket, io, instruction, mode = 'build', options =
|
|
|
454
480
|
clearBuildCompletion(ticket.id);
|
|
455
481
|
}
|
|
456
482
|
const isReviewResume = isReviewTicket && !isPlanMode && Boolean(ticket.session_id) && hasPreviousReviewFollowUp(ticket);
|
|
457
|
-
const selectedPrompt = options.trustedOrchestration
|
|
458
|
-
?
|
|
459
|
-
:
|
|
460
|
-
?
|
|
461
|
-
:
|
|
483
|
+
const selectedPrompt = options.trustedOrchestration
|
|
484
|
+
? prependSkillPromptBlock(options.trustedOrchestration.prompt, runTicket.skills)
|
|
485
|
+
: (isPlanMode
|
|
486
|
+
? questionFollowUpPrompt(runTicket, instruction, Boolean(project.memory_enabled))
|
|
487
|
+
: isBuildTicket
|
|
488
|
+
? followUpPrompt(runTicket, project, instruction, Boolean(project.memory_enabled), !options.buildOpenQuestionBatchId)
|
|
489
|
+
: prependSkillPromptBlock(reviewFindingsFollowUpPrompt(runTicket, project, latestReviewFindings, instruction, Boolean(project.memory_enabled)), runTicket.skills));
|
|
462
490
|
const prompt = isBuildTicket && !isPlanMode
|
|
463
491
|
? appendFigmaInspectionGuidance(selectedPrompt, runTicket.description || runTicket.title, 'implementation')
|
|
464
492
|
: selectedPrompt;
|
|
465
|
-
const resumeSessionId = options.
|
|
466
|
-
?
|
|
467
|
-
:
|
|
493
|
+
const resumeSessionId = options.resumeSessionId !== undefined
|
|
494
|
+
? options.resumeSessionId
|
|
495
|
+
: options.providerContinuation === 'fresh' || isPlanMode
|
|
496
|
+
? null
|
|
497
|
+
: (isBuildTicket || isReviewResume ? ticket.session_id : null);
|
|
468
498
|
const mainRunId = createAgentRun({
|
|
469
499
|
executionRunId: executionContext.runId,
|
|
470
500
|
parentType: 'ticket',
|
|
@@ -477,29 +507,88 @@ export function startFollowUp(ticket, io, instruction, mode = 'build', options =
|
|
|
477
507
|
throw new Error('Unable to create the follow-up agent run');
|
|
478
508
|
}
|
|
479
509
|
emitAgentRunsUpdated(asGenericEmitter(io), 'ticket', ticket.id);
|
|
480
|
-
const
|
|
510
|
+
const launch = (run, sessionId, permitId) => runAgent({
|
|
481
511
|
ticketId: ticket.id,
|
|
482
512
|
tool,
|
|
483
513
|
prompt,
|
|
484
514
|
cwd,
|
|
485
515
|
model: runTicket.model,
|
|
486
516
|
variant: runTicket.variant,
|
|
487
|
-
resumeSessionId,
|
|
517
|
+
resumeSessionId: sessionId,
|
|
488
518
|
trackBuildProcess: !isPlanMode && (isBuildTicket || isReviewTicket),
|
|
489
519
|
emitSuccessUpdate: false,
|
|
490
520
|
persistSessionIdToTicket: !isPlanMode,
|
|
491
521
|
executionContext,
|
|
492
522
|
runStream: {
|
|
493
|
-
runId:
|
|
494
|
-
label:
|
|
495
|
-
role:
|
|
496
|
-
runIndex:
|
|
523
|
+
runId: run.id,
|
|
524
|
+
label: run.label,
|
|
525
|
+
role: run.role,
|
|
526
|
+
runIndex: run.run_index,
|
|
497
527
|
},
|
|
498
528
|
io,
|
|
499
529
|
opencodeAgentMode: isPlanMode ? mode : undefined,
|
|
530
|
+
spawnPermitId: permitId,
|
|
500
531
|
});
|
|
501
|
-
|
|
502
|
-
|
|
532
|
+
let agentResult;
|
|
533
|
+
let completedMainRun = mainRun;
|
|
534
|
+
if (options.trustedOrchestration && !resumeSessionId) {
|
|
535
|
+
appendLifecycleEvent({
|
|
536
|
+
projectId: executionContext.projectId,
|
|
537
|
+
runId: executionContext.runId,
|
|
538
|
+
domainStatus: 'running',
|
|
539
|
+
eventType: 'provider_fresh_without_historical_session',
|
|
540
|
+
}, asGenericEmitter(io));
|
|
541
|
+
}
|
|
542
|
+
try {
|
|
543
|
+
agentResult = await launch(mainRun, resumeSessionId, spawnPermitId);
|
|
544
|
+
if (options.trustedOrchestration && resumeSessionId) {
|
|
545
|
+
appendLifecycleEvent({
|
|
546
|
+
projectId: executionContext.projectId,
|
|
547
|
+
runId: executionContext.runId,
|
|
548
|
+
domainStatus: 'running',
|
|
549
|
+
eventType: 'provider_continuation_resumed',
|
|
550
|
+
}, asGenericEmitter(io));
|
|
551
|
+
}
|
|
552
|
+
}
|
|
553
|
+
catch (error) {
|
|
554
|
+
if (!options.trustedOrchestration || !resumeSessionId || !isAgentContinuationRejectedError(error)) {
|
|
555
|
+
if (options.trustedOrchestration && resumeSessionId) {
|
|
556
|
+
appendLifecycleEvent({
|
|
557
|
+
projectId: executionContext.projectId,
|
|
558
|
+
runId: executionContext.runId,
|
|
559
|
+
domainStatus: 'continuation_unsafe_failure',
|
|
560
|
+
eventType: 'provider_continuation_unsafe_failure',
|
|
561
|
+
}, asGenericEmitter(io));
|
|
562
|
+
}
|
|
563
|
+
throw error;
|
|
564
|
+
}
|
|
565
|
+
withExecutionRunTransaction(transaction => transaction.appendLifecycleEvent({
|
|
566
|
+
projectId: executionContext.projectId,
|
|
567
|
+
runId: executionContext.runId,
|
|
568
|
+
domainStatus: 'continuation_rejected_before_execution',
|
|
569
|
+
eventType: 'provider_continuation_rejected_before_execution',
|
|
570
|
+
}), asGenericEmitter(io));
|
|
571
|
+
await options.trustedOrchestration.onContinuationFallback?.(executionContext);
|
|
572
|
+
await options.trustedOrchestration.beforeStart(executionContext);
|
|
573
|
+
const fallbackPermitId = acquireAgentSpawnPermit(executionContext.runId);
|
|
574
|
+
const fallbackRunId = createAgentRun({
|
|
575
|
+
executionRunId: executionContext.runId,
|
|
576
|
+
parentType: 'ticket',
|
|
577
|
+
parentId: ticket.id,
|
|
578
|
+
label: `${mainRun.label} (fresh fallback)`,
|
|
579
|
+
role: 'main',
|
|
580
|
+
});
|
|
581
|
+
const fallbackRun = getAgentRun(fallbackRunId);
|
|
582
|
+
if (!fallbackRun) {
|
|
583
|
+
throw new Error('Unable to create the fresh fallback AgentRun');
|
|
584
|
+
}
|
|
585
|
+
emitAgentRunsUpdated(asGenericEmitter(io), 'ticket', ticket.id);
|
|
586
|
+
completedMainRun = fallbackRun;
|
|
587
|
+
agentResult = await launch(fallbackRun, null, fallbackPermitId);
|
|
588
|
+
}
|
|
589
|
+
const { response: finalResponse, responseTiming, transcriptRuns } = agentResult;
|
|
590
|
+
const persistedCompletedMainRun = getAgentRun(completedMainRun.id);
|
|
591
|
+
const completionStatus = persistedCompletedMainRun?.agent_status === 'stopped' ? 'stopped' : 'done';
|
|
503
592
|
const askQuestion = isPlanMode && completionStatus === 'done' && typeof finalResponse === 'string'
|
|
504
593
|
? extractAskQuestionFromOutput(finalResponse)
|
|
505
594
|
: { questionSet: null, cleanedOutput: finalResponse ?? '', error: null };
|
|
@@ -559,6 +648,9 @@ export function startFollowUp(ticket, io, instruction, mode = 'build', options =
|
|
|
559
648
|
openQuestions,
|
|
560
649
|
})
|
|
561
650
|
: parsedResponse.response.trim();
|
|
651
|
+
const shouldDeferPostBuildCompletion = !isPlanMode
|
|
652
|
+
&& completionStatus === 'done'
|
|
653
|
+
&& !options.trustedOrchestration;
|
|
562
654
|
const authoritativeResult = withExecutionRunTransaction(transaction => {
|
|
563
655
|
const assistantMessageId = assistantMessage
|
|
564
656
|
? createTicketMessage({
|
|
@@ -570,11 +662,21 @@ export function startFollowUp(ticket, io, instruction, mode = 'build', options =
|
|
|
570
662
|
transcriptRuns,
|
|
571
663
|
})
|
|
572
664
|
: null;
|
|
573
|
-
db.prepare('UPDATE tickets SET agent_status = ?, agent_log = NULL, streaming_response = NULL, updated_at = CURRENT_TIMESTAMP WHERE id = ? AND project_id = ?').run(
|
|
665
|
+
db.prepare('UPDATE tickets SET agent_status = ?, agent_log = NULL, streaming_response = NULL, updated_at = CURRENT_TIMESTAMP WHERE id = ? AND project_id = ?').run((shouldDeferPostBuildCompletion || (isBuildTicket
|
|
666
|
+
&& !isPlanMode
|
|
667
|
+
&& completionStatus === 'done'
|
|
668
|
+
&& options.trustedOrchestration?.preserveOwnerRunningOnCompletion))
|
|
669
|
+
? 'running'
|
|
670
|
+
: completionStatus, ticket.id, executionContext.projectId);
|
|
574
671
|
const completedTicket = getTicket(ticket.id) ?? ticket;
|
|
575
|
-
if (
|
|
576
|
-
|
|
577
|
-
|
|
672
|
+
if (shouldDeferPostBuildCompletion) {
|
|
673
|
+
if (isBuildTicket) {
|
|
674
|
+
persistPendingPostBuildFinalization(executionContext.projectId, executionContext.runId, parsedResponse.suggestions);
|
|
675
|
+
}
|
|
676
|
+
else {
|
|
677
|
+
persistPendingPostBuildFinalization(executionContext.projectId, executionContext.runId, parsedResponse.suggestions, 'review');
|
|
678
|
+
}
|
|
679
|
+
if (isBuildTicket && parsedResponse.hasOpenQuestionsMetadata) {
|
|
578
680
|
db.prepare('UPDATE tickets SET planning_context_json = ?, updated_at = CURRENT_TIMESTAMP WHERE id = ?').run(JSON.stringify(createTicketOpenQuestionsContext(completedTicket, openQuestions)), ticket.id);
|
|
579
681
|
if (ticket.project_id && ticket.worktree_bundle_id) {
|
|
580
682
|
reconcileBuildOpenQuestions({
|
|
@@ -628,22 +730,36 @@ export function startFollowUp(ticket, io, instruction, mode = 'build', options =
|
|
|
628
730
|
bindTicketThinkingMessage(ticket.id, assistantMessageId);
|
|
629
731
|
}
|
|
630
732
|
emitAgentRunsUpdated(asGenericEmitter(io), 'ticket', ticket.id);
|
|
631
|
-
|
|
632
|
-
|
|
633
|
-
|
|
733
|
+
let finalizedBuildTicket = null;
|
|
734
|
+
let buildPostBuildFinalized = false;
|
|
735
|
+
const completedBeforePostBuild = getTicket(ticket.id) ?? ticket;
|
|
736
|
+
if (shouldDeferPostBuildCompletion) {
|
|
737
|
+
const postBuildResult = await runPostBuildChecks({
|
|
634
738
|
project,
|
|
635
739
|
sourceRunId: executionContext.runId,
|
|
636
|
-
owner: { kind: 'ticket', ticket:
|
|
740
|
+
owner: { kind: 'ticket', ticket: completedBeforePostBuild },
|
|
637
741
|
onStatusChange: () => emitUpdatedTickets([ticket.id], io),
|
|
638
742
|
emitter: asGenericEmitter(io),
|
|
743
|
+
releaseOwnerQueue: releaseQueueOwnership,
|
|
744
|
+
});
|
|
745
|
+
const finalization = finalizePostBuildCheckTicket({
|
|
746
|
+
projectId: executionContext.projectId,
|
|
747
|
+
sourceRunId: executionContext.runId,
|
|
748
|
+
batch: postBuildResult?.batch ?? null,
|
|
749
|
+
error: postBuildResult?.error ?? null,
|
|
750
|
+
getTicket,
|
|
751
|
+
emitter: asGenericEmitter(io),
|
|
639
752
|
});
|
|
753
|
+
finalizedBuildTicket = finalization.ticket;
|
|
754
|
+
buildPostBuildFinalized = finalization.finalized;
|
|
640
755
|
}
|
|
756
|
+
const completedTicket = finalizedBuildTicket ?? getTicket(ticket.id) ?? ticket;
|
|
641
757
|
const bundleReadyForAutomaticReview = Boolean(ticket.project_id
|
|
642
758
|
&& ticket.worktree_bundle_id
|
|
643
759
|
&& areBundleTicketsReadyForAutomaticReview(listTickets(ticket.project_id), ticket.worktree_bundle_id));
|
|
644
760
|
const preserveAutomaticReviewOwner = bundleReadyForAutomaticReview
|
|
645
761
|
&& depthAtLeast(resolveAutomationConfig(completedTicket.bundle ?? null, project).depth, 'auto_review');
|
|
646
|
-
if (isBuildTicket && !isPlanMode && completedTicket.agent_status === 'done' && !options.trustedOrchestration) {
|
|
762
|
+
if (isBuildTicket && !isPlanMode && buildPostBuildFinalized && completedTicket.agent_status === 'done' && !options.trustedOrchestration) {
|
|
647
763
|
captureStageSuccess(ticket.id, 'build');
|
|
648
764
|
if (!preserveAutomaticReviewOwner) {
|
|
649
765
|
const completed = autoParkTicketIfStale(ticket.id);
|
|
@@ -659,10 +775,12 @@ export function startFollowUp(ticket, io, instruction, mode = 'build', options =
|
|
|
659
775
|
workflowContext: options.initiation?.workflowContext ?? null,
|
|
660
776
|
io,
|
|
661
777
|
emitUpdatedTickets: ticketIds => emitUpdatedTickets(ticketIds, io),
|
|
778
|
+
releaseOwnerQueue: releaseQueueOwnership,
|
|
662
779
|
});
|
|
663
780
|
if (continuation.nextTicketId) {
|
|
664
781
|
sequenceHasNextBuild = true;
|
|
665
782
|
}
|
|
783
|
+
postBuildContinuationHasNextBuild = Boolean(continuation.nextBuild);
|
|
666
784
|
if (continuation.nextBuild) {
|
|
667
785
|
const nextBuild = continuation.nextBuild;
|
|
668
786
|
const nextSequenceId = continuation.nextSequenceId;
|
|
@@ -704,6 +822,7 @@ export function startFollowUp(ticket, io, instruction, mode = 'build', options =
|
|
|
704
822
|
const stoppedSequence = stopBuildSequence(nextBuild.id);
|
|
705
823
|
emitUpdatedTickets(stoppedSequence.affectedTicketIds, io);
|
|
706
824
|
}
|
|
825
|
+
markPostBuildCheckFinalizationComplete(executionContext.projectId, executionContext.runId);
|
|
707
826
|
};
|
|
708
827
|
if (resolveTicketContextKey(nextBuild) === resolveTicketContextKey(ticket)) {
|
|
709
828
|
queuedJob.finally(scheduleNextBuild).catch(() => { });
|
|
@@ -764,6 +883,7 @@ export function startFollowUp(ticket, io, instruction, mode = 'build', options =
|
|
|
764
883
|
}
|
|
765
884
|
if (isBuildTicket
|
|
766
885
|
&& !isPlanMode
|
|
886
|
+
&& buildPostBuildFinalized
|
|
767
887
|
&& completedTicket.agent_status === 'done'
|
|
768
888
|
&& parsedResponse.hasOpenQuestionsMetadata
|
|
769
889
|
&& !sequenceHasNextBuild) {
|
|
@@ -810,7 +930,9 @@ export function startFollowUp(ticket, io, instruction, mode = 'build', options =
|
|
|
810
930
|
emitBundleTickets(ticket.project_id, ticket.worktree_bundle_id, io);
|
|
811
931
|
}
|
|
812
932
|
}
|
|
813
|
-
if (project.memory_enabled
|
|
933
|
+
if (project.memory_enabled
|
|
934
|
+
&& parsedResponse.suggestions.length > 0
|
|
935
|
+
&& (isPlanMode || isBuildTicket)) {
|
|
814
936
|
persistProjectMemorySuggestions(project.id, ticket.id, 'follow_up', parsedResponse.suggestions);
|
|
815
937
|
}
|
|
816
938
|
clearTicketStreamingResponse(ticket.id);
|
|
@@ -819,7 +941,7 @@ export function startFollowUp(ticket, io, instruction, mode = 'build', options =
|
|
|
819
941
|
io.emit('ticket:updated', completedWithMessage);
|
|
820
942
|
}
|
|
821
943
|
if (options.trustedOrchestration) {
|
|
822
|
-
if (
|
|
944
|
+
if (completionStatus === 'done') {
|
|
823
945
|
await options.trustedOrchestration.onCompletion(executionContext);
|
|
824
946
|
}
|
|
825
947
|
else if (completedTicket.agent_status === 'stopped') {
|
|
@@ -828,7 +950,7 @@ export function startFollowUp(ticket, io, instruction, mode = 'build', options =
|
|
|
828
950
|
}
|
|
829
951
|
else if (!isPlanMode) {
|
|
830
952
|
const updated = getTicket(ticket.id);
|
|
831
|
-
if (isBuildTicket && updated?.agent_status === 'done') {
|
|
953
|
+
if (isBuildTicket && buildPostBuildFinalized && updated?.agent_status === 'done') {
|
|
832
954
|
if (ticket.project_id && ticket.worktree_bundle_id && !sequenceHasNextBuild) {
|
|
833
955
|
if (options.buildOpenQuestionBatchId) {
|
|
834
956
|
if (!parsedResponse.hasOpenQuestionsMetadata) {
|
|
@@ -875,6 +997,7 @@ export function startFollowUp(ticket, io, instruction, mode = 'build', options =
|
|
|
875
997
|
broadcaster: io,
|
|
876
998
|
initiation: options.initiation,
|
|
877
999
|
pausedStageRunId: executionContext.runId,
|
|
1000
|
+
releaseOwnerQueue: releaseQueueOwnership,
|
|
878
1001
|
});
|
|
879
1002
|
}
|
|
880
1003
|
else if (ownedProgressionRunId) {
|
|
@@ -924,27 +1047,37 @@ export function startFollowUp(ticket, io, instruction, mode = 'build', options =
|
|
|
924
1047
|
workflowContext: options.initiation?.workflowContext ?? null,
|
|
925
1048
|
},
|
|
926
1049
|
pausedStageRunId: executionContext.runId,
|
|
1050
|
+
releaseOwnerQueue: releaseQueueOwnership,
|
|
927
1051
|
});
|
|
928
1052
|
}
|
|
929
1053
|
emitBundleTickets(ticket.project_id, ticket.worktree_bundle_id, io);
|
|
930
1054
|
}
|
|
931
1055
|
}
|
|
932
|
-
else if (!isBuildTicket
|
|
933
|
-
|
|
934
|
-
|
|
935
|
-
|
|
936
|
-
|
|
937
|
-
|
|
938
|
-
|
|
939
|
-
|
|
940
|
-
|
|
1056
|
+
else if (!isBuildTicket
|
|
1057
|
+
&& updated?.agent_status === 'done'
|
|
1058
|
+
&& (!shouldDeferPostBuildCompletion || buildPostBuildFinalized)) {
|
|
1059
|
+
await completeSuccessfulReviewPostFinalization({
|
|
1060
|
+
ticket: updated,
|
|
1061
|
+
project,
|
|
1062
|
+
executionContext,
|
|
1063
|
+
initiation: options.initiation,
|
|
1064
|
+
io,
|
|
1065
|
+
releaseOwnerQueue: releaseQueueOwnership,
|
|
1066
|
+
memorySuggestions: parsedResponse.suggestions,
|
|
1067
|
+
});
|
|
941
1068
|
}
|
|
942
1069
|
}
|
|
1070
|
+
if (!isPlanMode
|
|
1071
|
+
&& buildPostBuildFinalized
|
|
1072
|
+
&& (!isBuildTicket || !postBuildContinuationHasNextBuild)) {
|
|
1073
|
+
markPostBuildCheckFinalizationComplete(executionContext.projectId, executionContext.runId);
|
|
1074
|
+
}
|
|
943
1075
|
}
|
|
944
1076
|
catch (error) {
|
|
945
1077
|
const executionRun = getExecutionRun(executionContext.projectId, executionContext.runId);
|
|
946
1078
|
if (executionRun && !['queued', 'running', 'waiting'].includes(executionRun.status)) {
|
|
947
1079
|
if (options.trustedOrchestration) {
|
|
1080
|
+
releaseQueueOwnership();
|
|
948
1081
|
await options.trustedOrchestration.onCancellation(executionContext);
|
|
949
1082
|
return;
|
|
950
1083
|
}
|
|
@@ -1049,8 +1182,20 @@ export function startFollowUp(ticket, io, instruction, mode = 'build', options =
|
|
|
1049
1182
|
},
|
|
1050
1183
|
});
|
|
1051
1184
|
}
|
|
1052
|
-
|
|
1053
|
-
|
|
1185
|
+
const ownerProjection = options.trustedOrchestration?.preserveOwnerOnFailure
|
|
1186
|
+
? options.trustedOrchestration.ownerProjectionBeforeRun
|
|
1187
|
+
: null;
|
|
1188
|
+
if (ownerProjection) {
|
|
1189
|
+
db.prepare(`
|
|
1190
|
+
UPDATE tickets SET agent_status = ?, agent_operation = ?, agent_log = ?, streaming_response = ?,
|
|
1191
|
+
updated_at = CURRENT_TIMESTAMP
|
|
1192
|
+
WHERE id = ? AND project_id = ? AND agent_status = 'running'
|
|
1193
|
+
`).run(ownerProjection.agentStatus, ownerProjection.agentOperation, ownerProjection.agentLog, ownerProjection.streamingResponse, ticket.id, executionContext.projectId);
|
|
1194
|
+
}
|
|
1195
|
+
else {
|
|
1196
|
+
db.prepare('UPDATE tickets SET agent_status = ?, agent_log = ?, streaming_response = NULL, updated_at = CURRENT_TIMESTAMP WHERE id = ? AND project_id = ?')
|
|
1197
|
+
.run('error', message, ticket.id, executionContext.projectId);
|
|
1198
|
+
}
|
|
1054
1199
|
if (ticket.state === 'build' && mode !== 'plan' && !options.trustedOrchestration) {
|
|
1055
1200
|
affectedTicketIds = advanceBuildChain(ticket.id, 'error').affectedTicketIds;
|
|
1056
1201
|
}
|
|
@@ -1064,7 +1209,10 @@ export function startFollowUp(ticket, io, instruction, mode = 'build', options =
|
|
|
1064
1209
|
eventType: 'build_follow_up_failed',
|
|
1065
1210
|
});
|
|
1066
1211
|
}, asGenericEmitter(io));
|
|
1067
|
-
|
|
1212
|
+
if (options.trustedOrchestration) {
|
|
1213
|
+
releaseQueueOwnership();
|
|
1214
|
+
await options.trustedOrchestration.onFailure(executionContext, message);
|
|
1215
|
+
}
|
|
1068
1216
|
emitUpdatedTickets(affectedTicketIds, io);
|
|
1069
1217
|
if (ownedReviewFixRunId && ownedReviewProgressionRunId && ticket.project_id && ticket.worktree_bundle_id) {
|
|
1070
1218
|
finishAutomationReviewFix({
|
|
@@ -1085,14 +1233,28 @@ export function startFollowUp(ticket, io, instruction, mode = 'build', options =
|
|
|
1085
1233
|
});
|
|
1086
1234
|
}
|
|
1087
1235
|
emitAgentRunsUpdated(asGenericEmitter(io), 'ticket', ticket.id);
|
|
1088
|
-
|
|
1236
|
+
if (options.trustedOrchestration?.preserveOwnerOnFailure) {
|
|
1237
|
+
const restoredTicket = getTicket(ticket.id);
|
|
1238
|
+
if (restoredTicket) {
|
|
1239
|
+
io.emit('ticket:updated', restoredTicket);
|
|
1240
|
+
}
|
|
1241
|
+
}
|
|
1242
|
+
else {
|
|
1243
|
+
updateStatus(ticket.id, 'error', message, io);
|
|
1244
|
+
}
|
|
1089
1245
|
}
|
|
1090
1246
|
finally {
|
|
1091
1247
|
unregisterBundleActivity(ticket, activityKind);
|
|
1248
|
+
if (hasBuildCancellationHandle) {
|
|
1249
|
+
untrackBuildProcessById(ticket.id);
|
|
1250
|
+
}
|
|
1092
1251
|
}
|
|
1093
1252
|
});
|
|
1094
1253
|
}
|
|
1095
1254
|
catch (error) {
|
|
1255
|
+
if (hasBuildCancellationHandle) {
|
|
1256
|
+
untrackBuildProcessById(ticket.id);
|
|
1257
|
+
}
|
|
1096
1258
|
const message = getErrorMessage(error);
|
|
1097
1259
|
withExecutionRunTransaction(transaction => {
|
|
1098
1260
|
options.compensate?.();
|