@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.
Files changed (180) hide show
  1. package/dist/client/assets/{ActivityView-D4Qh96zr.js → ActivityView-gBeoYQdD.js} +1 -1
  2. package/dist/client/assets/{GitHubActionsDialog-Bg03OmVv.js → GitHubActionsDialog-fc1Vwafm.js} +1 -1
  3. package/dist/client/assets/RepositoryGraphDialog-DCOjwUR3.js +1 -0
  4. package/dist/client/assets/VerificationDialog-CIObj1Rw.js +4 -0
  5. package/dist/client/assets/{architectureDiagram-3BPJPVTR-2lxabjSl.js → architectureDiagram-3BPJPVTR-B1tJZe1S.js} +1 -1
  6. package/dist/client/assets/{blockDiagram-GPEHLZMM-C80HvJmb.js → blockDiagram-GPEHLZMM-D_90AQ2Z.js} +1 -1
  7. package/dist/client/assets/{c4Diagram-AAUBKEIU-BM3k_lKz.js → c4Diagram-AAUBKEIU-DSyJfqly.js} +1 -1
  8. package/dist/client/assets/channel-DFw1f2Rh.js +1 -0
  9. package/dist/client/assets/{chunk-2J33WTMH-BTk3lX07.js → chunk-2J33WTMH-B9RStQGj.js} +1 -1
  10. package/dist/client/assets/{chunk-3OPIFGDE-DAxdBZ_4.js → chunk-3OPIFGDE-CHKuJYq0.js} +1 -1
  11. package/dist/client/assets/{chunk-5ZQYHXKU-BYm9s62a.js → chunk-5ZQYHXKU-Cznw7LTJ.js} +1 -1
  12. package/dist/client/assets/{chunk-727SXJPM-iVUM8xuV.js → chunk-727SXJPM-ix6OeZwJ.js} +1 -1
  13. package/dist/client/assets/{chunk-AQP2D5EJ-DVM7riMJ.js → chunk-AQP2D5EJ-DrPJIcE7.js} +1 -1
  14. package/dist/client/assets/{chunk-CSCIHK7Q-_D1FzP9B.js → chunk-CSCIHK7Q-BSEHTnBR.js} +1 -1
  15. package/dist/client/assets/{chunk-KSCS5N6A-D3XouAHf.js → chunk-KSCS5N6A-MdDdaLn8.js} +1 -1
  16. package/dist/client/assets/{chunk-L5ZTLDWV-B7NYWgT4.js → chunk-L5ZTLDWV-D_5xeDG1.js} +1 -1
  17. package/dist/client/assets/{chunk-LZXEDZCA-Dgkkbb6A.js → chunk-LZXEDZCA-Bz8_Fyt2.js} +2 -2
  18. package/dist/client/assets/{chunk-ND2GUHAM-CzO1oVCi.js → chunk-ND2GUHAM-DCINKlk8.js} +1 -1
  19. package/dist/client/assets/{chunk-NZK2D7GU-re0VVZne.js → chunk-NZK2D7GU-rGPgryKx.js} +1 -1
  20. package/dist/client/assets/{chunk-O5CBEL6O-BwsS59iy.js → chunk-O5CBEL6O-BHB8UIYA.js} +1 -1
  21. package/dist/client/assets/{chunk-WU5MYG2G-CLyh-xCA.js → chunk-WU5MYG2G-Bz5BJWjF.js} +1 -1
  22. package/dist/client/assets/classDiagram-4FO5ZUOK-Dt0kmMzQ.js +1 -0
  23. package/dist/client/assets/classDiagram-v2-Q7XG4LA2-BuxhA4Gw.js +1 -0
  24. package/dist/client/assets/{dagre-BM42HDAG-x71fYlqQ.js → dagre-BM42HDAG-B4TXLkOG.js} +1 -1
  25. package/dist/client/assets/{diagram-2AECGRRQ-CMdwzuYj.js → diagram-2AECGRRQ-CxMup1wq.js} +1 -1
  26. package/dist/client/assets/{diagram-5GNKFQAL-B3l6I4qJ.js → diagram-5GNKFQAL-CTfP_wnS.js} +1 -1
  27. package/dist/client/assets/{diagram-KO2AKTUF-BNhypLBW.js → diagram-KO2AKTUF-31NKNt4r.js} +1 -1
  28. package/dist/client/assets/{diagram-LMA3HP47-CmrhbiDt.js → diagram-LMA3HP47-Cxo7yvjc.js} +1 -1
  29. package/dist/client/assets/{diagram-OG6HWLK6-CRobDMLl.js → diagram-OG6HWLK6-ChgSAMLv.js} +1 -1
  30. package/dist/client/assets/{erDiagram-TEJ5UH35-CqO7K0TS.js → erDiagram-TEJ5UH35-u6msywL_.js} +1 -1
  31. package/dist/client/assets/{flowDiagram-I6XJVG4X-CuLTJZU0.js → flowDiagram-I6XJVG4X-CimeXkDN.js} +1 -1
  32. package/dist/client/assets/{ganttDiagram-6RSMTGT7-Bm7v1eRG.js → ganttDiagram-6RSMTGT7-DOu5sDUI.js} +1 -1
  33. package/dist/client/assets/{gitGraphDiagram-PVQCEYII-CNHZr-5i.js → gitGraphDiagram-PVQCEYII-zIToibUf.js} +1 -1
  34. package/dist/client/assets/index-C-VHd0Pr.js +274 -0
  35. package/dist/client/assets/index-D3xlEyeM.css +2 -0
  36. package/dist/client/assets/{infoDiagram-5YYISTIA-z27pUr2X.js → infoDiagram-5YYISTIA-CAtWGGJI.js} +1 -1
  37. package/dist/client/assets/{ishikawaDiagram-YF4QCWOH-CDocZ0jf.js → ishikawaDiagram-YF4QCWOH-7N-C7DEt.js} +1 -1
  38. package/dist/client/assets/{journeyDiagram-JHISSGLW-CgP31lsU.js → journeyDiagram-JHISSGLW-D7VUypFG.js} +1 -1
  39. package/dist/client/assets/{kanban-definition-UN3LZRKU-DxTm1_fc.js → kanban-definition-UN3LZRKU-AmbDmzSD.js} +1 -1
  40. package/dist/client/assets/{line-hrZ7m44_.js → line-qf4UZ8vh.js} +1 -1
  41. package/dist/client/assets/{mermaid-parser.core-BThJAIK-.js → mermaid-parser.core-BssCd1kF.js} +1 -1
  42. package/dist/client/assets/{mermaid.core-CfVyP_kK.js → mermaid.core-DzeMqg9Y.js} +3 -3
  43. package/dist/client/assets/{mindmap-definition-RKZ34NQL-CuISnLgW.js → mindmap-definition-RKZ34NQL-dEnNQcDm.js} +1 -1
  44. package/dist/client/assets/{pieDiagram-4H26LBE5-DnWAdd44.js → pieDiagram-4H26LBE5-VjMue0a-.js} +1 -1
  45. package/dist/client/assets/{quadrantDiagram-W4KKPZXB-Cb-RVl5A.js → quadrantDiagram-W4KKPZXB-DQFdm-0f.js} +1 -1
  46. package/dist/client/assets/{requirementDiagram-4Y6WPE33-DrXg_gCS.js → requirementDiagram-4Y6WPE33-CHIaXlsy.js} +1 -1
  47. package/dist/client/assets/{sankeyDiagram-5OEKKPKP-DzZjp_ZP.js → sankeyDiagram-5OEKKPKP-D-kzGaKb.js} +1 -1
  48. package/dist/client/assets/{sequenceDiagram-3UESZ5HK-CQJ3PhQD.js → sequenceDiagram-3UESZ5HK-CiDmlD8k.js} +1 -1
  49. package/dist/client/assets/{stateDiagram-AJRCARHV-B16j9pg1.js → stateDiagram-AJRCARHV-BKlnnFdT.js} +1 -1
  50. package/dist/client/assets/stateDiagram-v2-BHNVJYJU-DhJxc4em.js +1 -0
  51. package/dist/client/assets/{timeline-definition-PNZ67QCA-bUG3mZQt.js → timeline-definition-PNZ67QCA-D-BK07Un.js} +1 -1
  52. package/dist/client/assets/{vennDiagram-CIIHVFJN-DALCJcZD.js → vennDiagram-CIIHVFJN-CB9_GqSx.js} +1 -1
  53. package/dist/client/assets/{wardleyDiagram-YWT4CUSO-DPQd3l9A.js → wardleyDiagram-YWT4CUSO-BEuNfyLT.js} +1 -1
  54. package/dist/client/assets/{xychartDiagram-2RQKCTM6-BIv1FqXG.js → xychartDiagram-2RQKCTM6-CSS5WMrZ.js} +1 -1
  55. package/dist/client/index.html +2 -2
  56. package/dist/server/db.js +481 -27
  57. package/dist/server/db.js.map +1 -1
  58. package/dist/server/index.js +113 -54
  59. package/dist/server/index.js.map +1 -1
  60. package/dist/server/lib/activeAutomationChild.js +1 -0
  61. package/dist/server/lib/activeAutomationChild.js.map +1 -1
  62. package/dist/server/lib/agent.js +127 -15
  63. package/dist/server/lib/agent.js.map +1 -1
  64. package/dist/server/lib/agentRuns.js +12 -0
  65. package/dist/server/lib/agentRuns.js.map +1 -1
  66. package/dist/server/lib/agentSpawnPermits.js +37 -0
  67. package/dist/server/lib/agentSpawnPermits.js.map +1 -0
  68. package/dist/server/lib/automationCheckGate.js +9 -1
  69. package/dist/server/lib/automationCheckGate.js.map +1 -1
  70. package/dist/server/lib/automationProgression.js +19 -5
  71. package/dist/server/lib/automationProgression.js.map +1 -1
  72. package/dist/server/lib/automationReviewGate.js +1 -0
  73. package/dist/server/lib/automationReviewGate.js.map +1 -1
  74. package/dist/server/lib/buildCompletionContinuation.js +144 -4
  75. package/dist/server/lib/buildCompletionContinuation.js.map +1 -1
  76. package/dist/server/lib/buildSequences.js +13 -1
  77. package/dist/server/lib/buildSequences.js.map +1 -1
  78. package/dist/server/lib/bundleActivity.js +19 -0
  79. package/dist/server/lib/bundleActivity.js.map +1 -1
  80. package/dist/server/lib/chatOperations.js +81 -2
  81. package/dist/server/lib/chatOperations.js.map +1 -1
  82. package/dist/server/lib/checkAutoFix.js +604 -0
  83. package/dist/server/lib/checkAutoFix.js.map +1 -0
  84. package/dist/server/lib/checkAutoFixDetails.js +83 -0
  85. package/dist/server/lib/checkAutoFixDetails.js.map +1 -0
  86. package/dist/server/lib/checkAutoFixPolicy.js +59 -0
  87. package/dist/server/lib/checkAutoFixPolicy.js.map +1 -0
  88. package/dist/server/lib/checkRepair.js +149 -54
  89. package/dist/server/lib/checkRepair.js.map +1 -1
  90. package/dist/server/lib/checkRepairDispatch.js +91 -0
  91. package/dist/server/lib/checkRepairDispatch.js.map +1 -0
  92. package/dist/server/lib/checkRepairEvidence.js +84 -0
  93. package/dist/server/lib/checkRepairEvidence.js.map +1 -0
  94. package/dist/server/lib/checkRepairParent.js +21 -0
  95. package/dist/server/lib/checkRepairParent.js.map +1 -0
  96. package/dist/server/lib/checkRepairReconciliation.js +14 -5
  97. package/dist/server/lib/checkRepairReconciliation.js.map +1 -1
  98. package/dist/server/lib/checkRunner.js +27 -8
  99. package/dist/server/lib/checkRunner.js.map +1 -1
  100. package/dist/server/lib/checkRuns.js +63 -4
  101. package/dist/server/lib/checkRuns.js.map +1 -1
  102. package/dist/server/lib/executionReconciliation.js +387 -8
  103. package/dist/server/lib/executionReconciliation.js.map +1 -1
  104. package/dist/server/lib/executionRuns.js +24 -1
  105. package/dist/server/lib/executionRuns.js.map +1 -1
  106. package/dist/server/lib/git.js +302 -11
  107. package/dist/server/lib/git.js.map +1 -1
  108. package/dist/server/lib/integrations/github.js +138 -65
  109. package/dist/server/lib/integrations/github.js.map +1 -1
  110. package/dist/server/lib/integrations/importedIssueImages.js +10 -15
  111. package/dist/server/lib/integrations/importedIssueImages.js.map +1 -1
  112. package/dist/server/lib/postBuildCheckRuns.js +200 -5
  113. package/dist/server/lib/postBuildCheckRuns.js.map +1 -1
  114. package/dist/server/lib/postBuildChecks.js +83 -13
  115. package/dist/server/lib/postBuildChecks.js.map +1 -1
  116. package/dist/server/lib/projects.js +25 -1
  117. package/dist/server/lib/projects.js.map +1 -1
  118. package/dist/server/lib/queue.js +9 -3
  119. package/dist/server/lib/queue.js.map +1 -1
  120. package/dist/server/lib/repositoryGraphQueries.js +5 -3
  121. package/dist/server/lib/repositoryGraphQueries.js.map +1 -1
  122. package/dist/server/lib/repositoryGraphScan.js +13 -2
  123. package/dist/server/lib/repositoryGraphScan.js.map +1 -1
  124. package/dist/server/lib/repositoryGraphStore.js +61 -1
  125. package/dist/server/lib/repositoryGraphStore.js.map +1 -1
  126. package/dist/server/lib/specArtifact.js +10 -1
  127. package/dist/server/lib/specArtifact.js.map +1 -1
  128. package/dist/server/lib/specDraft.js +10 -2
  129. package/dist/server/lib/specDraft.js.map +1 -1
  130. package/dist/server/lib/specExport.js +70 -6
  131. package/dist/server/lib/specExport.js.map +1 -1
  132. package/dist/server/lib/specFormatting.js +3 -2
  133. package/dist/server/lib/specFormatting.js.map +1 -1
  134. package/dist/server/lib/specRepositoryEvidenceFormatting.js +75 -0
  135. package/dist/server/lib/specRepositoryEvidenceFormatting.js.map +1 -0
  136. package/dist/server/lib/specRepositoryImpact.js +447 -0
  137. package/dist/server/lib/specRepositoryImpact.js.map +1 -0
  138. package/dist/server/lib/specRepositoryImpactLimits.js +6 -0
  139. package/dist/server/lib/specRepositoryImpactLimits.js.map +1 -0
  140. package/dist/server/lib/specReviewContext.js +15 -5
  141. package/dist/server/lib/specReviewContext.js.map +1 -1
  142. package/dist/server/lib/specReviewValidation.js +1 -1
  143. package/dist/server/lib/specReviewValidation.js.map +1 -1
  144. package/dist/server/lib/specSections.js +28 -3
  145. package/dist/server/lib/specSections.js.map +1 -1
  146. package/dist/server/lib/specSnapshotEvidence.js +162 -0
  147. package/dist/server/lib/specSnapshotEvidence.js.map +1 -0
  148. package/dist/server/lib/specSnapshotEvidenceSerialization.js +202 -0
  149. package/dist/server/lib/specSnapshotEvidenceSerialization.js.map +1 -0
  150. package/dist/server/lib/specs.js +31 -5
  151. package/dist/server/lib/specs.js.map +1 -1
  152. package/dist/server/lib/ticketAutomationCommit.js +3 -1
  153. package/dist/server/lib/ticketAutomationCommit.js.map +1 -1
  154. package/dist/server/lib/ticketFollowUpOperations.js +16 -12
  155. package/dist/server/lib/ticketFollowUpOperations.js.map +1 -1
  156. package/dist/server/lib/ticketRunOperations.js +13 -1
  157. package/dist/server/lib/ticketRunOperations.js.map +1 -1
  158. package/dist/server/lib/ticketWorkflowOperations.js +5 -2
  159. package/dist/server/lib/ticketWorkflowOperations.js.map +1 -1
  160. package/dist/server/lib/types.js +1 -0
  161. package/dist/server/lib/types.js.map +1 -1
  162. package/dist/server/workers/build.js +46 -148
  163. package/dist/server/workers/build.js.map +1 -1
  164. package/dist/server/workers/chat.js +141 -31
  165. package/dist/server/workers/chat.js.map +1 -1
  166. package/dist/server/workers/followUp.js +210 -48
  167. package/dist/server/workers/followUp.js.map +1 -1
  168. package/dist/server/workers/specReview.js +17 -4
  169. package/dist/server/workers/specReview.js.map +1 -1
  170. package/dist/server/workers/specSession.js +127 -22
  171. package/dist/server/workers/specSession.js.map +1 -1
  172. package/package.json +1 -1
  173. package/dist/client/assets/RepositoryGraphDialog-CS_hOqPw.js +0 -1
  174. package/dist/client/assets/VerificationDialog-BYH-Ek8n.js +0 -4
  175. package/dist/client/assets/channel-HjENOCZ0.js +0 -1
  176. package/dist/client/assets/classDiagram-4FO5ZUOK-DnhdaVrK.js +0 -1
  177. package/dist/client/assets/classDiagram-v2-Q7XG4LA2-C-BjeSGJ.js +0 -1
  178. package/dist/client/assets/index-Bs5SQZhz.css +0 -2
  179. package/dist/client/assets/index-LGNsdNYM.js +0 -274
  180. package/dist/client/assets/stateDiagram-v2-BHNVJYJU-vNiFfHwm.js +0 -1
