@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.
Files changed (139) hide show
  1. package/dist/client/assets/{ActivityView-CEETnHri.js → ActivityView-DYDYyqIN.js} +1 -1
  2. package/dist/client/assets/{GitHubActionsDialog-CjBW65OR.js → GitHubActionsDialog-jhi4GOyV.js} +1 -1
  3. package/dist/client/assets/{RepositoryGraphDialog-F3C0n89W.js → RepositoryGraphDialog-BZV0vHu6.js} +1 -1
  4. package/dist/client/assets/{VerificationDialog-DD1CLydA.js → VerificationDialog-Sc6e8AKH.js} +1 -1
  5. package/dist/client/assets/{architectureDiagram-3BPJPVTR-COl_GdZ6.js → architectureDiagram-3BPJPVTR-DFbki8mi.js} +1 -1
  6. package/dist/client/assets/{blockDiagram-GPEHLZMM-qojIlH-q.js → blockDiagram-GPEHLZMM-BZFehG8P.js} +1 -1
  7. package/dist/client/assets/{c4Diagram-AAUBKEIU-DFtG4fMg.js → c4Diagram-AAUBKEIU-FVDXRu1t.js} +1 -1
  8. package/dist/client/assets/channel-D1kOpezG.js +1 -0
  9. package/dist/client/assets/{chunk-2J33WTMH-TJkOJXbn.js → chunk-2J33WTMH-4tuVZaT0.js} +1 -1
  10. package/dist/client/assets/{chunk-3OPIFGDE-CELQ603z.js → chunk-3OPIFGDE-DSn14S35.js} +1 -1
  11. package/dist/client/assets/{chunk-5ZQYHXKU-BgPEJ16b.js → chunk-5ZQYHXKU-Cwx1KNjg.js} +1 -1
  12. package/dist/client/assets/{chunk-727SXJPM-Biph-aPf.js → chunk-727SXJPM-Odza4hes.js} +1 -1
  13. package/dist/client/assets/{chunk-AQP2D5EJ-CPVToZH6.js → chunk-AQP2D5EJ-BmVoQT7M.js} +1 -1
  14. package/dist/client/assets/{chunk-CSCIHK7Q-BHO9oB4A.js → chunk-CSCIHK7Q-Bg7Ktx0B.js} +1 -1
  15. package/dist/client/assets/{chunk-KSCS5N6A-B8vatrko.js → chunk-KSCS5N6A-2tnhar2x.js} +1 -1
  16. package/dist/client/assets/{chunk-L5ZTLDWV-DvzBHR4-.js → chunk-L5ZTLDWV-dAyg8qMJ.js} +1 -1
  17. package/dist/client/assets/{chunk-LZXEDZCA-Bm8cj-JK.js → chunk-LZXEDZCA-0gElxrlR.js} +2 -2
  18. package/dist/client/assets/{chunk-ND2GUHAM-BPQZvPl9.js → chunk-ND2GUHAM-Bu-8Lz91.js} +1 -1
  19. package/dist/client/assets/{chunk-NZK2D7GU-DEQVA6Ya.js → chunk-NZK2D7GU-CInZFdzd.js} +1 -1
  20. package/dist/client/assets/{chunk-O5CBEL6O-hPGqWilt.js → chunk-O5CBEL6O-rAzpvdNR.js} +1 -1
  21. package/dist/client/assets/{chunk-WU5MYG2G-D0VvFXkQ.js → chunk-WU5MYG2G-DOOw2vq7.js} +1 -1
  22. package/dist/client/assets/classDiagram-4FO5ZUOK-C253nwny.js +1 -0
  23. package/dist/client/assets/classDiagram-v2-Q7XG4LA2-DFgDA23g.js +1 -0
  24. package/dist/client/assets/{dagre-BM42HDAG-rmJlMuw_.js → dagre-BM42HDAG-Dgua1iuh.js} +1 -1
  25. package/dist/client/assets/{diagram-2AECGRRQ-BqejYr09.js → diagram-2AECGRRQ-odacwlwu.js} +1 -1
  26. package/dist/client/assets/{diagram-5GNKFQAL-DGSf1BNT.js → diagram-5GNKFQAL-BiKjFmJ1.js} +1 -1
  27. package/dist/client/assets/{diagram-KO2AKTUF-e_TRdqvx.js → diagram-KO2AKTUF-CmYcvFri.js} +1 -1
  28. package/dist/client/assets/{diagram-LMA3HP47-CTSnwgUq.js → diagram-LMA3HP47-ncx0RBuX.js} +1 -1
  29. package/dist/client/assets/{diagram-OG6HWLK6-mUn9Y0aC.js → diagram-OG6HWLK6-DbchKIzw.js} +1 -1
  30. package/dist/client/assets/{erDiagram-TEJ5UH35-TmdWUwfA.js → erDiagram-TEJ5UH35-CMnpvRyQ.js} +1 -1
  31. package/dist/client/assets/{flowDiagram-I6XJVG4X-CoE0KTIp.js → flowDiagram-I6XJVG4X-Bi02_PK5.js} +1 -1
  32. package/dist/client/assets/{ganttDiagram-6RSMTGT7-FkX1d1D7.js → ganttDiagram-6RSMTGT7-BiS992US.js} +1 -1
  33. package/dist/client/assets/{gitGraphDiagram-PVQCEYII-CXze3DV2.js → gitGraphDiagram-PVQCEYII-Cc1hrTsT.js} +1 -1
  34. package/dist/client/assets/index-B1gdJKwK.js +275 -0
  35. package/dist/client/assets/index-CCQwWUKF.css +2 -0
  36. package/dist/client/assets/{infoDiagram-5YYISTIA-CO0CivOy.js → infoDiagram-5YYISTIA-BKVfqJCe.js} +1 -1
  37. package/dist/client/assets/{ishikawaDiagram-YF4QCWOH-pEp8gScG.js → ishikawaDiagram-YF4QCWOH-B-IbFOty.js} +1 -1
  38. package/dist/client/assets/{journeyDiagram-JHISSGLW-BAnBAX-u.js → journeyDiagram-JHISSGLW-DAZBgAQW.js} +1 -1
  39. package/dist/client/assets/{kanban-definition-UN3LZRKU-Cqe-m5fR.js → kanban-definition-UN3LZRKU-Bkr_fXev.js} +1 -1
  40. package/dist/client/assets/{line-CKXoUXdX.js → line-CROuuXDO.js} +1 -1
  41. package/dist/client/assets/{mermaid-parser.core-7XZHbu9R.js → mermaid-parser.core-DrBw_Rsc.js} +1 -1
  42. package/dist/client/assets/{mermaid.core-CsF9gbdO.js → mermaid.core-pPd6OYYj.js} +3 -3
  43. package/dist/client/assets/{mindmap-definition-RKZ34NQL-88fK1Uq_.js → mindmap-definition-RKZ34NQL-BXSd3TZU.js} +1 -1
  44. package/dist/client/assets/{pieDiagram-4H26LBE5-DHFlSAwL.js → pieDiagram-4H26LBE5-DoT7PIZC.js} +1 -1
  45. package/dist/client/assets/{quadrantDiagram-W4KKPZXB-D5WyQ5EU.js → quadrantDiagram-W4KKPZXB-ycZkLowm.js} +1 -1
  46. package/dist/client/assets/{requirementDiagram-4Y6WPE33-DGkMfp_N.js → requirementDiagram-4Y6WPE33-BPkO1yLu.js} +1 -1
  47. package/dist/client/assets/{sankeyDiagram-5OEKKPKP-loJAHDiT.js → sankeyDiagram-5OEKKPKP-D7AvhhCw.js} +1 -1
  48. package/dist/client/assets/{sequenceDiagram-3UESZ5HK-xgcwtjyW.js → sequenceDiagram-3UESZ5HK-C982swnH.js} +1 -1
  49. package/dist/client/assets/{stateDiagram-AJRCARHV-BB95DmQX.js → stateDiagram-AJRCARHV-xvJ3u8lc.js} +1 -1
  50. package/dist/client/assets/stateDiagram-v2-BHNVJYJU-BKQG8NCn.js +1 -0
  51. package/dist/client/assets/{timeline-definition-PNZ67QCA-OCHTEVfL.js → timeline-definition-PNZ67QCA-D89qjzb5.js} +1 -1
  52. package/dist/client/assets/{vennDiagram-CIIHVFJN-Bo_7YNy2.js → vennDiagram-CIIHVFJN-CoKeC__u.js} +1 -1
  53. package/dist/client/assets/{wardleyDiagram-YWT4CUSO-DquywRz0.js → wardleyDiagram-YWT4CUSO-DKhjzvSE.js} +1 -1
  54. package/dist/client/assets/{xychartDiagram-2RQKCTM6-BLNrbCwd.js → xychartDiagram-2RQKCTM6-DFn9ass1.js} +1 -1
  55. package/dist/client/index.html +2 -2
  56. package/dist/server/db.js +77 -2
  57. package/dist/server/db.js.map +1 -1
  58. package/dist/server/index.js +90 -17
  59. package/dist/server/index.js.map +1 -1
  60. package/dist/server/lib/agent.js +205 -242
  61. package/dist/server/lib/agent.js.map +1 -1
  62. package/dist/server/lib/agentProvider.js +64 -0
  63. package/dist/server/lib/agentProvider.js.map +1 -0
  64. package/dist/server/lib/agentRuns.js +1 -0
  65. package/dist/server/lib/agentRuns.js.map +1 -1
  66. package/dist/server/lib/automationProgression.js +6 -2
  67. package/dist/server/lib/automationProgression.js.map +1 -1
  68. package/dist/server/lib/automationReconciliation.js +20 -0
  69. package/dist/server/lib/automationReconciliation.js.map +1 -1
  70. package/dist/server/lib/automationResumeDecision.js +6 -5
  71. package/dist/server/lib/automationResumeDecision.js.map +1 -1
  72. package/dist/server/lib/buildCompletionContinuation.js +1 -1
  73. package/dist/server/lib/buildCompletionContinuation.js.map +1 -1
  74. package/dist/server/lib/claudeAgentProvider.js +48 -0
  75. package/dist/server/lib/claudeAgentProvider.js.map +1 -0
  76. package/dist/server/lib/executionEnvironment.js +20 -0
  77. package/dist/server/lib/executionEnvironment.js.map +1 -0
  78. package/dist/server/lib/executionReconciliation.js +43 -4
  79. package/dist/server/lib/executionReconciliation.js.map +1 -1
  80. package/dist/server/lib/executionRetry.js +16 -9
  81. package/dist/server/lib/executionRetry.js.map +1 -1
  82. package/dist/server/lib/executionRetryPredicates.js +12 -3
  83. package/dist/server/lib/executionRetryPredicates.js.map +1 -1
  84. package/dist/server/lib/git.js +4 -4
  85. package/dist/server/lib/git.js.map +1 -1
  86. package/dist/server/lib/hostExecutionEnvironment.js +77 -0
  87. package/dist/server/lib/hostExecutionEnvironment.js.map +1 -0
  88. package/dist/server/lib/lightweightPrompt.js +17 -54
  89. package/dist/server/lib/lightweightPrompt.js.map +1 -1
  90. package/dist/server/lib/opencodeAgentProvider.js +139 -0
  91. package/dist/server/lib/opencodeAgentProvider.js.map +1 -0
  92. package/dist/server/lib/opencodeErrors.js +35 -0
  93. package/dist/server/lib/opencodeErrors.js.map +1 -0
  94. package/dist/server/lib/opencodePromptOutput.js +112 -0
  95. package/dist/server/lib/opencodePromptOutput.js.map +1 -0
  96. package/dist/server/lib/opencodeSessionOperations.js +348 -0
  97. package/dist/server/lib/opencodeSessionOperations.js.map +1 -0
  98. package/dist/server/lib/opencodeTaskSessions.js +13 -225
  99. package/dist/server/lib/opencodeTaskSessions.js.map +1 -1
  100. package/dist/server/lib/postBuildCheckRuns.js +16 -12
  101. package/dist/server/lib/postBuildCheckRuns.js.map +1 -1
  102. package/dist/server/lib/postBuildChecks.js +45 -43
  103. package/dist/server/lib/postBuildChecks.js.map +1 -1
  104. package/dist/server/lib/previewProxy.js +36 -4
  105. package/dist/server/lib/previewProxy.js.map +1 -1
  106. package/dist/server/lib/projectAutoConfig.js +27 -97
  107. package/dist/server/lib/projectAutoConfig.js.map +1 -1
  108. package/dist/server/lib/projects.js +34 -6
  109. package/dist/server/lib/projects.js.map +1 -1
  110. package/dist/server/lib/reviewContext.js +10 -5
  111. package/dist/server/lib/reviewContext.js.map +1 -1
  112. package/dist/server/lib/reviewFindings.js +201 -27
  113. package/dist/server/lib/reviewFindings.js.map +1 -1
  114. package/dist/server/lib/reviewerConfig.js +23 -0
  115. package/dist/server/lib/reviewerConfig.js.map +1 -0
  116. package/dist/server/lib/specReviewOperations.js +64 -9
  117. package/dist/server/lib/specReviewOperations.js.map +1 -1
  118. package/dist/server/lib/ticketFollowUpOperations.js +28 -0
  119. package/dist/server/lib/ticketFollowUpOperations.js.map +1 -1
  120. package/dist/server/lib/tickets.js +15 -0
  121. package/dist/server/lib/tickets.js.map +1 -1
  122. package/dist/server/lib/types.js.map +1 -1
  123. package/dist/server/workers/build.js +8 -1
  124. package/dist/server/workers/build.js.map +1 -1
  125. package/dist/server/workers/followUp.js +15 -6
  126. package/dist/server/workers/followUp.js.map +1 -1
  127. package/dist/server/workers/plan.js +5 -21
  128. package/dist/server/workers/plan.js.map +1 -1
  129. package/dist/server/workers/review.js +176 -70
  130. package/dist/server/workers/review.js.map +1 -1
  131. package/dist/server/workers/specReview.js +26 -11
  132. package/dist/server/workers/specReview.js.map +1 -1
  133. package/package.json +1 -1
  134. package/dist/client/assets/channel-DJLjk5--.js +0 -1
  135. package/dist/client/assets/classDiagram-4FO5ZUOK-aHXCyXE_.js +0 -1
  136. package/dist/client/assets/classDiagram-v2-Q7XG4LA2-CRPsGis_.js +0 -1
  137. package/dist/client/assets/index-B9S66NLn.css +0 -2
  138. package/dist/client/assets/index-CHsj9z-M.js +0 -275
  139. package/dist/client/assets/stateDiagram-v2-BHNVJYJU-DKhxPOLT.js +0 -1
