@straiffi/archon 1.8.12 → 1.8.14
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-CEETnHri.js → ActivityView-DYDYyqIN.js} +1 -1
- package/dist/client/assets/{GitHubActionsDialog-CjBW65OR.js → GitHubActionsDialog-jhi4GOyV.js} +1 -1
- package/dist/client/assets/{RepositoryGraphDialog-F3C0n89W.js → RepositoryGraphDialog-BZV0vHu6.js} +1 -1
- package/dist/client/assets/{VerificationDialog-DD1CLydA.js → VerificationDialog-Sc6e8AKH.js} +1 -1
- package/dist/client/assets/{architectureDiagram-3BPJPVTR-COl_GdZ6.js → architectureDiagram-3BPJPVTR-DFbki8mi.js} +1 -1
- package/dist/client/assets/{blockDiagram-GPEHLZMM-qojIlH-q.js → blockDiagram-GPEHLZMM-BZFehG8P.js} +1 -1
- package/dist/client/assets/{c4Diagram-AAUBKEIU-DFtG4fMg.js → c4Diagram-AAUBKEIU-FVDXRu1t.js} +1 -1
- package/dist/client/assets/channel-D1kOpezG.js +1 -0
- package/dist/client/assets/{chunk-2J33WTMH-TJkOJXbn.js → chunk-2J33WTMH-4tuVZaT0.js} +1 -1
- package/dist/client/assets/{chunk-3OPIFGDE-CELQ603z.js → chunk-3OPIFGDE-DSn14S35.js} +1 -1
- package/dist/client/assets/{chunk-5ZQYHXKU-BgPEJ16b.js → chunk-5ZQYHXKU-Cwx1KNjg.js} +1 -1
- package/dist/client/assets/{chunk-727SXJPM-Biph-aPf.js → chunk-727SXJPM-Odza4hes.js} +1 -1
- package/dist/client/assets/{chunk-AQP2D5EJ-CPVToZH6.js → chunk-AQP2D5EJ-BmVoQT7M.js} +1 -1
- package/dist/client/assets/{chunk-CSCIHK7Q-BHO9oB4A.js → chunk-CSCIHK7Q-Bg7Ktx0B.js} +1 -1
- package/dist/client/assets/{chunk-KSCS5N6A-B8vatrko.js → chunk-KSCS5N6A-2tnhar2x.js} +1 -1
- package/dist/client/assets/{chunk-L5ZTLDWV-DvzBHR4-.js → chunk-L5ZTLDWV-dAyg8qMJ.js} +1 -1
- package/dist/client/assets/{chunk-LZXEDZCA-Bm8cj-JK.js → chunk-LZXEDZCA-0gElxrlR.js} +2 -2
- package/dist/client/assets/{chunk-ND2GUHAM-BPQZvPl9.js → chunk-ND2GUHAM-Bu-8Lz91.js} +1 -1
- package/dist/client/assets/{chunk-NZK2D7GU-DEQVA6Ya.js → chunk-NZK2D7GU-CInZFdzd.js} +1 -1
- package/dist/client/assets/{chunk-O5CBEL6O-hPGqWilt.js → chunk-O5CBEL6O-rAzpvdNR.js} +1 -1
- package/dist/client/assets/{chunk-WU5MYG2G-D0VvFXkQ.js → chunk-WU5MYG2G-DOOw2vq7.js} +1 -1
- package/dist/client/assets/classDiagram-4FO5ZUOK-C253nwny.js +1 -0
- package/dist/client/assets/classDiagram-v2-Q7XG4LA2-DFgDA23g.js +1 -0
- package/dist/client/assets/{dagre-BM42HDAG-rmJlMuw_.js → dagre-BM42HDAG-Dgua1iuh.js} +1 -1
- package/dist/client/assets/{diagram-2AECGRRQ-BqejYr09.js → diagram-2AECGRRQ-odacwlwu.js} +1 -1
- package/dist/client/assets/{diagram-5GNKFQAL-DGSf1BNT.js → diagram-5GNKFQAL-BiKjFmJ1.js} +1 -1
- package/dist/client/assets/{diagram-KO2AKTUF-e_TRdqvx.js → diagram-KO2AKTUF-CmYcvFri.js} +1 -1
- package/dist/client/assets/{diagram-LMA3HP47-CTSnwgUq.js → diagram-LMA3HP47-ncx0RBuX.js} +1 -1
- package/dist/client/assets/{diagram-OG6HWLK6-mUn9Y0aC.js → diagram-OG6HWLK6-DbchKIzw.js} +1 -1
- package/dist/client/assets/{erDiagram-TEJ5UH35-TmdWUwfA.js → erDiagram-TEJ5UH35-CMnpvRyQ.js} +1 -1
- package/dist/client/assets/{flowDiagram-I6XJVG4X-CoE0KTIp.js → flowDiagram-I6XJVG4X-Bi02_PK5.js} +1 -1
- package/dist/client/assets/{ganttDiagram-6RSMTGT7-FkX1d1D7.js → ganttDiagram-6RSMTGT7-BiS992US.js} +1 -1
- package/dist/client/assets/{gitGraphDiagram-PVQCEYII-CXze3DV2.js → gitGraphDiagram-PVQCEYII-Cc1hrTsT.js} +1 -1
- package/dist/client/assets/index-B1gdJKwK.js +275 -0
- package/dist/client/assets/index-CCQwWUKF.css +2 -0
- package/dist/client/assets/{infoDiagram-5YYISTIA-CO0CivOy.js → infoDiagram-5YYISTIA-BKVfqJCe.js} +1 -1
- package/dist/client/assets/{ishikawaDiagram-YF4QCWOH-pEp8gScG.js → ishikawaDiagram-YF4QCWOH-B-IbFOty.js} +1 -1
- package/dist/client/assets/{journeyDiagram-JHISSGLW-BAnBAX-u.js → journeyDiagram-JHISSGLW-DAZBgAQW.js} +1 -1
- package/dist/client/assets/{kanban-definition-UN3LZRKU-Cqe-m5fR.js → kanban-definition-UN3LZRKU-Bkr_fXev.js} +1 -1
- package/dist/client/assets/{line-CKXoUXdX.js → line-CROuuXDO.js} +1 -1
- package/dist/client/assets/{mermaid-parser.core-7XZHbu9R.js → mermaid-parser.core-DrBw_Rsc.js} +1 -1
- package/dist/client/assets/{mermaid.core-CsF9gbdO.js → mermaid.core-pPd6OYYj.js} +3 -3
- package/dist/client/assets/{mindmap-definition-RKZ34NQL-88fK1Uq_.js → mindmap-definition-RKZ34NQL-BXSd3TZU.js} +1 -1
- package/dist/client/assets/{pieDiagram-4H26LBE5-DHFlSAwL.js → pieDiagram-4H26LBE5-DoT7PIZC.js} +1 -1
- package/dist/client/assets/{quadrantDiagram-W4KKPZXB-D5WyQ5EU.js → quadrantDiagram-W4KKPZXB-ycZkLowm.js} +1 -1
- package/dist/client/assets/{requirementDiagram-4Y6WPE33-DGkMfp_N.js → requirementDiagram-4Y6WPE33-BPkO1yLu.js} +1 -1
- package/dist/client/assets/{sankeyDiagram-5OEKKPKP-loJAHDiT.js → sankeyDiagram-5OEKKPKP-D7AvhhCw.js} +1 -1
- package/dist/client/assets/{sequenceDiagram-3UESZ5HK-xgcwtjyW.js → sequenceDiagram-3UESZ5HK-C982swnH.js} +1 -1
- package/dist/client/assets/{stateDiagram-AJRCARHV-BB95DmQX.js → stateDiagram-AJRCARHV-xvJ3u8lc.js} +1 -1
- package/dist/client/assets/stateDiagram-v2-BHNVJYJU-BKQG8NCn.js +1 -0
- package/dist/client/assets/{timeline-definition-PNZ67QCA-OCHTEVfL.js → timeline-definition-PNZ67QCA-D89qjzb5.js} +1 -1
- package/dist/client/assets/{vennDiagram-CIIHVFJN-Bo_7YNy2.js → vennDiagram-CIIHVFJN-CoKeC__u.js} +1 -1
- package/dist/client/assets/{wardleyDiagram-YWT4CUSO-DquywRz0.js → wardleyDiagram-YWT4CUSO-DKhjzvSE.js} +1 -1
- package/dist/client/assets/{xychartDiagram-2RQKCTM6-BLNrbCwd.js → xychartDiagram-2RQKCTM6-DFn9ass1.js} +1 -1
- package/dist/client/index.html +2 -2
- package/dist/server/db.js +77 -2
- package/dist/server/db.js.map +1 -1
- package/dist/server/index.js +90 -17
- package/dist/server/index.js.map +1 -1
- package/dist/server/lib/agent.js +205 -242
- package/dist/server/lib/agent.js.map +1 -1
- package/dist/server/lib/agentProvider.js +64 -0
- package/dist/server/lib/agentProvider.js.map +1 -0
- package/dist/server/lib/agentRuns.js +1 -0
- package/dist/server/lib/agentRuns.js.map +1 -1
- package/dist/server/lib/automationProgression.js +6 -2
- package/dist/server/lib/automationProgression.js.map +1 -1
- package/dist/server/lib/automationReconciliation.js +20 -0
- package/dist/server/lib/automationReconciliation.js.map +1 -1
- package/dist/server/lib/automationResumeDecision.js +6 -5
- package/dist/server/lib/automationResumeDecision.js.map +1 -1
- package/dist/server/lib/buildCompletionContinuation.js +1 -1
- package/dist/server/lib/buildCompletionContinuation.js.map +1 -1
- package/dist/server/lib/claudeAgentProvider.js +48 -0
- package/dist/server/lib/claudeAgentProvider.js.map +1 -0
- package/dist/server/lib/executionEnvironment.js +20 -0
- package/dist/server/lib/executionEnvironment.js.map +1 -0
- package/dist/server/lib/executionReconciliation.js +43 -4
- package/dist/server/lib/executionReconciliation.js.map +1 -1
- package/dist/server/lib/executionRetry.js +16 -9
- package/dist/server/lib/executionRetry.js.map +1 -1
- package/dist/server/lib/executionRetryPredicates.js +12 -3
- package/dist/server/lib/executionRetryPredicates.js.map +1 -1
- package/dist/server/lib/git.js +4 -4
- package/dist/server/lib/git.js.map +1 -1
- package/dist/server/lib/hostExecutionEnvironment.js +77 -0
- package/dist/server/lib/hostExecutionEnvironment.js.map +1 -0
- package/dist/server/lib/lightweightPrompt.js +17 -54
- package/dist/server/lib/lightweightPrompt.js.map +1 -1
- package/dist/server/lib/opencodeAgentProvider.js +139 -0
- package/dist/server/lib/opencodeAgentProvider.js.map +1 -0
- package/dist/server/lib/opencodeErrors.js +35 -0
- package/dist/server/lib/opencodeErrors.js.map +1 -0
- package/dist/server/lib/opencodePromptOutput.js +112 -0
- package/dist/server/lib/opencodePromptOutput.js.map +1 -0
- package/dist/server/lib/opencodeSessionOperations.js +348 -0
- package/dist/server/lib/opencodeSessionOperations.js.map +1 -0
- package/dist/server/lib/opencodeTaskSessions.js +13 -225
- package/dist/server/lib/opencodeTaskSessions.js.map +1 -1
- package/dist/server/lib/postBuildCheckRuns.js +16 -12
- package/dist/server/lib/postBuildCheckRuns.js.map +1 -1
- package/dist/server/lib/postBuildChecks.js +45 -43
- package/dist/server/lib/postBuildChecks.js.map +1 -1
- package/dist/server/lib/previewProxy.js +36 -4
- package/dist/server/lib/previewProxy.js.map +1 -1
- package/dist/server/lib/projectAutoConfig.js +27 -97
- package/dist/server/lib/projectAutoConfig.js.map +1 -1
- package/dist/server/lib/projects.js +34 -6
- package/dist/server/lib/projects.js.map +1 -1
- package/dist/server/lib/reviewContext.js +10 -5
- package/dist/server/lib/reviewContext.js.map +1 -1
- package/dist/server/lib/reviewFindings.js +201 -27
- package/dist/server/lib/reviewFindings.js.map +1 -1
- package/dist/server/lib/reviewerConfig.js +23 -0
- package/dist/server/lib/reviewerConfig.js.map +1 -0
- package/dist/server/lib/specReviewOperations.js +64 -9
- package/dist/server/lib/specReviewOperations.js.map +1 -1
- package/dist/server/lib/ticketFollowUpOperations.js +28 -0
- package/dist/server/lib/ticketFollowUpOperations.js.map +1 -1
- package/dist/server/lib/tickets.js +15 -0
- package/dist/server/lib/tickets.js.map +1 -1
- package/dist/server/lib/types.js.map +1 -1
- package/dist/server/workers/build.js +8 -1
- package/dist/server/workers/build.js.map +1 -1
- package/dist/server/workers/followUp.js +15 -6
- package/dist/server/workers/followUp.js.map +1 -1
- package/dist/server/workers/plan.js +5 -21
- package/dist/server/workers/plan.js.map +1 -1
- package/dist/server/workers/review.js +176 -70
- package/dist/server/workers/review.js.map +1 -1
- package/dist/server/workers/specReview.js +26 -11
- package/dist/server/workers/specReview.js.map +1 -1
- package/package.json +1 -1
- package/dist/client/assets/channel-DJLjk5--.js +0 -1
- package/dist/client/assets/classDiagram-4FO5ZUOK-aHXCyXE_.js +0 -1
- package/dist/client/assets/classDiagram-v2-Q7XG4LA2-CRPsGis_.js +0 -1
- package/dist/client/assets/index-B9S66NLn.css +0 -2
- package/dist/client/assets/index-CHsj9z-M.js +0 -275
- package/dist/client/assets/stateDiagram-v2-BHNVJYJU-DKhxPOLT.js +0 -1
|
@@ -2,15 +2,17 @@ import db from '../db.js';
|
|
|
2
2
|
import { assertNoActiveAutomationChild } from '../lib/activeAutomationChild.js';
|
|
3
3
|
import { formatAgentErrorForTranscript, getAgentErrorTranscriptRuns, registerReviewProcess, runAgent, storeTicketUsageSnapshot, storeTicketUsageSnapshotDirect, untrackReviewProcess, } from '../lib/agent.js';
|
|
4
4
|
import config from '../lib/config.js';
|
|
5
|
+
import { getBundlePullRequestRecord } from '../lib/bundlePullRequests.js';
|
|
5
6
|
import { persistProjectMemorySuggestions } from '../lib/projectMemory.js';
|
|
6
7
|
import { getReviewDiffDataAsync, resolveWorktreePath } from '../lib/git.js';
|
|
7
8
|
import { getProjectMemoryPromptBlock } from '../lib/projectMemoryPrompt.js';
|
|
8
9
|
import { extractProjectMemorySuggestionsFromOutput, getProjectMemorySuggestionPromptRules } from '../lib/projectMemorySuggestions.js';
|
|
9
10
|
import { getEffectiveProject } from '../lib/projects.js';
|
|
11
|
+
import { resolveReviewerConfig } from '../lib/reviewerConfig.js';
|
|
10
12
|
import { enqueue, isRunning } from '../lib/queue.js';
|
|
11
13
|
import { getExecutionRun, transitionExecutionRun, withExecutionRunTransaction } from '../lib/executionRuns.js';
|
|
12
14
|
import { buildReviewContext } from '../lib/reviewContext.js';
|
|
13
|
-
import { computeDiffSignature, createReviewRun, hasPriorReviewRunForBundle, insertReviewFindings, parseStructuredReviewOutput, } from '../lib/reviewFindings.js';
|
|
15
|
+
import { computeDiffSignature, constrainReviewOutputToDiff, createReviewRun, finalizeReviewRun, hasPriorReviewRunForBundle, insertReviewFindings, parseStructuredReviewOutput, updateReviewRunPreparation, } from '../lib/reviewFindings.js';
|
|
14
16
|
import { buildSpecCoverageContext } from '../lib/specCoverageContext.js';
|
|
15
17
|
import { listTickets } from '../lib/tickets.js';
|
|
16
18
|
import { registerBundleActivity, unregisterBundleActivity } from '../lib/bundleActivity.js';
|
|
@@ -26,9 +28,17 @@ import { runAutomationCommitChain } from '../lib/ticketAutomationCommit.js';
|
|
|
26
28
|
import { submitTicketFollowUp } from '../lib/ticketFollowUpOperations.js';
|
|
27
29
|
import { completeAutomationProgression, createAutomationReviewFix, ensureAutomationProgression, finishAutomationReviewFix, pauseAutomationProgression, resolveProgressionForChild, waitAutomationProgression, } from '../lib/automationProgression.js';
|
|
28
30
|
import { formatBuildOpenQuestionAnswersPrompt, listAnsweredBuildOpenQuestionsForBundle } from '../lib/buildOpenQuestions.js';
|
|
31
|
+
import { validateWorkflowContext } from '../lib/types.js';
|
|
32
|
+
import { isOpencodeModelResolutionError } from '../lib/opencodeErrors.js';
|
|
29
33
|
const getErrorMessage = (error) => {
|
|
30
34
|
return error instanceof Error ? error.message : String(error);
|
|
31
35
|
};
|
|
36
|
+
const getReviewerExecutionError = (error, model, variant) => {
|
|
37
|
+
const reviewer = variant ? `${model} (${variant})` : model;
|
|
38
|
+
const wrapped = new Error(`Configured reviewer ${reviewer} could not run: ${getErrorMessage(error)}`, { cause: error });
|
|
39
|
+
wrapped.transcriptRuns = getAgentErrorTranscriptRuns(error);
|
|
40
|
+
return wrapped;
|
|
41
|
+
};
|
|
32
42
|
export const resolveReviewContinuation = (executionRunId) => {
|
|
33
43
|
const runs = listAgentRunsForExecutionRun(executionRunId);
|
|
34
44
|
return {
|
|
@@ -73,7 +83,7 @@ const stripSystemReminderBlocks = (output) => {
|
|
|
73
83
|
const normalizeReviewOutput = (output) => {
|
|
74
84
|
return extractProjectMemorySuggestionsFromOutput(stripSystemReminderBlocks(output));
|
|
75
85
|
};
|
|
76
|
-
const resolveStructuredReviewOutput = (parentResponse, transcriptRuns) => {
|
|
86
|
+
const resolveStructuredReviewOutput = (parentResponse, transcriptRuns, mainRole = 'code-review') => {
|
|
77
87
|
const normalizedParent = typeof parentResponse === 'string'
|
|
78
88
|
? normalizeReviewOutput(parentResponse)
|
|
79
89
|
: { cleanedOutput: '', suggestions: [] };
|
|
@@ -84,7 +94,7 @@ const resolveStructuredReviewOutput = (parentResponse, transcriptRuns) => {
|
|
|
84
94
|
return { normalizedParent, parsed: parsedParent };
|
|
85
95
|
}
|
|
86
96
|
const parsedMainTranscript = transcriptRuns
|
|
87
|
-
.filter(run => run.role ===
|
|
97
|
+
.filter(run => run.role === mainRole && run.agent_status === 'done' && run.response_text?.trim())
|
|
88
98
|
.flatMap(run => {
|
|
89
99
|
const normalized = normalizeReviewOutput(run.response_text ?? '');
|
|
90
100
|
if (!normalized.cleanedOutput) {
|
|
@@ -126,6 +136,15 @@ const resolveStructuredReviewOutput = (parentResponse, transcriptRuns) => {
|
|
|
126
136
|
},
|
|
127
137
|
};
|
|
128
138
|
};
|
|
139
|
+
const formatParsedReviewMarkdown = (parsed) => {
|
|
140
|
+
if (parsed.cleanedMarkdown) {
|
|
141
|
+
return parsed.cleanedMarkdown;
|
|
142
|
+
}
|
|
143
|
+
if (parsed.findings.length === 0) {
|
|
144
|
+
return '## Findings\nNo genuine issues found.';
|
|
145
|
+
}
|
|
146
|
+
return `## Findings\n${parsed.findings.map((finding, index) => (`${index + 1}. ${finding.title}\n - Severity: ${finding.severity}\n - What: ${finding.what_text}${finding.why_text ? `\n - Why: ${finding.why_text}` : ''}${finding.fix_text ? `\n - Fix: ${finding.fix_text}` : ''}`)).join('\n\n')}`;
|
|
147
|
+
};
|
|
129
148
|
const MAX_INLINE_DIFF_LINES = 400;
|
|
130
149
|
const MAX_INLINE_DIFF_CHARS = 20_000;
|
|
131
150
|
const SUBAGENT_REVIEW_GUIDANCE = 'If you delegate any part of the review to subagents, you remain responsible for evaluating their results and consolidating every accepted finding into your final response using the exact format below.';
|
|
@@ -205,7 +224,9 @@ const reviewPrompt = ({ ticket, diff, memoryEnabled, reviewContext, agentRunId,
|
|
|
205
224
|
const continuationBlock = buildReviewContinuationBlock(continuation, 'blind');
|
|
206
225
|
return prependSkillPromptBlock(`Review the following code changes.
|
|
207
226
|
|
|
208
|
-
This is a code review task, not an implementation task. Focus on genuine defects: bugs, regressions, broken assumptions, missing or incorrect tests, type or runtime issues, and risky behavior changes. Infer the intended behavior from the patch itself instead of relying on any external ticket context.
|
|
227
|
+
This is a code review task, not an implementation task. Focus on genuine defects: bugs, regressions, broken assumptions, missing or incorrect tests, type or runtime issues, and risky behavior changes. Infer the intended behavior from the patch itself instead of relying on any external ticket context. The supplied diff is the authoritative review scope. Treat linked projects and other repositories as read-only context.
|
|
228
|
+
|
|
229
|
+
You may inspect unchanged files, callers, helpers, tests, and project memory only to understand the behavior and impact of changed code. Unchanged code is supporting evidence, not an independent review target. Report a finding only when it is introduced, exposed, or materially worsened by this diff; it can be anchored to a changed path and changed line responsible for the issue; and fixing it requires changing this patch rather than unrelated pre-existing code. Do not report pre-existing defects, general cleanup, architectural improvements, or issues from another branch or ticket. If unchanged code demonstrates a regression, cite it as evidence but anchor the finding to the changed line that caused the regression. When causality is uncertain, omit the finding.
|
|
209
230
|
|
|
210
231
|
Before writing findings, perform this investigation workflow:
|
|
211
232
|
1. ${diffPromptBlock.investigationInstruction}
|
|
@@ -213,6 +234,7 @@ Before writing findings, perform this investigation workflow:
|
|
|
213
234
|
3. Inspect directly related code paths such as nearby helpers, callers, consumers, and tests that could be affected.
|
|
214
235
|
4. Check whether the change is consistent with the project's accepted decisions and conventions.
|
|
215
236
|
5. Only then report genuine issues that are supported by the code you inspected.
|
|
237
|
+
6. Before returning the review, discard every candidate finding that cannot be traced directly to a changed line in the supplied diff.
|
|
216
238
|
|
|
217
239
|
${SUBAGENT_REVIEW_GUIDANCE}
|
|
218
240
|
|
|
@@ -250,7 +272,7 @@ After the markdown findings, append a machine-readable block using these exact m
|
|
|
250
272
|
{"findings":[{"ordinal":1,"title":"...","severity":"high","file_path":"path/to/file.ts","old_line_number":12,"new_line_number":15,"line_content":"...","hunk_header":"@@ -12,3 +15,4 @@","what_text":"...","why_text":"...","fix_text":"..."}]}
|
|
251
273
|
</archon-review-findings>
|
|
252
274
|
|
|
253
|
-
Use an empty findings array when there are no genuine issues. The JSON must be valid and must not be wrapped in code fences. Escape all JSON string contents correctly. If a snippet would be awkward to escape, set \`line_content\` to null. For pure additions, set only \`new_line_number\` and use \`old_line_number\`: null. For pure deletions, set only \`old_line_number\` and use \`new_line_number\`: null.${getProjectMemorySuggestionPromptRules(memoryEnabled, 'review') ? `
|
|
275
|
+
Every finding must set \`file_path\` to a path in \`<review_scope>\` and set at least one line number identifying a changed diff line responsible for the issue. Do not use an unchanged context line merely because it is near the defect. Use an empty findings array when there are no in-scope genuine issues. The JSON must be valid and must not be wrapped in code fences. Escape all JSON string contents correctly. If a snippet would be awkward to escape, set \`line_content\` to null. For pure additions, set only \`new_line_number\` and use \`old_line_number\`: null. For pure deletions, set only \`old_line_number\` and use \`new_line_number\`: null.${getProjectMemorySuggestionPromptRules(memoryEnabled, 'review') ? `
|
|
254
276
|
|
|
255
277
|
${getProjectMemorySuggestionPromptRules(memoryEnabled, 'review')}` : ''}
|
|
256
278
|
|
|
@@ -268,13 +290,16 @@ const specCoverageReviewPrompt = ({ ticket, diff, reviewContext, specContext, ag
|
|
|
268
290
|
});
|
|
269
291
|
const diffPromptBlock = buildDiffPromptBlock(diff);
|
|
270
292
|
const continuationBlock = buildReviewContinuationBlock(continuation, 'spec-coverage');
|
|
271
|
-
return prependSkillPromptBlock(`Verify the implementation against this specification. Focus on missing acceptance criteria, unhandled edge cases, and scope drift — not generic code-quality defects already covered by the blind review.
|
|
293
|
+
return prependSkillPromptBlock(`Verify the implementation against this specification. Focus on missing acceptance criteria, unhandled edge cases, and scope drift — not generic code-quality defects already covered by the blind review. The supplied diff is the authoritative review scope.
|
|
294
|
+
|
|
295
|
+
You may inspect unchanged code to understand the implementation, but it is supporting evidence rather than an independent review target. Report only conformance gaps introduced by, exposed by, or expected to be implemented in this diff, and anchor every finding to the changed path and changed line responsible. Do not report unrelated missing functionality, pre-existing defects, or cleanup opportunities. When causality or patch responsibility is uncertain, omit the finding.
|
|
272
296
|
|
|
273
297
|
Before writing findings, perform this investigation workflow:
|
|
274
298
|
1. ${diffPromptBlock.investigationInstruction}
|
|
275
299
|
2. Read the full contents of every changed file that matters to the spec, not just the diff hunk.
|
|
276
300
|
3. Compare the implementation against the spec_context block: are all acceptance criteria satisfied, are listed edge cases handled, and does the change stay within scope?
|
|
277
301
|
4. Only then report genuine conformance gaps that are supported by the code you inspected.
|
|
302
|
+
5. Before returning the review, discard every candidate finding that cannot be traced directly to a changed line in the supplied diff.
|
|
278
303
|
|
|
279
304
|
${SUBAGENT_REVIEW_GUIDANCE}
|
|
280
305
|
|
|
@@ -314,7 +339,7 @@ After the markdown findings, append a machine-readable block using these exact m
|
|
|
314
339
|
{"findings":[{"ordinal":1,"title":"...","severity":"high","file_path":"path/to/file.ts","old_line_number":12,"new_line_number":15,"line_content":"...","hunk_header":"@@ -12,3 +15,4 @@","what_text":"...","why_text":"...","fix_text":"..."}]}
|
|
315
340
|
</archon-review-findings>
|
|
316
341
|
|
|
317
|
-
Use an empty findings array when there are no genuine issues. The JSON must be valid and must not be wrapped in code fences. Escape all JSON string contents correctly. If a snippet would be awkward to escape, set \`line_content\` to null. For pure additions, set only \`new_line_number\` and use \`old_line_number\`: null. For pure deletions, set only \`old_line_number\` and use \`new_line_number\`: null.
|
|
342
|
+
Every finding must set \`file_path\` to a path in \`<review_scope>\` and set at least one line number identifying a changed diff line responsible for the conformance gap. Do not use an unchanged context line merely because it is related. Use an empty findings array when there are no in-scope genuine issues. The JSON must be valid and must not be wrapped in code fences. Escape all JSON string contents correctly. If a snippet would be awkward to escape, set \`line_content\` to null. For pure additions, set only \`new_line_number\` and use \`old_line_number\`: null. For pure deletions, set only \`old_line_number\` and use \`new_line_number\`: null.
|
|
318
343
|
|
|
319
344
|
Do not include planning text, implementation steps, or commentary about changing modes.`, ticket.skills);
|
|
320
345
|
};
|
|
@@ -378,6 +403,9 @@ const runReviewCompletionAutomation = async (ticket, project, reviewRunId, parse
|
|
|
378
403
|
return true;
|
|
379
404
|
}
|
|
380
405
|
case 'fix_iteration': {
|
|
406
|
+
if (!reviewRunId) {
|
|
407
|
+
throw new Error('Review fix cannot start without persisted review findings');
|
|
408
|
+
}
|
|
381
409
|
const previousIteration = bundleState?.review_iteration_count ?? 0;
|
|
382
410
|
const previousFixLoopActive = bundleState?.fix_loop_active ?? 0;
|
|
383
411
|
upsertBundleAutomationState(projectId, bundleId, {
|
|
@@ -385,6 +413,11 @@ const runReviewCompletionAutomation = async (ticket, project, reviewRunId, parse
|
|
|
385
413
|
fix_loop_active: 1,
|
|
386
414
|
});
|
|
387
415
|
const instruction = buildAutomationFixInstruction(config.reviewSeverity);
|
|
416
|
+
const reviewFixWorkflowContext = validateWorkflowContext({
|
|
417
|
+
...(initiation.workflowContext ?? {}),
|
|
418
|
+
review_finding_run_id: reviewRunId,
|
|
419
|
+
review_severity: config.reviewSeverity,
|
|
420
|
+
});
|
|
388
421
|
let reviewFix = null;
|
|
389
422
|
try {
|
|
390
423
|
reviewFix = progression
|
|
@@ -394,8 +427,10 @@ const runReviewCompletionAutomation = async (ticket, project, reviewRunId, parse
|
|
|
394
427
|
ticketId: ticket.id,
|
|
395
428
|
ticketTitle: ticket.title,
|
|
396
429
|
progressionRunId: progression.id,
|
|
397
|
-
workflowContext:
|
|
430
|
+
workflowContext: reviewFixWorkflowContext,
|
|
398
431
|
triggeringReviewRunId: executionContext.runId,
|
|
432
|
+
reviewFindingRunId: reviewRunId,
|
|
433
|
+
reviewSeverity: config.reviewSeverity,
|
|
399
434
|
broadcaster: asGenericEmitter(io),
|
|
400
435
|
})
|
|
401
436
|
: null;
|
|
@@ -416,7 +451,7 @@ const runReviewCompletionAutomation = async (ticket, project, reviewRunId, parse
|
|
|
416
451
|
initiation: {
|
|
417
452
|
initiator: 'automation',
|
|
418
453
|
causalParentRunId: reviewFix?.runId ?? executionContext.runId,
|
|
419
|
-
workflowContext:
|
|
454
|
+
workflowContext: reviewFixWorkflowContext,
|
|
420
455
|
},
|
|
421
456
|
});
|
|
422
457
|
if (!started.ok) {
|
|
@@ -613,6 +648,7 @@ export function startReview(ticket, io, options) {
|
|
|
613
648
|
}
|
|
614
649
|
let activityRegistered = false;
|
|
615
650
|
let registeredReviewProcess = null;
|
|
651
|
+
let activeReviewRunId = null;
|
|
616
652
|
let finalizeStoppedReviewAfterFailure = null;
|
|
617
653
|
try {
|
|
618
654
|
registerBundleActivity(acceptedTicket, 'review');
|
|
@@ -626,7 +662,17 @@ export function startReview(ticket, io, options) {
|
|
|
626
662
|
throw new Error('Ticket project no longer exists');
|
|
627
663
|
}
|
|
628
664
|
const cwd = currentTicket.bundle?.kind === 'project_root' ? project.repo_path : resolveWorktreePath(branch, project);
|
|
629
|
-
const tool = resolveTicketTool(
|
|
665
|
+
const tool = resolveTicketTool(currentTicket, config.tool ?? 'opencode');
|
|
666
|
+
const reviewerConfig = tool === 'opencode'
|
|
667
|
+
? resolveReviewerConfig(currentTicket.bundle, project, {
|
|
668
|
+
model: currentTicket.model,
|
|
669
|
+
variant: currentTicket.variant,
|
|
670
|
+
})
|
|
671
|
+
: {
|
|
672
|
+
model: currentTicket.model,
|
|
673
|
+
variant: currentTicket.model ? currentTicket.variant : null,
|
|
674
|
+
source: 'fallback',
|
|
675
|
+
};
|
|
630
676
|
const reviewProcessState = registerReviewProcess(acceptedTicket.id);
|
|
631
677
|
registeredReviewProcess = reviewProcessState;
|
|
632
678
|
const createdAgentRunIds = [];
|
|
@@ -679,6 +725,14 @@ export function startReview(ticket, io, options) {
|
|
|
679
725
|
if (messageId) {
|
|
680
726
|
bindTicketThinkingMessage(ticket.id, messageId);
|
|
681
727
|
}
|
|
728
|
+
if (activeReviewRunId) {
|
|
729
|
+
finalizeReviewRun({
|
|
730
|
+
reviewRunId: activeReviewRunId,
|
|
731
|
+
status: 'stopped',
|
|
732
|
+
messageId,
|
|
733
|
+
failureMessage: 'Review was stopped by the user',
|
|
734
|
+
});
|
|
735
|
+
}
|
|
682
736
|
db.prepare('UPDATE tickets SET agent_status = ?, agent_log = NULL, updated_at = CURRENT_TIMESTAMP WHERE id = ? AND project_id = ?')
|
|
683
737
|
.run('stopped', ticket.id, executionContext.projectId);
|
|
684
738
|
terminalizeAgentRunsForExecutionRun(executionContext.runId, 'stopped', null);
|
|
@@ -723,7 +777,6 @@ export function startReview(ticket, io, options) {
|
|
|
723
777
|
finalizeStoppedReview();
|
|
724
778
|
return true;
|
|
725
779
|
};
|
|
726
|
-
beginTicketThinkingRun(ticket.id);
|
|
727
780
|
withExecutionRunTransaction(transaction => {
|
|
728
781
|
db.prepare('UPDATE tickets SET agent_status = ?, agent_operation = ?, agent_log = ?, streaming_response = NULL, updated_at = CURRENT_TIMESTAMP WHERE id = ? AND project_id = ?').run('running', 'review', 'Preparing review baseline...', ticket.id, executionContext.projectId);
|
|
729
782
|
transaction.transitionExecutionRun({
|
|
@@ -733,19 +786,59 @@ export function startReview(ticket, io, options) {
|
|
|
733
786
|
domainStatus: 'running',
|
|
734
787
|
eventType: 'review_started',
|
|
735
788
|
});
|
|
789
|
+
activeReviewRunId = createReviewRun({
|
|
790
|
+
ticketId: currentTicket.id,
|
|
791
|
+
projectId: currentTicket.project_id,
|
|
792
|
+
worktreeBundleId: currentTicket.worktree_bundle_id,
|
|
793
|
+
diffSignature: null,
|
|
794
|
+
workspaceSignature: null,
|
|
795
|
+
messageId: null,
|
|
796
|
+
model: reviewerConfig.model,
|
|
797
|
+
variant: reviewerConfig.variant,
|
|
798
|
+
status: 'running',
|
|
799
|
+
});
|
|
800
|
+
transaction.addExecutionRunLink({
|
|
801
|
+
projectId: executionContext.projectId,
|
|
802
|
+
runId: executionContext.runId,
|
|
803
|
+
link: {
|
|
804
|
+
entityType: 'review_run',
|
|
805
|
+
entityId: activeReviewRunId,
|
|
806
|
+
relationship: 'result',
|
|
807
|
+
expectedParent: { entityType: 'ticket', entityId: currentTicket.id },
|
|
808
|
+
},
|
|
809
|
+
});
|
|
736
810
|
}, asGenericEmitter(io));
|
|
811
|
+
beginTicketThinkingRun(ticket.id);
|
|
737
812
|
updateStatus(ticket.id, 'running', 'Preparing review baseline...', io, 'review');
|
|
738
813
|
await captureStageBaseline(ticket.id, 'review');
|
|
739
814
|
if (stopReviewBeforeAgentIfRequested()) {
|
|
740
815
|
return;
|
|
741
816
|
}
|
|
742
817
|
updateStatus(ticket.id, 'running', 'Computing review diff...', io);
|
|
743
|
-
const
|
|
818
|
+
const trackedPullRequest = ticket.project_id && ticket.worktree_bundle_id
|
|
819
|
+
? getBundlePullRequestRecord(ticket.worktree_bundle_id, ticket.project_id)
|
|
820
|
+
: null;
|
|
821
|
+
const diffData = await getReviewDiffDataAsync({
|
|
822
|
+
cwd,
|
|
823
|
+
branch,
|
|
824
|
+
project,
|
|
825
|
+
pullRequestBaseBranch: trackedPullRequest?.baseBranch ?? null,
|
|
826
|
+
});
|
|
827
|
+
const diffText = diffData.diff;
|
|
744
828
|
if (stopReviewBeforeAgentIfRequested()) {
|
|
745
829
|
return;
|
|
746
830
|
}
|
|
747
|
-
const reviewContext = buildReviewContext({
|
|
831
|
+
const reviewContext = buildReviewContext({
|
|
832
|
+
cwd,
|
|
833
|
+
branch,
|
|
834
|
+
project,
|
|
835
|
+
diffData,
|
|
836
|
+
baseBranch: trackedPullRequest?.baseBranch ?? null,
|
|
837
|
+
});
|
|
748
838
|
const diffSignature = computeDiffSignature(diffText);
|
|
839
|
+
if (!activeReviewRunId || !updateReviewRunPreparation(activeReviewRunId, diffSignature, reviewContext.workspaceSignature)) {
|
|
840
|
+
throw new Error('The running review record could not be updated after diff preparation');
|
|
841
|
+
}
|
|
749
842
|
const supplementalRequirements = ticket.project_id && ticket.worktree_bundle_id
|
|
750
843
|
? formatBuildOpenQuestionAnswersPrompt(listAnsweredBuildOpenQuestionsForBundle(ticket.project_id, ticket.worktree_bundle_id))
|
|
751
844
|
: '';
|
|
@@ -794,20 +887,28 @@ export function startReview(ticket, io, options) {
|
|
|
794
887
|
continuation: options?.continuation,
|
|
795
888
|
});
|
|
796
889
|
const blindRun = async () => {
|
|
797
|
-
|
|
798
|
-
|
|
799
|
-
|
|
800
|
-
|
|
801
|
-
|
|
802
|
-
|
|
803
|
-
|
|
804
|
-
|
|
805
|
-
|
|
806
|
-
|
|
807
|
-
|
|
808
|
-
|
|
809
|
-
|
|
810
|
-
|
|
890
|
+
try {
|
|
891
|
+
return await runAgent({
|
|
892
|
+
ticketId: ticket.id,
|
|
893
|
+
tool,
|
|
894
|
+
prompt: blindPrompt,
|
|
895
|
+
cwd,
|
|
896
|
+
model: reviewerConfig.model,
|
|
897
|
+
variant: reviewerConfig.variant,
|
|
898
|
+
resumeSessionId: options?.continuation?.blindSessionId ?? null,
|
|
899
|
+
emitSuccessUpdate: false,
|
|
900
|
+
executionContext,
|
|
901
|
+
io,
|
|
902
|
+
runStream: blindRunStreamTarget,
|
|
903
|
+
reviewProcessState,
|
|
904
|
+
});
|
|
905
|
+
}
|
|
906
|
+
catch (error) {
|
|
907
|
+
if (tool === 'opencode' && reviewerConfig.model && isOpencodeModelResolutionError(error)) {
|
|
908
|
+
throw getReviewerExecutionError(error, reviewerConfig.model, reviewerConfig.variant);
|
|
909
|
+
}
|
|
910
|
+
throw error;
|
|
911
|
+
}
|
|
811
912
|
};
|
|
812
913
|
const specCoverageRun = async () => {
|
|
813
914
|
if (!specContext) {
|
|
@@ -827,8 +928,8 @@ export function startReview(ticket, io, options) {
|
|
|
827
928
|
continuation: options?.continuation,
|
|
828
929
|
}),
|
|
829
930
|
cwd,
|
|
830
|
-
model:
|
|
831
|
-
variant:
|
|
931
|
+
model: reviewerConfig.model,
|
|
932
|
+
variant: reviewerConfig.variant,
|
|
832
933
|
resumeSessionId: options?.continuation?.specCoverageSessionId ?? null,
|
|
833
934
|
emitSuccessUpdate: false,
|
|
834
935
|
executionContext,
|
|
@@ -852,8 +953,11 @@ export function startReview(ticket, io, options) {
|
|
|
852
953
|
if (blindSettled.status === 'rejected') {
|
|
853
954
|
throw blindSettled.reason;
|
|
854
955
|
}
|
|
956
|
+
if (specCoverageSettled.status === 'rejected') {
|
|
957
|
+
throw specCoverageSettled.reason;
|
|
958
|
+
}
|
|
855
959
|
blindResult = blindSettled.value;
|
|
856
|
-
specCoverageResult = specCoverageSettled.
|
|
960
|
+
specCoverageResult = specCoverageSettled.value;
|
|
857
961
|
}
|
|
858
962
|
else {
|
|
859
963
|
blindResult = await blindRun();
|
|
@@ -874,30 +978,32 @@ export function startReview(ticket, io, options) {
|
|
|
874
978
|
return;
|
|
875
979
|
}
|
|
876
980
|
const { normalizedParent: normalizedResponse, parsed: blindParsed, } = resolveStructuredReviewOutput(finalResponse, blindResult.transcriptRuns ?? []);
|
|
877
|
-
|
|
981
|
+
const constrainedBlindParsed = blindParsed
|
|
982
|
+
? constrainReviewOutputToDiff(blindParsed, diffText)
|
|
983
|
+
: null;
|
|
984
|
+
let reviewRunId = activeReviewRunId;
|
|
878
985
|
let parsedFindings = [];
|
|
879
986
|
let parsedStatus = null;
|
|
880
987
|
let persistedMessageId = null;
|
|
881
988
|
let reviewContent = null;
|
|
882
989
|
let findingsToPersist = [];
|
|
883
|
-
if (
|
|
884
|
-
const
|
|
885
|
-
|
|
886
|
-
|
|
887
|
-
const specParsed = specCoverageSpecOutput
|
|
888
|
-
? parseStructuredReviewOutput(specCoverageSpecOutput)
|
|
990
|
+
if (constrainedBlindParsed?.status === 'completed') {
|
|
991
|
+
const specOutput = resolveStructuredReviewOutput(specCoverageResult?.response ?? null, specCoverageResult?.transcriptRuns ?? [], 'spec-coverage').parsed;
|
|
992
|
+
const specParsed = specOutput
|
|
993
|
+
? constrainReviewOutputToDiff(specOutput, diffText)
|
|
889
994
|
: null;
|
|
890
995
|
const mergedFindings = specParsed && specParsed.status === 'completed'
|
|
891
|
-
? [...
|
|
996
|
+
? [...constrainedBlindParsed.findings, ...specParsed.findings.map(finding => ({
|
|
892
997
|
...finding,
|
|
893
|
-
ordinal: finding.ordinal +
|
|
998
|
+
ordinal: finding.ordinal + constrainedBlindParsed.findings.length,
|
|
894
999
|
}))]
|
|
895
|
-
:
|
|
896
|
-
const
|
|
897
|
-
|
|
898
|
-
|
|
1000
|
+
: constrainedBlindParsed.findings;
|
|
1001
|
+
const blindMarkdown = formatParsedReviewMarkdown(constrainedBlindParsed);
|
|
1002
|
+
const combinedMarkdown = specParsed?.status === 'completed'
|
|
1003
|
+
? `${blindMarkdown}\n\n## Spec-Coverage Review\n${formatParsedReviewMarkdown(specParsed)}`
|
|
1004
|
+
: blindMarkdown;
|
|
899
1005
|
parsedFindings = mergedFindings;
|
|
900
|
-
parsedStatus =
|
|
1006
|
+
parsedStatus = constrainedBlindParsed.status;
|
|
901
1007
|
reviewContent = combinedMarkdown;
|
|
902
1008
|
findingsToPersist = mergedFindings;
|
|
903
1009
|
}
|
|
@@ -922,19 +1028,15 @@ export function startReview(ticket, io, options) {
|
|
|
922
1028
|
transcriptRuns: transcriptRuns.length > 0 ? transcriptRuns : null,
|
|
923
1029
|
})
|
|
924
1030
|
: null;
|
|
925
|
-
|
|
926
|
-
|
|
927
|
-
|
|
928
|
-
|
|
929
|
-
projectId: ticket.project_id,
|
|
930
|
-
worktreeBundleId: ticket.worktree_bundle_id,
|
|
931
|
-
diffSignature,
|
|
932
|
-
workspaceSignature: reviewContext.workspaceSignature,
|
|
1031
|
+
if (activeReviewRunId) {
|
|
1032
|
+
finalizeReviewRun({
|
|
1033
|
+
reviewRunId: activeReviewRunId,
|
|
1034
|
+
status: parsedStatus ?? 'parse_failed',
|
|
933
1035
|
messageId,
|
|
934
|
-
|
|
1036
|
+
failureMessage: parseFailed ? 'Review output could not be parsed' : null,
|
|
935
1037
|
});
|
|
936
1038
|
if (findingsToPersist.length > 0) {
|
|
937
|
-
insertReviewFindings(
|
|
1039
|
+
insertReviewFindings(activeReviewRunId, findingsToPersist);
|
|
938
1040
|
}
|
|
939
1041
|
}
|
|
940
1042
|
if (messageId) {
|
|
@@ -949,18 +1051,6 @@ export function startReview(ticket, io, options) {
|
|
|
949
1051
|
},
|
|
950
1052
|
});
|
|
951
1053
|
}
|
|
952
|
-
if (createdReviewRunId) {
|
|
953
|
-
transaction.addExecutionRunLink({
|
|
954
|
-
projectId: executionContext.projectId,
|
|
955
|
-
runId: executionContext.runId,
|
|
956
|
-
link: {
|
|
957
|
-
entityType: 'review_run',
|
|
958
|
-
entityId: createdReviewRunId,
|
|
959
|
-
relationship: 'result',
|
|
960
|
-
expectedParent: { entityType: 'ticket', entityId: ticket.id },
|
|
961
|
-
},
|
|
962
|
-
});
|
|
963
|
-
}
|
|
964
1054
|
db.prepare('UPDATE tickets SET agent_status = ?, agent_log = NULL, updated_at = CURRENT_TIMESTAMP WHERE id = ? AND project_id = ?')
|
|
965
1055
|
.run('done', ticket.id, executionContext.projectId);
|
|
966
1056
|
terminalizeAgentRunsForExecutionRun(executionContext.runId, parseFailed ? 'error' : 'done', parseFailed ? 'Review output could not be parsed' : null);
|
|
@@ -972,7 +1062,7 @@ export function startReview(ticket, io, options) {
|
|
|
972
1062
|
...(parseFailed ? { failure: { code: 'parse_failed', message: 'Review output could not be parsed' } } : {}),
|
|
973
1063
|
eventType: parseFailed ? 'review_parse_failed' : 'review_completed',
|
|
974
1064
|
});
|
|
975
|
-
return { messageId, reviewRunId:
|
|
1065
|
+
return { messageId, reviewRunId: activeReviewRunId };
|
|
976
1066
|
}, asGenericEmitter(io));
|
|
977
1067
|
persistedMessageId = persisted.messageId;
|
|
978
1068
|
reviewRunId = persisted.reviewRunId;
|
|
@@ -990,8 +1080,8 @@ export function startReview(ticket, io, options) {
|
|
|
990
1080
|
if (tool === 'claude' && usageSnapshot) {
|
|
991
1081
|
storeTicketUsageSnapshotDirect(ticket.id, usageSnapshot);
|
|
992
1082
|
}
|
|
993
|
-
emitAgentRunsUpdated(asGenericEmitter(io), 'ticket', ticket.id);
|
|
994
1083
|
updateStatus(ticket.id, 'done', null, io);
|
|
1084
|
+
emitAgentRunsUpdated(asGenericEmitter(io), 'ticket', ticket.id);
|
|
995
1085
|
const completedWithMessage = getTicket(ticket.id);
|
|
996
1086
|
if (completedWithMessage) {
|
|
997
1087
|
io.emit('ticket:updated', completedWithMessage);
|
|
@@ -1075,8 +1165,9 @@ export function startReview(ticket, io, options) {
|
|
|
1075
1165
|
}
|
|
1076
1166
|
try {
|
|
1077
1167
|
withExecutionRunTransaction(transaction => {
|
|
1168
|
+
let errorMessageId = null;
|
|
1078
1169
|
if (errorContent) {
|
|
1079
|
-
|
|
1170
|
+
errorMessageId = createTicketMessage({
|
|
1080
1171
|
ticketId: acceptedTicket.id,
|
|
1081
1172
|
role: 'assistant',
|
|
1082
1173
|
kind: 'error',
|
|
@@ -1088,7 +1179,7 @@ export function startReview(ticket, io, options) {
|
|
|
1088
1179
|
runId: executionContext.runId,
|
|
1089
1180
|
link: {
|
|
1090
1181
|
entityType: 'ticket_message',
|
|
1091
|
-
entityId:
|
|
1182
|
+
entityId: errorMessageId,
|
|
1092
1183
|
relationship: 'result',
|
|
1093
1184
|
expectedParent: { entityType: 'ticket', entityId: acceptedTicket.id },
|
|
1094
1185
|
},
|
|
@@ -1097,6 +1188,14 @@ export function startReview(ticket, io, options) {
|
|
|
1097
1188
|
db.prepare('UPDATE tickets SET agent_status = ?, agent_log = ?, streaming_response = NULL, updated_at = CURRENT_TIMESTAMP WHERE id = ? AND project_id = ?')
|
|
1098
1189
|
.run('error', message, acceptedTicket.id, executionContext.projectId);
|
|
1099
1190
|
terminalizeAgentRunsForExecutionRun(executionContext.runId, 'error', message);
|
|
1191
|
+
if (activeReviewRunId) {
|
|
1192
|
+
finalizeReviewRun({
|
|
1193
|
+
reviewRunId: activeReviewRunId,
|
|
1194
|
+
status: 'error',
|
|
1195
|
+
messageId: errorMessageId,
|
|
1196
|
+
failureMessage: message,
|
|
1197
|
+
});
|
|
1198
|
+
}
|
|
1100
1199
|
transaction.transitionExecutionRun({
|
|
1101
1200
|
projectId: executionContext.projectId,
|
|
1102
1201
|
runId: executionContext.runId,
|
|
@@ -1123,6 +1222,13 @@ export function startReview(ticket, io, options) {
|
|
|
1123
1222
|
const currentExecutionRun = getExecutionRun(executionContext.projectId, executionContext.runId);
|
|
1124
1223
|
if (currentExecutionRun && ['queued', 'running', 'waiting'].includes(currentExecutionRun.status)) {
|
|
1125
1224
|
terminalizeAgentRunsForExecutionRun(executionContext.runId, 'error', message);
|
|
1225
|
+
if (activeReviewRunId) {
|
|
1226
|
+
finalizeReviewRun({
|
|
1227
|
+
reviewRunId: activeReviewRunId,
|
|
1228
|
+
status: 'error',
|
|
1229
|
+
failureMessage: message,
|
|
1230
|
+
});
|
|
1231
|
+
}
|
|
1126
1232
|
transitionExecutionRun({
|
|
1127
1233
|
projectId: executionContext.projectId,
|
|
1128
1234
|
runId: executionContext.runId,
|