@@ -12,6 +12,8 @@ import { pruneAllRepositoryGraphScans } from './lib/repositoryGraphRetention.js'
12
12
  import { registerRepositoryGraphRoutes } from './lib/repositoryGraphRoutes.js';
13
13
  import { deleteChatSession, getChatSession, listChatSessions } from './lib/chats.js';
14
14
  import { deleteSpecSession, getCreatedTicketIdsForSnapshot, getSpecSession, getSpecSnapshot, listSpecSessions } from './lib/specs.js';
15
+ import { getSpecSnapshotRepositoryEvidenceFreshness } from './lib/specSnapshotEvidence.js';
16
+ import { projectSpecSnapshotForActionPrompt } from './lib/specRepositoryEvidenceFormatting.js';
15
17
  import { createChatAttachment, createSpecAttachment, getAttachmentById, deleteChatAttachment, deleteProjectAttachments, deleteSpecSessionAttachment, getChatAttachmentForSession, getChatAttachmentLinkedMessageId, getSpecAttachmentForSession, getSpecAttachmentLinkedMessageId, MAX_CHAT_ATTACHMENTS_PER_TURN, MAX_CHAT_ATTACHMENT_SIZE_BYTES, MAX_SPEC_ATTACHMENTS_PER_TURN, MAX_SPEC_ATTACHMENT_SIZE_BYTES, readChatAttachmentContent, readSpecAttachmentContent, validateImageAttachment, } from './lib/attachments.js';