@@ -50,7 +50,7 @@ import { getProjectFileManifest, ProjectFileContentError, ProjectFileTargetUnava
50
50
  import { updateProjectTargetSelection } from './lib/projectTargets.js';
51
51
  import { hasActiveBundleSpecWork } from './lib/specWorkspaceActivity.js';
52
52
  import { exportProjectMemoryArchive, importProjectMemoryArchive } from './lib/projectMemoryTransfer.js';
53
- import { buildReviewFindingsResponse, computeDiffSignature, getLatestReviewRunForContext, listReviewFindings } from './lib/reviewFindings.js';
53
+ import { buildReviewFindingsResponse, computeDiffSignature, getLatestCompletedReviewRunForContext, listReviewFindings } from './lib/reviewFindings.js';
54
54
  import { formatBuildOpenQuestionAnswersPrompt, getLatestBuildOpenQuestionBatchStatus, hasActiveBuildOpenQuestionBatch, listBuildOpenQuestionsForBundle, loadBuildOpenQuestionsByBundleIds, } from './lib/buildOpenQuestions.js';
55
55
  import { acceptBuildOpenQuestionResolution } from './lib/buildOpenQuestionOperations.js';
56
56
  import { areBundleTicketsReadyForAutomaticReview } from './lib/bundleAutomationReadiness.js';
@@ -108,11 +108,12 @@ import { getBundleReviewRecovery, recoverBundleReview, rerunTicketReviewOperatio
108
108
  import { resolveReviewContinuation } from './workers/review.js';
109
109
  import { clearTicketStageSnapshots, getActiveBundleStageChangeHead, reconcileStageSnapshots, undoTicketStage } from './lib/ticketUndo.js';
110
110
  import { closeAllTerminalSessions, createProjectTerminalSession, createTerminalSessionForWorkspace, destroyTerminalSessionById, registerTerminalSocketHandlers, } from './lib/terminal.js';
111
- import { countBundleTickets, createTicketRecord, createBundle, deleteBundle, ensureProjectRootBundle, autoParkTicketIfStale, autoParkSettledBundleTicket, isBundleSettledForAutoPark, clearAutoParkDismissalIfNeeded, assignTicketDoneOrder, assignTicketLaneOrder, getBundle, getBundleByName, getBundleByBranch, getBundleRepresentativeTicketContext, isProjectRootBundle, getTicket, isBundledTicket, listTicketsInRunContext, listBundles, listBoardTicketEnrichment, listTickets, resolveTicketBranch, resolveTicketTool, updateBundleAutomationConfig, updateBundleIdentity, } from './lib/tickets.js';
111
+ import { countBundleTickets, createTicketRecord, createBundle, deleteBundle, ensureProjectRootBundle, autoParkTicketIfStale, autoParkSettledBundleTicket, isBundleSettledForAutoPark, clearAutoParkDismissalIfNeeded, assignTicketDoneOrder, assignTicketLaneOrder, getBundle, getBundleByName, getBundleByBranch, getBundleRepresentativeTicketContext, isProjectRootBundle, getTicket, isBundledTicket, listTicketsInRunContext, listBundles, listBoardTicketEnrichment, listTickets, resolveTicketBranch, resolveTicketTool, updateBundleAutomationConfig, updateBundleReviewerConfig, updateBundleIdentity, } from './lib/tickets.js';
112
112
  import { createTicketMessage, upsertTicketDescriptionMessage } from './lib/ticketMessages.js';
113
113
  import { listAgentRunsForExecutionRun, listAgentRunsForParent, terminalizeAgentRunsForExecutionRun } from './lib/agentRuns.js';
114
114
  import { HttpError } from './lib/httpError.js';
115
115
  import { parseIncomingExternalSource } from './lib/externalSource.js';
116
+ import { resolveReviewerConfig } from './lib/reviewerConfig.js';
116
117
  import { materializeTicketsWithDependencies } from './lib/ticketBatch.js';
117
118
  import { IMPLEMENTATION_READY_DESCRIPTION_SECTION_HEADINGS } from './lib/ticketDescriptionContract.js';
118
119
  import { buildImplementationResourcesAppendix, buildSpecImplementationDraft, buildVisualizationAppendix } from './lib/specDraft.js';
@@ -1405,6 +1406,7 @@ const resolveBundleTargetTicket = (tickets, options = {}) => {
1405
1406
  const reviewOwnerTicket = options.reviewOwnerTicketId
1406
1407
  ? tickets.find(ticket => ticket.id === options.reviewOwnerTicketId) ?? null
1407
1408
  : null;
1409
+ const runningTicket = tickets.find(ticket => ticket.agent_status === 'running') ?? null;
1408
1410
  const latestBuiltTicket = resolveBundleLatestBuiltTicket(tickets);
1409
1411
  const latestSessionTicket = options.latestSessionTicketId
1410
1412
  ? tickets.find(ticket => ticket.id === options.latestSessionTicketId && ticket.session_id) ?? null
@@ -1414,6 +1416,7 @@ const resolveBundleTargetTicket = (tickets, options = {}) => {
1414
1416
  : null;
1415
1417
  return explicitTargetTicket
1416
1418
  ?? reviewOwnerTicket
1419
+ ?? runningTicket
1417
1420
  ?? latestBuiltTicket
1418
1421
  ?? latestSessionTicket
1419
1422
  ?? latestSessionTicketById
@@ -1541,6 +1544,9 @@ const serializeBundleRow = (projectId, bundle, openQuestions = bundle ? loadBuil
1541
1544
  const effectivePolicy = resolveEffectiveRequiredCheckPolicyMembership(project);
1542
1545
  return {
1543
1546
  ...bundle,
1547
+ reviewer_model: bundle.kind === 'project_root' ? null : bundle.reviewer_model ?? null,
1548
+ reviewer_variant: bundle.kind === 'project_root' || !bundle.reviewer_model ? null : bundle.reviewer_variant ?? null,
1549
+ reviewer_config: resolveReviewerConfig(bundle.kind === 'project_root' ? null : bundle, project),
1544
1550
  has_prepared_worktree: hasPreparedWorktree,
1545
1551
  pull_request: getGitHubConnectionConfig(projectId)
1546
1552
  ? serializeBundlePullRequest(getBundlePullRequestRecord(bundle.id, projectId))
@@ -1790,10 +1796,14 @@ const serializeBundleDetails = (project, bundle, extras = {}) => {
1790
1796
  const serializeBundleConversationDetails = (project, bundle, extras = {}) => {
1791
1797
  const tickets = bundle ? listBundleConversationTickets(project.id, bundle.id) : [];
1792
1798
  const latestSessionTicket = resolveBundleLatestSessionTicket(tickets);
1799
+ const runningReviewOwner = tickets.find(ticket => (ticket.state === 'review'
1800
+ && ticket.agent_status === 'running'
1801
+ && ticket.review_follow_up_active !== true)) ?? null;
1802
+ const reviewOwnerTicketId = runningReviewOwner?.id ?? extras.review_owner_ticket_id ?? null;
1793
1803
  const resolvedTargetTicket = extras.target_ticket_id
1794
1804
  ? tickets.find(ticket => ticket.id === extras.target_ticket_id) ?? null
1795
1805
  : resolveBundleTargetTicket(tickets, {
1796
- reviewOwnerTicketId: extras.review_owner_ticket_id,
1806
+ reviewOwnerTicketId,
1797
1807
  latestSessionTicketId: latestSessionTicket?.id ?? null,
1798
1808
  });
1799
1809
  return {
@@ -1801,7 +1811,7 @@ const serializeBundleConversationDetails = (project, bundle, extras = {}) => {
1801
1811
  execution_order_ticket_ids: tickets.map(ticket => ticket.id),
1802
1812
  latest_session_ticket_id: latestSessionTicket?.id ?? null,
1803
1813
  latest_session_id: latestSessionTicket?.session_id ?? null,
1804
- review_owner_ticket_id: extras.review_owner_ticket_id ?? null,
1814
+ review_owner_ticket_id: reviewOwnerTicketId,
1805
1815
  target_ticket_id: resolvedTargetTicket?.id ?? null,
1806
1816
  };
1807
1817
  };
@@ -2083,7 +2093,7 @@ const getBundleReviewFindings = async (projectId, bundleId) => {
2083
2093
  projectId,
2084
2094
  worktreeBundleId: representativeTicket.worktree_bundle_id,
2085
2095
  };
2086
- const latestReviewRun = getLatestReviewRunForContext(context);
2096
+ const latestReviewRun = getLatestCompletedReviewRunForContext(context);
2087
2097
  return buildReviewFindingsResponse({
2088
2098
  context,
2089
2099
  isContextRunning: tickets.some(ticket => ticket.agent_status === 'running'),
@@ -2103,7 +2113,7 @@ const getTicketReviewFindings = async (ticketId) => {
2103
2113
  projectId: ticket.project_id,
2104
2114
  worktreeBundleId: ticket.worktree_bundle_id,
2105
2115
  };
2106
- const latestReviewRun = getLatestReviewRunForContext(context);
2116
+ const latestReviewRun = getLatestCompletedReviewRunForContext(context);
2107
2117
  return buildReviewFindingsResponse({
2108
2118
  context,
2109
2119
  isContextRunning: ticket.agent_status === 'running',
@@ -3867,7 +3877,7 @@ app.post('/bundles', async (req, res) => {
3867
3877
  });
3868
3878
  }
3869
3879
  }
3870
- res.status(201).json(bundle);
3880
+ res.status(201).json(serializeBundleRow(result.project.id, bundle, [], result.project));
3871
3881
  });
3872
3882
  app.delete('/bundles/:id', (req, res) => {
3873
3883
  const result = getRequiredProject(req);
@@ -3935,6 +3945,7 @@ app.patch('/bundles/:id', (req, res) => {
3935
3945
  return res.status(404).json({ error: 'Bundle not found' });
3936
3946
  }
3937
3947
  const hasNameUpdate = hasOwn(req.body, 'name');
3948
+ const hasReviewerUpdate = hasOwn(req.body, 'reviewer_model') || hasOwn(req.body, 'reviewer_variant');
3938
3949
  if (hasOwn(req.body, 'required_check_policy_override')) {
3939
3950
  return res.status(400).json({ error: 'Bundle required-check policy overrides are no longer supported; configure required checks on the project' });
3940
3951
  }
@@ -3942,7 +3953,9 @@ app.patch('/bundles/:id', (req, res) => {
3942
3953
  return res.status(409).json({
3943
3954
  error: hasNameUpdate
3944
3955
  ? 'Project root bundles cannot be renamed'
3945
- : 'Project root bundle automation cannot be overridden',
3956
+ : hasReviewerUpdate
3957
+ ? 'Project root bundle reviewer configuration cannot be overridden'
3958
+ : 'Project root bundle automation cannot be overridden',
3946
3959
  });
3947
3960
  }
3948
3961
  let nextName = bundle.name;
@@ -4028,6 +4041,37 @@ app.patch('/bundles/:id', (req, res) => {
4028
4041
  return res.status(400).json({ error: 'automation_review_max_iterations must be an integer between 1 and 10' });
4029
4042
  }
4030
4043
  }
4044
+ let reviewerModel = bundle.reviewer_model ?? null;
4045
+ let reviewerVariant = reviewerModel ? bundle.reviewer_variant ?? null : null;
4046
+ if (hasOwn(req.body, 'reviewer_model')) {
4047
+ const value = req.body.reviewer_model;
4048
+ if (value == null) {
4049
+ reviewerModel = null;
4050
+ reviewerVariant = null;
4051
+ }
4052
+ else {
4053
+ const normalized = normalizeModelId(value);
4054
+ if (!normalized) {
4055
+ return res.status(400).json({ error: 'reviewer_model must be a valid model id' });
4056
+ }
4057
+ reviewerModel = normalized;
4058
+ if (!hasOwn(req.body, 'reviewer_variant')) {
4059
+ reviewerVariant = null;
4060
+ }
4061
+ }
4062
+ }
4063
+ if (hasOwn(req.body, 'reviewer_variant')) {
4064
+ const value = req.body.reviewer_variant;
4065
+ if (value == null) {
4066
+ reviewerVariant = null;
4067
+ }
4068
+ else if (typeof value === 'string' && value.trim()) {
4069
+ reviewerVariant = reviewerModel ? value.trim() : null;
4070
+ }
4071
+ else {
4072
+ return res.status(400).json({ error: 'reviewer_variant must be a non-empty string' });
4073
+ }
4074
+ }
4031
4075
  let updated = null;
4032
4076
  try {
4033
4077
  updated = db.transaction(() => {
@@ -4039,7 +4083,7 @@ app.patch('/bundles/:id', (req, res) => {
4039
4083
  branch: nextBranch,
4040
4084
  });
4041
4085
  }
4042
- return updateBundleAutomationConfig({
4086
+ updateBundleAutomationConfig({
4043
4087
  bundleId: bundle.id,
4044
4088
  projectId: result.project.id,
4045
4089
  automationDepth,
@@ -4047,6 +4091,12 @@ app.patch('/bundles/:id', (req, res) => {
4047
4091
  automationPauseOnOpenQuestions,
4048
4092
  automationReviewMaxIterations,
4049
4093
  });
4094
+ return updateBundleReviewerConfig({
4095
+ bundleId: bundle.id,
4096
+ projectId: result.project.id,
4097
+ reviewerModel,
4098
+ reviewerVariant,
4099
+ });
4050
4100
  })();
4051
4101
  }
4052
4102
  catch (error) {
@@ -4315,7 +4365,7 @@ app.post('/bundles/:id/follow-up', (req, res) => {
4315
4365
  return res.status(response.status).json(response.value);
4316
4366
  });
4317
4367
  const AUTOMATION_SIDE_EFFECT_KINDS = new Set(['automation_commit', 'automation_push', 'automation_pull_request']);
4318
- const AUTOMATION_WORKER_PAUSE_KINDS = new Set(['build', 'review', 'build_follow_up', 'automation_review_fix', 'check_repair', 'check_batch']);
4368
+ const AUTOMATION_WORKER_PAUSE_KINDS = new Set(['build', 'review', 'build_follow_up', 'automation_review_fix', 'check_auto_fix', 'check_repair', 'check_batch']);
4319
4369
  app.post('/bundles/:id/resume-automation', async (req, res) => {
4320
4370
  const result = getRequiredProject(req);
4321
4371
  if ('error' in result) {
@@ -4687,6 +4737,19 @@ app.post('/bundles/:id/resume-automation', async (req, res) => {
4687
4737
  return res.status(409).json({ error: 'Automation progression ownership is invalid' });
4688
4738
  }
4689
4739
  const workflowContext = validateWorkflowContext(progression.metadata);
4740
+ const sourceReviewRun = getLatestCompletedReviewRunForContext({
4741
+ ticketId: owner.id,
4742
+ projectId: owner.project_id,
4743
+ worktreeBundleId: owner.worktree_bundle_id,
4744
+ });
4745
+ if (!sourceReviewRun || sourceReviewRun.status !== 'completed') {
4746
+ throw new Error('The completed review findings to resume are unavailable');
4747
+ }
4748
+ const reviewFixWorkflowContext = validateWorkflowContext({
4749
+ ...(workflowContext ?? {}),
4750
+ review_finding_run_id: sourceReviewRun.id,
4751
+ review_severity: automationConfig.reviewSeverity,
4752
+ });
4690
4753
  runAutomationProgression({
4691
4754
  projectId: result.project.id,
4692
4755
  bundleId: bundle.id,
@@ -4703,7 +4766,9 @@ app.post('/bundles/:id/resume-automation', async (req, res) => {
4703
4766
  ticketId: owner.id,
4704
4767
  ticketTitle: owner.title,
4705
4768
  progressionRunId,
4706
- workflowContext,
4769
+ workflowContext: reviewFixWorkflowContext,
4770
+ reviewFindingRunId: sourceReviewRun.id,
4771
+ reviewSeverity: automationConfig.reviewSeverity,
4707
4772
  broadcaster: io,
4708
4773
  });
4709
4774
  reviewFixRunId = reviewFix.runId;
@@ -4719,7 +4784,7 @@ app.post('/bundles/:id/resume-automation', async (req, res) => {
4719
4784
  initiation: {
4720
4785
  initiator: 'automation',
4721
4786
  causalParentRunId: reviewFix.runId,
4722
- workflowContext,
4787
+ workflowContext: reviewFixWorkflowContext,
4723
4788
  },
4724
4789
  });
4725
4790
  }
@@ -5968,7 +6033,7 @@ app.post('/projects', (req, res) => {
5968
6033
  return res.status(400).json({ error: validation.error });
5969
6034
  }
5970
6035
  const projectCount = Number(db.prepare('SELECT COUNT(*) AS count FROM projects').get()?.count ?? 0);
5971
- const { name, repo_path, linked_project_ids, run_setup, run_services, check_definitions, required_check_definition_ids, pre_review_check_definition_ids, post_build_check_definition_ids, auto_fix_check_definition_ids, test_commands, run_ide, preview_service_name, preview_path, preview_capability_mode, helper_model, helper_variant, commit_message_rules, commit_after_each_ticket, auto_park_stale_tickets, memory_enabled, scan_include_globs_json, scan_exclude_globs_json, worktree_sync, spec_aware_code_review_enabled, automation_depth, automation_review_fix_enabled, automation_pause_on_open_questions, automation_review_severity, automation_review_max_iterations, } = validation.values;
6036
+ const { name, repo_path, linked_project_ids, run_setup, run_services, check_definitions, required_check_definition_ids, pre_review_check_definition_ids, post_build_check_definition_ids, auto_fix_check_definition_ids, test_commands, run_ide, preview_service_name, preview_path, preview_capability_mode, helper_model, helper_variant, reviewer_model, reviewer_variant, commit_message_rules, commit_after_each_ticket, auto_park_stale_tickets, memory_enabled, scan_include_globs_json, scan_exclude_globs_json, worktree_sync, spec_aware_code_review_enabled, automation_depth, automation_review_fix_enabled, automation_pause_on_open_questions, automation_review_severity, automation_review_max_iterations, } = validation.values;
5972
6037
  if (!repo_path) {
5973
6038
  return res.status(400).json({ error: 'repo_path must be a non-empty string' });
5974
6039
  }
@@ -6000,6 +6065,8 @@ app.post('/projects', (req, res) => {
6000
6065
  preview_capability_mode,
6001
6066
  helper_model,
6002
6067
  helper_variant,
6068
+ reviewer_model,
6069
+ reviewer_variant,
6003
6070
  commit_message_rules,
6004
6071
  commit_after_each_ticket,
6005
6072
  auto_park_stale_tickets,
@@ -6014,8 +6081,8 @@ app.post('/projects', (req, res) => {
6014
6081
  automation_review_severity,
6015
6082
  automation_review_max_iterations
6016
6083
  )
6017
- VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
6018
- `).run(id, name, normalizedRepoPath, run_setup, run_services, check_definitions, required_check_definition_ids ?? '[]', pre_review_check_definition_ids ?? '[]', post_build_check_definition_ids ?? '[]', auto_fix_check_definition_ids ?? '[]', test_commands, run_ide ?? null, preview_service_name ?? null, preview_path ?? null, preview_capability_mode ?? null, helper_model ?? null, helper_variant ?? null, commit_message_rules ?? null, commit_after_each_ticket ?? 0, auto_park_stale_tickets ?? 0, memory_enabled ?? 0, scan_include_globs_json ?? null, scan_exclude_globs_json ?? null, worktree_sync ?? null, spec_aware_code_review_enabled ?? 0, automation_depth ?? 'manual', automation_review_fix_enabled ?? 0, automation_pause_on_open_questions ?? 0, automation_review_severity ?? 'medium', automation_review_max_iterations ?? 3);
6084
+ VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
6085
+ `).run(id, name, normalizedRepoPath, run_setup, run_services, check_definitions, required_check_definition_ids ?? '[]', pre_review_check_definition_ids ?? '[]', post_build_check_definition_ids ?? '[]', auto_fix_check_definition_ids ?? '[]', test_commands, run_ide ?? null, preview_service_name ?? null, preview_path ?? null, preview_capability_mode ?? null, helper_model ?? null, helper_variant ?? null, reviewer_model ?? null, reviewer_model ? reviewer_variant ?? null : null, commit_message_rules ?? null, commit_after_each_ticket ?? 0, auto_park_stale_tickets ?? 0, memory_enabled ?? 0, scan_include_globs_json ?? null, scan_exclude_globs_json ?? null, worktree_sync ?? null, spec_aware_code_review_enabled ?? 0, automation_depth ?? 'manual', automation_review_fix_enabled ?? 0, automation_pause_on_open_questions ?? 0, automation_review_severity ?? 'medium', automation_review_max_iterations ?? 3);
6019
6086
  replaceProjectLinks(id, linked_project_ids ?? []);
6020
6087
  ensureProjectRootBundle(id);
6021
6088
  if (projectCount === 0) {
@@ -7222,7 +7289,7 @@ app.patch('/projects/:id', (req, res) => {
7222
7289
  });
7223
7290
  }
7224
7291
  }
7225
- const { name, repo_path, linked_project_ids, run_setup, run_services, check_definitions, required_check_definition_ids, pre_review_check_definition_ids, post_build_check_definition_ids, auto_fix_check_definition_ids, test_commands, run_ide, preview_service_name, preview_path, preview_capability_mode, helper_model, helper_variant, commit_message_rules, commit_after_each_ticket, auto_park_stale_tickets, memory_enabled, scan_include_globs_json, scan_exclude_globs_json, worktree_sync, spec_aware_code_review_enabled, automation_depth, automation_review_fix_enabled, automation_pause_on_open_questions, automation_review_severity, automation_review_max_iterations, } = validation.values;
7292
+ const { name, repo_path, linked_project_ids, run_setup, run_services, check_definitions, required_check_definition_ids, pre_review_check_definition_ids, post_build_check_definition_ids, auto_fix_check_definition_ids, test_commands, run_ide, preview_service_name, preview_path, preview_capability_mode, helper_model, helper_variant, reviewer_model, reviewer_variant, commit_message_rules, commit_after_each_ticket, auto_park_stale_tickets, memory_enabled, scan_include_globs_json, scan_exclude_globs_json, worktree_sync, spec_aware_code_review_enabled, automation_depth, automation_review_fix_enabled, automation_pause_on_open_questions, automation_review_severity, automation_review_max_iterations, } = validation.values;
7226
7293
  const updateProject = db.prepare(`
7227
7294
  UPDATE projects SET
7228
7295
  name = ?,
@@ -7241,6 +7308,8 @@ app.patch('/projects/:id', (req, res) => {
7241
7308
  preview_capability_mode = ?,
7242
7309
  helper_model = ?,
7243
7310
  helper_variant = ?,
7311
+ reviewer_model = ?,
7312
+ reviewer_variant = ?,
7244
7313
  commit_message_rules = ?,
7245
7314
  commit_after_each_ticket = ?,
7246
7315
  auto_park_stale_tickets = ?,
@@ -7270,6 +7339,10 @@ app.patch('/projects/:id', (req, res) => {
7270
7339
  const nextAutoFixCheckDefinitionIds = hasOwn(validation.values, 'auto_fix_check_definition_ids')
7271
7340
  ? auto_fix_check_definition_ids ?? '[]'
7272
7341
  : project.auto_fix_check_definition_ids;
7342
+ const nextReviewerModel = hasOwn(validation.values, 'reviewer_model') ? reviewer_model ?? null : project.reviewer_model;
7343
+ const nextReviewerVariant = nextReviewerModel
7344
+ ? (hasOwn(validation.values, 'reviewer_variant') ? reviewer_variant ?? null : project.reviewer_variant)
7345
+ : null;
7273
7346
  const updateResult = db.transaction(() => {
7274
7347
  const policyReferences = validateProjectRequiredCheckPolicyReferences({
7275
7348
  projectId: project.id,
@@ -7282,7 +7355,7 @@ app.patch('/projects/:id', (req, res) => {
7282
7355
  if ('error' in policyReferences) {
7283
7356
  return policyReferences;
7284
7357
  }
7285
- updateProject.run(name ?? project.name, repo_path ?? project.repo_path, hasOwn(validation.values, 'run_setup') ? run_setup : project.run_setup, hasOwn(validation.values, 'run_services') ? run_services : project.run_services, nextCheckDefinitions, nextRequiredCheckDefinitionIds, nextPreReviewCheckDefinitionIds, nextPostBuildCheckDefinitionIds, nextAutoFixCheckDefinitionIds, hasOwn(validation.values, 'test_commands') ? test_commands : project.test_commands, hasOwn(validation.values, 'run_ide') ? run_ide : project.run_ide, hasOwn(validation.values, 'preview_service_name') ? preview_service_name : project.preview_service_name, hasOwn(validation.values, 'preview_path') ? preview_path : project.preview_path, hasOwn(validation.values, 'preview_capability_mode') ? preview_capability_mode : project.preview_capability_mode, hasOwn(validation.values, 'helper_model') ? helper_model : project.helper_model, hasOwn(validation.values, 'helper_variant') ? helper_variant : project.helper_variant, hasOwn(validation.values, 'commit_message_rules') ? commit_message_rules : project.commit_message_rules, hasOwn(validation.values, 'commit_after_each_ticket') ? commit_after_each_ticket : project.commit_after_each_ticket, hasOwn(validation.values, 'auto_park_stale_tickets') ? auto_park_stale_tickets : project.auto_park_stale_tickets, hasOwn(validation.values, 'memory_enabled') ? memory_enabled : project.memory_enabled, hasOwn(validation.values, 'scan_include_globs_json') ? scan_include_globs_json : project.scan_include_globs_json, hasOwn(validation.values, 'scan_exclude_globs_json') ? scan_exclude_globs_json : project.scan_exclude_globs_json, hasOwn(validation.values, 'worktree_sync') ? worktree_sync : project.worktree_sync, hasOwn(validation.values, 'spec_aware_code_review_enabled') ? spec_aware_code_review_enabled : project.spec_aware_code_review_enabled, hasOwn(validation.values, 'automation_depth') ? automation_depth : project.automation_depth, hasOwn(validation.values, 'automation_review_fix_enabled') ? automation_review_fix_enabled : project.automation_review_fix_enabled, hasOwn(validation.values, 'automation_pause_on_open_questions') ? automation_pause_on_open_questions : project.automation_pause_on_open_questions, hasOwn(validation.values, 'automation_review_severity') ? automation_review_severity : project.automation_review_severity, hasOwn(validation.values, 'automation_review_max_iterations') ? automation_review_max_iterations : project.automation_review_max_iterations, req.params.id);
7358
+ updateProject.run(name ?? project.name, repo_path ?? project.repo_path, hasOwn(validation.values, 'run_setup') ? run_setup : project.run_setup, hasOwn(validation.values, 'run_services') ? run_services : project.run_services, nextCheckDefinitions, nextRequiredCheckDefinitionIds, nextPreReviewCheckDefinitionIds, nextPostBuildCheckDefinitionIds, nextAutoFixCheckDefinitionIds, hasOwn(validation.values, 'test_commands') ? test_commands : project.test_commands, hasOwn(validation.values, 'run_ide') ? run_ide : project.run_ide, hasOwn(validation.values, 'preview_service_name') ? preview_service_name : project.preview_service_name, hasOwn(validation.values, 'preview_path') ? preview_path : project.preview_path, hasOwn(validation.values, 'preview_capability_mode') ? preview_capability_mode : project.preview_capability_mode, hasOwn(validation.values, 'helper_model') ? helper_model : project.helper_model, hasOwn(validation.values, 'helper_variant') ? helper_variant : project.helper_variant, nextReviewerModel, nextReviewerVariant, hasOwn(validation.values, 'commit_message_rules') ? commit_message_rules : project.commit_message_rules, hasOwn(validation.values, 'commit_after_each_ticket') ? commit_after_each_ticket : project.commit_after_each_ticket, hasOwn(validation.values, 'auto_park_stale_tickets') ? auto_park_stale_tickets : project.auto_park_stale_tickets, hasOwn(validation.values, 'memory_enabled') ? memory_enabled : project.memory_enabled, hasOwn(validation.values, 'scan_include_globs_json') ? scan_include_globs_json : project.scan_include_globs_json, hasOwn(validation.values, 'scan_exclude_globs_json') ? scan_exclude_globs_json : project.scan_exclude_globs_json, hasOwn(validation.values, 'worktree_sync') ? worktree_sync : project.worktree_sync, hasOwn(validation.values, 'spec_aware_code_review_enabled') ? spec_aware_code_review_enabled : project.spec_aware_code_review_enabled, hasOwn(validation.values, 'automation_depth') ? automation_depth : project.automation_depth, hasOwn(validation.values, 'automation_review_fix_enabled') ? automation_review_fix_enabled : project.automation_review_fix_enabled, hasOwn(validation.values, 'automation_pause_on_open_questions') ? automation_pause_on_open_questions : project.automation_pause_on_open_questions, hasOwn(validation.values, 'automation_review_severity') ? automation_review_severity : project.automation_review_severity, hasOwn(validation.values, 'automation_review_max_iterations') ? automation_review_max_iterations : project.automation_review_max_iterations, req.params.id);
7286
7359
  if (hasOwn(validation.values, 'linked_project_ids')) {
7287
7360
  replaceProjectLinks(project.id, linked_project_ids ?? []);
7288
7361
  }