16
18
  import { createProjectChatSession, resolveChatTool, resolveProjectChatPlanQuestionSet, stopProjectChatSessionResponse, submitProjectChatSessionMessage, updateProjectChatSessionMode, } from './lib/chatOperations.js';
17
19
  import { createProjectSpecSession, deleteProjectSpecSession, resolveProjectSpecPlanQuestionSet, stopProjectSpecSessionResponse, submitProjectSpecSessionMessage, updateProjectSpecSessionMode, } from './lib/specOperations.js';
@@ -21,7 +23,7 @@ import { resolveSessionTargetForExecution } from './lib/sessionTargets.js';
21
23
  import { createChatMessage, getChatMessage, updateChatMessageContent } from './lib/chatMessages.js';
22
24
  import { attachChatTicketProposalsToMessageContent } from './lib/chatTicketProposals.js';
23
25
  import { createCorsOriginResolver, parseCorsOrigins } from './lib/cors.js';
24
- import { abortGitOperation, branchExistsLocally, commitGitChanges, createWorktreeAsync, deleteWorktree, getBundleReviewDiffForCwd, getGitDiffData, getGitDiffFiles, getGitStatus, getGitUnifiedDiff, getLocalProjectBranch, getProjectBranch, getProjectBranchSuggestions, getSelectedGitUnifiedDiff, getUnpushedCommitDiffForCwd, getUnpushedCommitSummaryForCwd, hasKnownBranchRef, listUnpushedCommitsForCwd, pullGitBranch, pushCurrentBranch, rebaseGitBranchOntoBase, resolveExistingWorktreePath, resolveWorktreePath, squashUnpushedCommitsForCwd, summarizeTicketDiffFiles, switchProjectBranch, syncWorktreeFilesAsync, undoLatestUnpushedCommitForCwd, UnpushedCommitDiffSelectionError } from './lib/git.js';
26
+ import { abortGitOperation, branchExistsLocally, commitGitChanges, createWorktreeAsync, deleteWorktree, getBundleReviewDiffForCwd, getGitDiffDataAsync, getGitDiffFiles, getGitStatus, getGitStatusAsync, getGitUnifiedDiff, getGitUnifiedDiffAsync, getLocalProjectBranch, getProjectBranch, getProjectBranchSuggestions, getSelectedGitUnifiedDiff, getUnpushedCommitDiffForCwd, getUnpushedCommitSummaryForCwd, getUnpushedCommitSummaryForCwdAsync, hasKnownBranchRef, listUnpushedCommitsForCwd, pullGitBranch, pushCurrentBranch, rebaseGitBranchOntoBase, resolveExistingWorktreePath, resolveWorktreePath, squashUnpushedCommitsForCwd, summarizeTicketDiffFiles, switchProjectBranch, syncWorktreeFilesAsync, undoLatestUnpushedCommitForCwd, UnpushedCommitDiffSelectionError } from './lib/git.js';
25
27
  import config from './lib/config.js';
26
28
  import { autoConfigProject, ProjectAutoConfigError } from './lib/projectAutoConfig.js';
27
29
  import { analyzeRepoPath, createInitialCommit, ensureInitialCommitForWorktrees, initializeGitRepo, isInitialCommitRequiredError, } from './lib/projectRepos.js';
@@ -88,7 +90,8 @@ import { getActiveRunStatus, getActiveRunStatusForProject, getPreviewStatusForPr
88
90
  import { clearAllTestSessions, createTestSession, deleteTestSession, discoverTestsForSession, doesTestFileExistForSession, getTestSession, isTestSelectionSupported, startTestSessionRun, stopTestSessionRun } from './lib/testSessions.js';
89
91
  import { closeCheckRunnerAdmissions, getCheckBatchAttempts, openCheckRunnerAdmissions, rerunCheckBatchAndSchedule, shutdownCheckRunner, startCheckBatch, stopCheckBatch } from './lib/checkRunner.js';
90
92
  import { CheckRepairError, getCheckRepairCandidateState, getCheckRepairDetails, getLatestCheckRepairForBatch, retryCheckRepair, startCheckRepair, stopCheckRepair } from './lib/checkRepair.js';
91
- import { findActiveCheckBatchForTarget, getCheckAttemptDetails, getCheckBatchDetails, hasActiveProjectCheckBatch, isCheckAttemptCurrent, resolveCheckBatchRerunEligibility } from './lib/checkRuns.js';
93
+ import { getCheckAutoFixDetails, stopCheckAutoFix } from './lib/checkAutoFix.js';
94
+ import { findActiveCheckAutoFixForTarget, findActiveCheckBatchForTarget, getCheckAttemptDetails, getCheckBatchDetails, hasActiveProjectCheckBatch, isCheckAttemptCurrent, resolveCheckBatchRerunEligibility } from './lib/checkRuns.js';
92
95
  import { getCheckAttemptDiagnosticResponse, getCheckBatchDiagnosticResponse } from './lib/checkDiagnostics.js';
93
96
  import { getCheckDefinitionFingerprint } from './lib/checkDefinitions.js';
94
97
  import { getCheckGateEvaluation, hydrateCheckGatePresentApplicability } from './lib/checkGateEvaluations.js';
@@ -113,7 +116,7 @@ import { parseIncomingExternalSource } from './lib/externalSource.js';
113
116
  import { materializeTicketsWithDependencies } from './lib/ticketBatch.js';
114
117
  import { IMPLEMENTATION_READY_DESCRIPTION_SECTION_HEADINGS } from './lib/ticketDescriptionContract.js';
115
118
  import { buildImplementationResourcesAppendix, buildSpecImplementationDraft, buildVisualizationAppendix } from './lib/specDraft.js';
116
- import { exportSpecToDocs, checkSpecExportCollision } from './lib/specExport.js';
119
+ import { exportSpecToDocs, checkSpecExportCollision, SpecExportCollisionError } from './lib/specExport.js';
117
120
  import { createTicketDependency, deleteTicketDependenciesForTicket, deleteTicketDependency, getTicketDependency, isTicketBuildComplete, isTicketRunSetupReady, listTicketDependencies, validateCreateTicketDependency, } from './lib/ticketDependencies.js';
118
121
  import { startBuild } from './workers/build.js';
119
122
  import { expandPlanningTicketOutline, generatePlanningTicketOutline, generatePlanText, prepareLinkedPlanningResearch, startPlan, stopAllPlanAgents, } from './workers/plan.js';
@@ -425,11 +428,19 @@ const buildExecutionRunDetailResponse = async (project, run) => {
425
428
  retry_eligibility: retryEligibility,
426
429
  action_kind: null,
427
430
  }
428
- : run.kind === 'github_actions'
429
- ? { ...serializeGitHubActionsExecutionDetail(getGitHubActionsExecutionDetails(project.id, run.id)), retry_eligibility: retryEligibility }
430
- : ['automation_commit', 'automation_push', 'automation_pull_request'].includes(run.kind)
431
- ? { kind: run.kind, available: true, automation_stage: getAutomationStageDetails(project.id, run.id), retry_eligibility: retryEligibility }
432
- : { kind: run.kind, available: true, retry_eligibility: retryEligibility };
431
+ : run.kind === 'check_auto_fix'
432
+ ? {
433
+ kind: 'check_auto_fix',
434
+ available: true,
435
+ check_auto_fix: getCheckAutoFixDetails(project.id, run.id),
436
+ retry_eligibility: retryEligibility,
437
+ action_kind: null,
438
+ }
439
+ : run.kind === 'github_actions'
440
+ ? { ...serializeGitHubActionsExecutionDetail(getGitHubActionsExecutionDetails(project.id, run.id)), retry_eligibility: retryEligibility }
441
+ : ['automation_commit', 'automation_push', 'automation_pull_request'].includes(run.kind)
442
+ ? { kind: run.kind, available: true, automation_stage: getAutomationStageDetails(project.id, run.id), retry_eligibility: retryEligibility }
443
+ : { kind: run.kind, available: true, retry_eligibility: retryEligibility };
433
444
  const artifacts = loadExecutionArtifactSummariesForRuns(project.id, [run.id], MAX_ARTIFACTS_PER_RUN).get(run.id)
434
445
  ?? { artifacts: [], artifact_count: 0 };
435
446
  return {
@@ -490,7 +501,8 @@ const getBundlePlanBlockerError = () => {
490
501
  return 'AI planning is blocked because this bundle worktree is currently being modified.';
491
502
  };
492
503
  const hasActiveBundleCheckWork = (projectId, bundleId) => Boolean(getActiveBundleRepairBlocker(bundleId)
493
- || findActiveCheckBatchForTarget(projectId, 'bundle', bundleId));
504
+ || findActiveCheckBatchForTarget(projectId, 'bundle', bundleId)
505
+ || findActiveCheckAutoFixForTarget(projectId, 'bundle', bundleId));
494
506
  const deleteTicketRecord = async (ticket) => {
495
507
  if (ticket.project_id
496
508
  && ticket.worktree_bundle_id
@@ -1446,8 +1458,8 @@ const bundlePullRequestDiscoveryErrorTimestamps = new Map();
1446
1458
  const bundlePullRequestSyncInFlight = new Map();
1447
1459
  const bundlePullRequestSyncErrorTimestamps = new Map();
1448
1460
  const getBundlePullRequestDiscoveryKey = (projectId, bundleId) => `${projectId}:${bundleId}`;
1449
- const startPassiveGitHubWork = (label, callback) => {
1450
- setImmediate(() => {
1461
+ const startPassiveGitHubWork = (response, label, callback) => {
1462
+ const start = () => setImmediate(() => {
1451
1463
  try {
1452
1464
  callback();
1453
1465
  }
@@ -1455,6 +1467,11 @@ const startPassiveGitHubWork = (label, callback) => {
1455
1467
  console.warn(`[integrations] github passive work failed ${label}`, error);
1456
1468
  }
1457
1469
  });
1470
+ if (response.writableFinished) {
1471
+ start();
1472
+ return;
1473
+ }
1474
+ response.once('finish', start);
1458
1475
  };
1459
1476
  const isBundlePullRequestDiscoveryCoolingDown = (timestamps, key, cooldownMs) => {
1460
1477
  const lastAttemptAt = timestamps.get(key);
@@ -2019,7 +2036,7 @@ const buildBundleTickets = (projectId, bundleId, broadcaster) => {
2019
2036
  value: details,
2020
2037
  };
2021
2038
  };
2022
- const getCurrentReviewWorkspaceSignature = (ticket) => {
2039
+ const getCurrentReviewWorkspaceSignature = async (ticket) => {
2023
2040
  if (!ticket) {
2024
2041
  return null;
2025
2042
  }
@@ -2027,9 +2044,9 @@ const getCurrentReviewWorkspaceSignature = (ticket) => {
2027
2044
  if ('error' in workspace) {
2028
2045
  return null;
2029
2046
  }
2030
- return getGitStatus(workspace.cwd, workspace.branch, workspace.project).workspace_signature ?? null;
2047
+ return (await getGitStatusAsync(workspace.cwd, workspace.branch, workspace.project)).workspace_signature ?? null;
2031
2048
  };
2032
- const getCurrentReviewDiffSignature = (ticket) => {
2049
+ const getCurrentReviewDiffSignature = async (ticket) => {
2033
2050
  if (!ticket) {
2034
2051
  return null;
2035
2052
  }
@@ -2037,9 +2054,9 @@ const getCurrentReviewDiffSignature = (ticket) => {
2037
2054
  if ('error' in workspace) {
2038
2055
  return null;
2039
2056
  }
2040
- return computeDiffSignature(getGitUnifiedDiff(workspace.cwd));
2057
+ return computeDiffSignature(await getGitUnifiedDiffAsync(workspace.cwd));
2041
2058
  };
2042
- const getBundleReviewFindings = (projectId, bundleId) => {
2059
+ const getBundleReviewFindings = async (projectId, bundleId) => {
2043
2060
  const bundle = getBundle(bundleId, projectId);
2044
2061
  if (!bundle) {
2045
2062
  return null;
@@ -2070,13 +2087,13 @@ const getBundleReviewFindings = (projectId, bundleId) => {
2070
2087
  return buildReviewFindingsResponse({
2071
2088
  context,
2072
2089
  isContextRunning: tickets.some(ticket => ticket.agent_status === 'running'),
2073
- currentWorkspaceSignature: getCurrentReviewWorkspaceSignature(representativeTicket),
2090
+ currentWorkspaceSignature: await getCurrentReviewWorkspaceSignature(representativeTicket),
2074
2091
  currentDiffSignature: latestReviewRun && latestReviewRun.workspace_signature === null
2075
- ? getCurrentReviewDiffSignature(representativeTicket)
2092
+ ? await getCurrentReviewDiffSignature(representativeTicket)
2076
2093
  : null,
2077
2094
  });
2078
2095
  };
2079
- const getTicketReviewFindings = (ticketId) => {
2096
+ const getTicketReviewFindings = async (ticketId) => {
2080
2097
  const ticket = getTicketRouteContext(ticketId);
2081
2098
  if (!ticket) {
2082
2099
  return null;
@@ -2090,9 +2107,9 @@ const getTicketReviewFindings = (ticketId) => {
2090
2107
  return buildReviewFindingsResponse({
2091
2108
  context,
2092
2109
  isContextRunning: ticket.agent_status === 'running',
2093
- currentWorkspaceSignature: getCurrentReviewWorkspaceSignature(ticket),
2110
+ currentWorkspaceSignature: await getCurrentReviewWorkspaceSignature(ticket),
2094
2111
  currentDiffSignature: latestReviewRun && latestReviewRun.workspace_signature === null
2095
- ? getCurrentReviewDiffSignature(ticket)
2112
+ ? await getCurrentReviewDiffSignature(ticket)
2096
2113
  : null,
2097
2114
  });
2098
2115
  };
@@ -2733,13 +2750,14 @@ app.post('/projects/:id/chat-sessions/:sessionId/stop', async (req, res) => {
2733
2750
  const result = await stopProjectChatSessionResponse({
2734
2751
  projectId: req.params.id,
2735
2752
  chatSessionId: req.params.sessionId,
2753
+ broadcaster: io,
2736
2754
  });
2737
2755
  if (!result.ok) {
2738
2756
  return res.status(result.status).json({ error: result.error });
2739
2757
  }
2740
2758
  return res.status(result.status).json(result.value);
2741
2759
  });
2742
- app.get('/projects/:id/chat-sessions/:sessionId/diff', (req, res) => {
2760
+ app.get('/projects/:id/chat-sessions/:sessionId/diff', async (req, res) => {
2743
2761
  const project = getProjectById(req.params.id);
2744
2762
  if (!project) {
2745
2763
  return res.status(404).json({ error: 'Not found' });
@@ -2752,14 +2770,14 @@ app.get('/projects/:id/chat-sessions/:sessionId/diff', (req, res) => {
2752
2770
  if (!workspace.target_available || !workspace.cwd) {
2753
2771
  return res.status(409).json({ error: workspace.target_unavailable_reason ?? 'Chat target is unavailable.' });
2754
2772
  }
2755
- const diffData = getGitDiffData(workspace.cwd);
2773
+ const diffData = await getGitDiffDataAsync(workspace.cwd);
2756
2774
  return res.json({
2757
2775
  stats: summarizeTicketDiffFiles(diffData.files),
2758
2776
  files: diffData.files,
2759
2777
  diff: diffData.diff,
2760
2778
  });
2761
2779
  });
2762
- app.get('/projects/:id/chat-sessions/:sessionId/git-status', (req, res) => {
2780
+ app.get('/projects/:id/chat-sessions/:sessionId/git-status', async (req, res) => {
2763
2781
  const project = getProjectById(req.params.id);
2764
2782
  if (!project) {
2765
2783
  return res.status(404).json({ error: 'Not found' });
@@ -2772,7 +2790,7 @@ app.get('/projects/:id/chat-sessions/:sessionId/git-status', (req, res) => {
2772
2790
  if (!workspace.target_available || !workspace.cwd) {
2773
2791
  return res.status(409).json({ error: workspace.target_unavailable_reason ?? 'Chat target is unavailable.' });
2774
2792
  }
2775
- return res.json(getGitStatus(workspace.cwd, workspace.branch, project));
2793
+ return res.json(await getGitStatusAsync(workspace.cwd, workspace.branch, project));
2776
2794
  });
2777
2795
  app.delete('/projects/:id/chat-sessions/:sessionId', (req, res) => {
2778
2796
  const project = getProjectById(req.params.id);
@@ -3073,7 +3091,7 @@ app.delete('/projects/:id/spec-sessions/:sessionId', (req, res) => {
3073
3091
  });
3074
3092
  return res.json({ ok: true });
3075
3093
  });
3076
- app.get('/projects/:id/spec-sessions/:sessionId/snapshots/:snapshotId', (req, res) => {
3094
+ app.get('/projects/:id/spec-sessions/:sessionId/snapshots/:snapshotId', async (req, res) => {
3077
3095
  const project = getProjectById(req.params.id);
3078
3096
  if (!project) {
3079
3097
  return res.status(404).json({ error: 'Not found' });
@@ -3091,6 +3109,7 @@ app.get('/projects/:id/spec-sessions/:sessionId/snapshots/:snapshotId', (req, re
3091
3109
  }
3092
3110
  return res.json({
3093
3111
  ...snapshot,
3112
+ repository_evidence_freshness: await getSpecSnapshotRepositoryEvidenceFreshness(project, snapshot.repository_evidence),
3094
3113
  created_ticket_ids: getCreatedTicketIdsForSnapshot(snapshot.id, project.id),
3095
3114
  });
3096
3115
  });
@@ -3190,7 +3209,7 @@ app.post('/projects/:id/spec-sessions/:sessionId/snapshots/:snapshotId/create-ti
3190
3209
  return res.status(500).json({ error: getErrorMessage(error) || 'Unable to create tickets from the spec snapshot.' });
3191
3210
  }
3192
3211
  });
3193
- app.post('/projects/:id/spec-sessions/:sessionId/snapshots/:snapshotId/implement-in-chat', (req, res) => {
3212
+ app.post('/projects/:id/spec-sessions/:sessionId/snapshots/:snapshotId/implement-in-chat', async (req, res) => {
3194
3213
  const project = getProjectById(req.params.id);
3195
3214
  if (!project) {
3196
3215
  return res.status(404).json({ error: 'Not found' });
@@ -3207,14 +3226,20 @@ app.post('/projects/:id/spec-sessions/:sessionId/snapshots/:snapshotId/implement
3207
3226
  if (!targetResult.ok) {
3208
3227
  return res.status(409).json({ error: targetResult.error });
3209
3228
  }
3210
- const draftText = buildSpecImplementationDraft({ snapshot, specSession });
3229
+ const repositoryEvidenceFreshness = await getSpecSnapshotRepositoryEvidenceFreshness(project, snapshot.repository_evidence, { uncached: true });
3230
+ const promptSnapshot = projectSpecSnapshotForActionPrompt(snapshot, repositoryEvidenceFreshness);
3231
+ const draftText = buildSpecImplementationDraft({
3232
+ snapshot: promptSnapshot,
3233
+ specSession,
3234
+ repositoryEvidenceFreshness,
3235
+ });
3211
3236
  return res.status(200).json({
3212
3237
  draft_text: draftText,
3213
3238
  spec_session_id: specSession.id,
3214
3239
  spec_snapshot_id: snapshot.id,
3215
3240
  });
3216
3241
  });
3217
- app.post('/projects/:id/spec-sessions/:sessionId/snapshots/:snapshotId/export', (req, res) => {
3242
+ app.post('/projects/:id/spec-sessions/:sessionId/snapshots/:snapshotId/export', async (req, res) => {
3218
3243
  const project = getProjectById(req.params.id);
3219
3244
  if (!project) {
3220
3245
  return res.status(404).json({ error: 'Not found' });
@@ -3243,10 +3268,14 @@ app.post('/projects/:id/spec-sessions/:sessionId/snapshots/:snapshotId/export',
3243
3268
  conflicting_path: collision,
3244
3269
  });
3245
3270
  }
3271
+ const repositoryEvidenceFreshness = await getSpecSnapshotRepositoryEvidenceFreshness(project, snapshot.repository_evidence, { uncached: true });
3272
+ const exportSnapshot = projectSpecSnapshotForActionPrompt(snapshot, repositoryEvidenceFreshness);
3246
3273
  const result = exportSpecToDocs({
3247
- snapshot,
3274
+ snapshot: exportSnapshot,
3248
3275
  specSession,
3249
3276
  repoPath: targetResult.target.cwd,
3277
+ repositoryEvidenceFreshness,
3278
+ overwrite,
3250
3279
  });
3251
3280
  return res.status(201).json({
3252
3281
  path: result.filePath,
@@ -3254,6 +3283,12 @@ app.post('/projects/:id/spec-sessions/:sessionId/snapshots/:snapshotId/export',
3254
3283
  });
3255
3284
  }
3256
3285
  catch (error) {
3286
+ if (error instanceof SpecExportCollisionError) {
3287
+ return res.status(409).json({
3288
+ error: error.message,
3289
+ conflicting_path: error.filePath,
3290
+ });
3291
+ }
3257
3292
  return res.status(500).json({ error: getErrorMessage(error) || 'Unable to export the spec snapshot.' });
3258
3293
  }
3259
3294
  });
@@ -3353,14 +3388,14 @@ app.get('/tickets/:id', async (req, res) => {
3353
3388
  res.json(ticket);
3354
3389
  if (passivePullRequestContext) {
3355
3390
  const { project, bundle } = passivePullRequestContext;
3356
- startPassiveGitHubWork('ticket-open-pr-sync', () => {
3391
+ startPassiveGitHubWork(res, 'ticket-open-pr-sync', () => {
3357
3392
  startTrackedBundlePullRequestSyncIfNeeded(project, bundle);
3358
3393
  startBundlePullRequestDiscoveryIfNeeded(project, bundle);
3359
3394
  });
3360
3395
  }
3361
3396
  return;
3362
3397
  });
3363
- app.get('/tickets/:id/review-findings', (req, res) => {
3398
+ app.get('/tickets/:id/review-findings', async (req, res) => {
3364
3399
  const ticket = getTicketRouteContext(req.params.id);
3365
3400
  if (!ticket) {
3366
3401
  return res.status(404).json({ error: 'Not found' });
@@ -3368,7 +3403,7 @@ app.get('/tickets/:id/review-findings', (req, res) => {
3368
3403
  if (!matchesTicketProjectContext(ticket, req)) {
3369
3404
  return res.status(404).json({ error: 'Not found' });
3370
3405
  }
3371
- const response = getTicketReviewFindings(ticket.id);
3406
+ const response = await getTicketReviewFindings(ticket.id);
3372
3407
  if (!response) {
3373
3408
  return res.status(404).json({ error: 'Not found' });
3374
3409
  }
@@ -3384,7 +3419,7 @@ app.get('/tickets/:id/agent-runs', (req, res) => {
3384
3419
  }
3385
3420
  return res.json({ runs: listAgentRunsForParent('ticket', ticket.id) });
3386
3421
  });
3387
- app.get('/tickets/:id/diff', (req, res) => {
3422
+ app.get('/tickets/:id/diff', async (req, res) => {
3388
3423
  const ticket = getTicketRouteContext(req.params.id);
3389
3424
  if (!ticket) {
3390
3425
  return res.status(404).json({ error: 'Not found' });
@@ -3397,7 +3432,7 @@ app.get('/tickets/:id/diff', (req, res) => {
3397
3432
  const { status, error } = workspace;
3398
3433
  return res.status(status).json({ error });
3399
3434
  }
3400
- const diffData = getGitDiffData(workspace.cwd);
3435
+ const diffData = await getGitDiffDataAsync(workspace.cwd);
3401
3436
  return res.json({
3402
3437
  stats: summarizeTicketDiffFiles(diffData.files),
3403
3438
  files: diffData.files,
@@ -3418,7 +3453,7 @@ app.get('/tickets/:id/committed-diff', (req, res) => {
3418
3453
  }
3419
3454
  return sendUnpushedCommitDiff(res, workspace, getCommitHashQuery(req));
3420
3455
  });
3421
- app.get('/tickets/:id/git-status', (req, res) => {
3456
+ app.get('/tickets/:id/git-status', async (req, res) => {
3422
3457
  const ticket = getTicketRouteContext(req.params.id);
3423
3458
  if (!ticket) {
3424
3459
  return res.status(404).json({ error: 'Not found' });
@@ -3431,9 +3466,9 @@ app.get('/tickets/:id/git-status', (req, res) => {
3431
3466
  return res.status(workspace.status).json({ error: workspace.error });
3432
3467
  }
3433
3468
  const refreshRemote = req.query.refresh_remote === 'true';
3434
- return res.json(getGitStatus(workspace.cwd, workspace.branch, workspace.project, { refreshRemote }));
3469
+ return res.json(await getGitStatusAsync(workspace.cwd, workspace.branch, workspace.project, { refreshRemote }));
3435
3470
  });
3436
- app.get('/tickets/:id/git-commits', (req, res) => {
3471
+ app.get('/tickets/:id/git-commits', async (req, res) => {
3437
3472
  const ticket = getTicketRouteContext(req.params.id);
3438
3473
  if (!ticket) {
3439
3474
  return res.status(404).json({ error: 'Not found' });
@@ -3445,7 +3480,7 @@ app.get('/tickets/:id/git-commits', (req, res) => {
3445
3480
  if ('error' in workspace) {
3446
3481
  return res.status(workspace.status).json({ error: workspace.error });
3447
3482
  }
3448
- const summary = getUnpushedCommitSummaryForCwd(workspace.cwd, workspace.branch, workspace.project);
3483
+ const summary = await getUnpushedCommitSummaryForCwdAsync(workspace.cwd, workspace.branch, workspace.project);
3449
3484
  return res.json({ commits: summary.commits, total_count: summary.totalCount });
3450
3485
  });
3451
3486
  app.get('/bundles', async (req, res) => {
@@ -3465,7 +3500,7 @@ app.get('/bundles', async (req, res) => {
3465
3500
  timing.mark('serialize_bundles');
3466
3501
  timing.end({ count: serializedBundles.length });
3467
3502
  res.json(serializedBundles);
3468
- startPassiveGitHubWork('project-bundle-pr-sync', () => {
3503
+ startPassiveGitHubWork(res, 'project-bundle-pr-sync', () => {
3469
3504
  startProjectBundlePullRequestSyncIfNeeded(result.project, bundles);
3470
3505
  });
3471
3506
  });
@@ -3493,16 +3528,16 @@ app.get('/bundles/:id/conversation', (req, res) => {
3493
3528
  }
3494
3529
  const payload = serializeBundleConversationDetails(result.project, bundle);
3495
3530
  res.json(payload);
3496
- startPassiveGitHubWork('bundle-conversation-pr-discovery', () => {
3531
+ startPassiveGitHubWork(res, 'bundle-conversation-pr-discovery', () => {
3497
3532
  startBundlePullRequestDiscoveryIfNeeded(result.project, bundle);
3498
3533
  });
3499
3534
  });
3500
- app.get('/bundles/:id/review-findings', (req, res) => {
3535
+ app.get('/bundles/:id/review-findings', async (req, res) => {
3501
3536
  const result = getRequiredProject(req);
3502
3537
  if ('error' in result) {
3503
3538
  return res.status(400).json({ error: result.error });
3504
3539
  }
3505
- const response = getBundleReviewFindings(result.project.id, req.params.id);
3540
+ const response = await getBundleReviewFindings(result.project.id, req.params.id);
3506
3541
  if (!response) {
3507
3542
  return res.status(404).json({ error: 'Bundle not found' });
3508
3543
  }
@@ -5933,7 +5968,7 @@ app.post('/projects', (req, res) => {
5933
5968
  return res.status(400).json({ error: validation.error });
5934
5969
  }
5935
5970
  const projectCount = Number(db.prepare('SELECT COUNT(*) AS count FROM projects').get()?.count ?? 0);
5936
- 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, 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;
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;
5937
5972
  if (!repo_path) {
5938
5973
  return res.status(400).json({ error: 'repo_path must be a non-empty string' });
5939
5974
  }
@@ -5957,6 +5992,7 @@ app.post('/projects', (req, res) => {
5957
5992
  required_check_definition_ids,
5958
5993
  pre_review_check_definition_ids,
5959
5994
  post_build_check_definition_ids,
5995
+ auto_fix_check_definition_ids,
5960
5996
  test_commands,
5961
5997
  run_ide,
5962
5998
  preview_service_name,
@@ -5978,8 +6014,8 @@ app.post('/projects', (req, res) => {
5978
6014
  automation_review_severity,
5979
6015
  automation_review_max_iterations
5980
6016
  )
5981
- VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
5982
- `).run(id, name, normalizedRepoPath, run_setup, run_services, check_definitions, required_check_definition_ids ?? '[]', pre_review_check_definition_ids ?? '[]', post_build_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);
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);
5983
6019
  replaceProjectLinks(id, linked_project_ids ?? []);
5984
6020
  ensureProjectRootBundle(id);
5985
6021
  if (projectCount === 0) {
@@ -6873,7 +6909,7 @@ app.post('/projects/:id/git-abort', async (req, res) => {
6873
6909
  return res.status(500).json({ error: 'Unable to determine project branch' });
6874
6910
  }
6875
6911
  });
6876
- app.get('/projects/:id/diff', (req, res) => {
6912
+ app.get('/projects/:id/diff', async (req, res) => {
6877
6913
  const project = getProjectById(req.params.id);
6878
6914
  if (!project) {
6879
6915
  return res.status(404).json({ error: 'Not found' });
@@ -6882,7 +6918,7 @@ app.get('/projects/:id/diff', (req, res) => {
6882
6918
  if ('error' in workspace) {
6883
6919
  return res.status(workspace.status).json({ error: workspace.error });
6884
6920
  }
6885
- const diffData = getGitDiffData(workspace.cwd);
6921
+ const diffData = await getGitDiffDataAsync(workspace.cwd);
6886
6922
  return res.json({
6887
6923
  stats: summarizeTicketDiffFiles(diffData.files),
6888
6924
  files: diffData.files,
@@ -6900,7 +6936,7 @@ app.get('/projects/:id/committed-diff', (req, res) => {
6900
6936
  }
6901
6937
  return sendUnpushedCommitDiff(res, workspace, getCommitHashQuery(req));
6902
6938
  });
6903
- app.get('/projects/:id/git-status', (req, res) => {
6939
+ app.get('/projects/:id/git-status', async (req, res) => {
6904
6940
  const project = getProjectById(req.params.id);
6905
6941
  if (!project) {
6906
6942
  return res.status(404).json({ error: 'Not found' });
@@ -6910,9 +6946,9 @@ app.get('/projects/:id/git-status', (req, res) => {
6910
6946
  return res.status(workspace.status).json({ error: workspace.error });
6911
6947
  }
6912
6948
  const refreshRemote = req.query.refresh_remote === 'true';
6913
- return res.json(getGitStatus(workspace.cwd, workspace.branch, workspace.project, { refreshRemote }));
6949
+ return res.json(await getGitStatusAsync(workspace.cwd, workspace.branch, workspace.project, { refreshRemote }));
6914
6950
  });
6915
- app.get('/projects/:id/git-commits', (req, res) => {
6951
+ app.get('/projects/:id/git-commits', async (req, res) => {
6916
6952
  const project = getProjectById(req.params.id);
6917
6953
  if (!project) {
6918
6954
  return res.status(404).json({ error: 'Not found' });
@@ -6921,7 +6957,7 @@ app.get('/projects/:id/git-commits', (req, res) => {
6921
6957
  if ('error' in workspace) {
6922
6958
  return res.status(workspace.status).json({ error: workspace.error });
6923
6959
  }
6924
- const summary = getUnpushedCommitSummaryForCwd(workspace.cwd, workspace.branch, workspace.project);
6960
+ const summary = await getUnpushedCommitSummaryForCwdAsync(workspace.cwd, workspace.branch, workspace.project);
6925
6961
  return res.json({ commits: summary.commits, total_count: summary.totalCount });
6926
6962
  });
6927
6963
  app.post('/projects/:id/git-commit', async (req, res) => {
@@ -7186,7 +7222,7 @@ app.patch('/projects/:id', (req, res) => {
7186
7222
  });
7187
7223
  }
7188
7224
  }
7189
- 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, 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;
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;
7190
7226
  const updateProject = db.prepare(`
7191
7227
  UPDATE projects SET
7192
7228
  name = ?,
@@ -7197,6 +7233,7 @@ app.patch('/projects/:id', (req, res) => {
7197
7233
  required_check_definition_ids = ?,
7198
7234
  pre_review_check_definition_ids = ?,
7199
7235
  post_build_check_definition_ids = ?,
7236
+ auto_fix_check_definition_ids = ?,
7200
7237
  test_commands = ?,
7201
7238
  run_ide = ?,
7202
7239
  preview_service_name = ?,
@@ -7230,6 +7267,9 @@ app.patch('/projects/:id', (req, res) => {
7230
7267
  const nextPostBuildCheckDefinitionIds = hasOwn(validation.values, 'post_build_check_definition_ids')
7231
7268
  ? post_build_check_definition_ids ?? '[]'
7232
7269
  : project.post_build_check_definition_ids ?? '[]';
7270
+ const nextAutoFixCheckDefinitionIds = hasOwn(validation.values, 'auto_fix_check_definition_ids')
7271
+ ? auto_fix_check_definition_ids ?? '[]'
7272
+ : project.auto_fix_check_definition_ids;
7233
7273
  const updateResult = db.transaction(() => {
7234
7274
  const policyReferences = validateProjectRequiredCheckPolicyReferences({
7235
7275
  projectId: project.id,
@@ -7237,11 +7277,12 @@ app.patch('/projects/:id', (req, res) => {
7237
7277
  requiredCheckDefinitionIdsJson: nextRequiredCheckDefinitionIds,
7238
7278
  preReviewCheckDefinitionIdsJson: nextPreReviewCheckDefinitionIds,
7239
7279
  postBuildCheckDefinitionIdsJson: nextPostBuildCheckDefinitionIds,
7280
+ autoFixCheckDefinitionIdsJson: nextAutoFixCheckDefinitionIds,
7240
7281
  });
7241
7282
  if ('error' in policyReferences) {
7242
7283
  return policyReferences;
7243
7284
  }
7244
- 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, 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);
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);
7245
7286
  if (hasOwn(validation.values, 'linked_project_ids')) {
7246
7287
  replaceProjectLinks(project.id, linked_project_ids ?? []);
7247
7288
  }
@@ -7278,6 +7319,13 @@ const assertProjectDeletionEligible = (projectId, claimId) => {
7278
7319
  if (hasActiveProjectCheckBatch(projectId)) {
7279
7320
  throw new ProjectDeletionError(409, 'Cannot delete a project while checks are active');
7280
7321
  }
7322
+ if (db.prepare("SELECT 1 FROM sqlite_master WHERE type = 'table' AND name = 'check_auto_fix_loops'").get() && db.prepare(`
7323
+ SELECT 1 FROM check_auto_fix_loops loop
7324
+ JOIN execution_runs run ON run.id = loop.execution_run_id
7325
+ WHERE run.project_id = ? AND loop.terminal_reason IS NULL LIMIT 1
7326
+ `).get(projectId)) {
7327
+ throw new ProjectDeletionError(409, 'Cannot delete a project while automatic check repair is active');
7328
+ }
7281
7329
  if (!claimId && hasActiveProjectRepositoryGraphScan(projectId)) {
7282
7330
  throw new ProjectDeletionError(409, 'Cannot delete a project while a repository graph scan is active');
7283
7331
  }
@@ -7311,6 +7359,12 @@ const completeClaimedProjectDeletion = async (projectId, claimId) => {
7311
7359
  WHERE evaluation_id IN (SELECT id FROM check_gate_evaluations WHERE project_id = ?)
7312
7360
  `).run(projectId);
7313
7361
  db.prepare('DELETE FROM check_gate_evaluations WHERE project_id = ?').run(projectId);
7362
+ if (db.prepare("SELECT 1 FROM sqlite_master WHERE type = 'table' AND name = 'check_auto_fix_loops'").get()) {
7363
+ db.prepare(`
7364
+ DELETE FROM check_auto_fix_loops
7365
+ WHERE execution_run_id IN (SELECT id FROM execution_runs WHERE project_id = ?)
7366
+ `).run(projectId);
7367
+ }
7314
7368
  if (db.prepare("SELECT 1 FROM sqlite_master WHERE type = 'table' AND name = 'check_repair_details'").get()) {
7315
7369
  db.prepare(`
7316
7370
  DELETE FROM check_repair_details
@@ -8361,6 +8415,9 @@ app.post('/projects/:id/check-repairs/:repairRunId/stop', async (req, res) => {
8361
8415
  return res.status(404).json({ error: 'Not found' });
8362
8416
  }
8363
8417
  try {
8418
+ if (getCheckAutoFixDetails(req.params.id, req.params.repairRunId)) {
8419
+ return res.json(await stopCheckAutoFix(req.params.id, req.params.repairRunId, io));
8420
+ }
8364
8421
  return res.json(await stopCheckRepair(req.params.id, req.params.repairRunId, io));
8365
8422
  }
8366
8423
  catch (error) {
@@ -8499,6 +8556,7 @@ app.get('/projects/:id/check-batches/:batchRunId/diagnostics', async (req, res)
8499
8556
  ...diagnostics,
8500
8557
  repair: await getCheckRepairCandidateState(project.id, req.params.batchRunId),
8501
8558
  latest_repair: getLatestCheckRepairForBatch(project.id, req.params.batchRunId),
8559
+ auto_fix: getCheckAutoFixDetails(project.id, req.params.batchRunId),
8502
8560
  });
8503
8561
  });
8504
8562
  app.get('/projects/:id/check-attempts/:attemptRunId/diagnostics', (req, res) => {
@@ -8936,6 +8994,7 @@ app.post('/tickets/:id/stop-build', async (req, res) => {
8936
8994
  const result = await stopBuildTicketRun({
8937
8995
  ticketId: req.params.id,
8938
8996
  requestedProjectId: getRequestedProjectId(req),
8997
+ broadcaster: io,
8939
8998
  });
8940
8999
  if (!result.ok) {
8941
9000
  return res.status(result.status).json({ error: result.error });