@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
@@ -0,0 +1,83 @@
1
+ import db from '../db.js';
2
+ const MAX_ATTEMPTS = 3;
3
+ const TERMINAL_STATUSES = new Set(['completed', 'failed', 'cancelled', 'interrupted']);
4
+ export const getCheckAutoFixDetails = (projectId, runOrBatchId) => {
5
+ const tablesAvailable = db.prepare(`
6
+ SELECT COUNT(*) AS count FROM sqlite_master
7
+ WHERE type = 'table' AND name IN ('check_auto_fix_loops', 'check_auto_fix_attempts', 'lifecycle_events')
8
+ `).get();
9
+ if (tablesAvailable.count !== 3) {
10
+ return null;
11
+ }
12
+ const loop = db.prepare(`
13
+ SELECT loop.*, run.status AS execution_status FROM check_auto_fix_loops loop
14
+ JOIN execution_runs run ON run.id = loop.execution_run_id
15
+ WHERE run.project_id = ? AND (
16
+ loop.execution_run_id = ? OR loop.originating_batch_run_id = ? OR loop.final_batch_run_id = ?
17
+ OR EXISTS (
18
+ SELECT 1 FROM check_auto_fix_attempts attempt
19
+ WHERE attempt.loop_run_id = loop.execution_run_id
20
+ AND (attempt.source_batch_run_id = ? OR attempt.rerun_batch_run_id = ?)
21
+ )
22
+ )
23
+ ORDER BY loop.created_at DESC LIMIT 1
24
+ `).get(projectId, runOrBatchId, runOrBatchId, runOrBatchId, runOrBatchId, runOrBatchId);
25
+ if (!loop) {
26
+ return null;
27
+ }
28
+ const rows = db.prepare(`
29
+ SELECT attempt.ordinal, attempt.source_batch_run_id, attempt.child_run_id,
30
+ attempt.launch_outcome, attempt.rerun_batch_run_id, attempt.terminal_reason,
31
+ attempt.terminal_message, attempt.created_at, attempt.updated_at,
32
+ EXISTS (
33
+ SELECT 1 FROM lifecycle_events event
34
+ WHERE event.execution_run_id = attempt.loop_run_id
35
+ AND event.event_type = 'check_auto_fix_fallback'
36
+ AND json_extract(event.metadata_json, '$.attempt') = attempt.ordinal
37
+ ) AS fallback_used,
38
+ child.status AS child_status, rerun.status AS rerun_status
39
+ FROM check_auto_fix_attempts attempt
40
+ LEFT JOIN execution_runs child ON child.id = attempt.child_run_id
41
+ LEFT JOIN execution_runs rerun ON rerun.id = attempt.rerun_batch_run_id
42
+ WHERE attempt.loop_run_id = ? ORDER BY attempt.ordinal
43
+ `).all(loop.execution_run_id);
44
+ const active = rows[rows.length - 1];
45
+ const phase = loop.terminal_reason
46
+ ? 'terminal'
47
+ : loop.cancellation_requested
48
+ ? 'stopping'
49
+ : active?.rerun_batch_run_id && active.rerun_status && !TERMINAL_STATUSES.has(active.rerun_status)
50
+ ? 'rerunning'
51
+ : active?.child_run_id && active.child_status && !TERMINAL_STATUSES.has(active.child_status)
52
+ ? 'repairing'
53
+ : 'dispatching';
54
+ return {
55
+ execution_run_id: loop.execution_run_id,
56
+ execution_status: loop.execution_status,
57
+ phase,
58
+ originating_batch_run_id: loop.originating_batch_run_id,
59
+ final_batch_run_id: loop.final_batch_run_id ?? loop.originating_batch_run_id,
60
+ owner_type: loop.owner_type,
61
+ owner_id: loop.owner_id,
62
+ causal_execution_run_id: loop.causal_execution_run_id,
63
+ causal_agent_run_id: loop.causal_agent_run_id,
64
+ attempt_count: loop.attempt_count,
65
+ max_attempts: MAX_ATTEMPTS,
66
+ cancellation_requested: loop.cancellation_requested === 1,
67
+ terminal_reason: loop.terminal_reason,
68
+ terminal_message: loop.terminal_message,
69
+ attempts: rows.map(row => ({
70
+ ordinal: row.ordinal,
71
+ source_batch_run_id: row.source_batch_run_id,
72
+ child_run_id: row.child_run_id,
73
+ continuation: row.launch_outcome === 'continued' || row.launch_outcome === 'fresh' ? row.launch_outcome : null,
74
+ fallback_used: row.fallback_used === 1,
75
+ rerun_batch_run_id: row.rerun_batch_run_id,
76
+ terminal_reason: row.terminal_reason,
77
+ terminal_message: row.terminal_message,
78
+ created_at: row.created_at,
79
+ updated_at: row.updated_at,
80
+ })),
81
+ };
82
+ };
83
+ //# sourceMappingURL=checkAutoFixDetails.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"checkAutoFixDetails.js","sourceRoot":"","sources":["../../../server/lib/checkAutoFixDetails.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,59 @@
1
+ import { createHash } from 'crypto';
2
+ import { getCheckDefinitionFingerprint } from './checkDefinitions.js';
3
+ import { parseRequiredCheckDefinitionIds } from './requiredCheckPolicy.js';
4
+ const updateLengthDelimited = (hash, value) => {
5
+ const buffer = Buffer.from(value, 'utf8');
6
+ const length = Buffer.alloc(8);
7
+ length.writeBigUInt64BE(BigInt(buffer.length));
8
+ hash.update(length).update(buffer);
9
+ };
10
+ const compareDefinitionIds = (left, right) => (Buffer.compare(Buffer.from(left.id, 'utf8'), Buffer.from(right.id, 'utf8')));
11
+ const snapshotDefinition = (definition) => ({
12
+ id: definition.id,
13
+ name: definition.name,
14
+ category: definition.category,
15
+ command: definition.command,
16
+ ...(definition.cwd ? { cwd: definition.cwd } : {}),
17
+ timeout_ms: definition.timeout_ms,
18
+ ...(definition.category === 'test' ? { runner: definition.runner } : {}),
19
+ });
20
+ export const getCheckAutoFixPolicyFingerprint = (definitions) => {
21
+ const hash = createHash('sha256');
22
+ updateLengthDelimited(hash, 'archon-check-auto-fix-policy-v1');
23
+ for (const definition of [...definitions].sort(compareDefinitionIds)) {
24
+ updateLengthDelimited(hash, definition.id);
25
+ updateLengthDelimited(hash, getCheckDefinitionFingerprint(definition));
26
+ }
27
+ return hash.digest('hex');
28
+ };
29
+ export const createCheckAutoFixPolicySnapshot = (project, selectedDefinitionSnapshots) => {
30
+ const membership = parseRequiredCheckDefinitionIds(project.auto_fix_check_definition_ids, 'auto_fix_check_definition_ids');
31
+ if ('error' in membership) {
32
+ return { status: 'invalid', error: membership.error };
33
+ }
34
+ const membershipSet = new Set(membership.value);
35
+ const definitions = selectedDefinitionSnapshots
36
+ .filter(definition => membershipSet.has(definition.id))
37
+ .map(snapshotDefinition)
38
+ .sort(compareDefinitionIds);
39
+ return {
40
+ status: 'valid',
41
+ snapshot: {
42
+ definitionIds: definitions.map(definition => definition.id),
43
+ definitions,
44
+ fingerprint: getCheckAutoFixPolicyFingerprint(definitions),
45
+ },
46
+ };
47
+ };
48
+ export const doCurrentDefinitionsMatchCheckAutoFixPolicySnapshot = (snapshot, currentDefinitions) => {
49
+ if (snapshot.fingerprint !== getCheckAutoFixPolicyFingerprint(snapshot.definitions)) {
50
+ return false;
51
+ }
52
+ const currentDefinitionsById = new Map(currentDefinitions.map(definition => [definition.id, definition]));
53
+ return snapshot.definitions.every(definition => {
54
+ const currentDefinition = currentDefinitionsById.get(definition.id);
55
+ return currentDefinition !== undefined
56
+ && getCheckDefinitionFingerprint(currentDefinition) === getCheckDefinitionFingerprint(definition);
57
+ });
58
+ };
59
+ //# sourceMappingURL=checkAutoFixPolicy.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"checkAutoFixPolicy.js","sourceRoot":"","sources":["../../../server/lib/checkAutoFixPolicy.ts"],"names":[],"mappings":"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"}
@@ -1,6 +1,7 @@
1
1
  import db from '../db.js';
2
2
  import { stopBuildAgent } from './agent.js';
3
3
  import { terminalizeAgentRunsForExecutionRun } from './agentRuns.js';
4
+ import { resolveCausalAgentRun } from './agentRuns.js';
4
5
  import { assertNoActiveAutomationChild } from './activeAutomationChild.js';
5
6
  import { getBundlePlanMutationBlockerById } from './bundleActivity.js';
6
7
  import { runAutomationReviewGateOrPause } from './automationReviewGate.js';
@@ -8,14 +9,17 @@ import { resolveBundleReviewOwner } from './bundleReviewOperations.js';
8
9
  import { resolveBuildTicketCommitCheckpointLineage } from './buildTicketCommit.js';
9
10
  import { getExecutionRun, withExecutionRunTransaction } from './executionRuns.js';
10
11
  import { getCheckDefinitionFingerprint } from './checkDefinitions.js';
11
- import { findActiveCheckBatchForTarget, getCheckBatchDetails } from './checkRuns.js';
12
+ import { findActiveCheckAutoFixForTarget, findActiveCheckBatchForTarget, getCheckBatchDetails } from './checkRuns.js';
12
13
  import { startCheckBatch, stopCheckBatch, waitForCheckBatch } from './checkRunner.js';
13
14
  import { finalizeCheckRepair, finalizeCheckRepairInTransaction } from './checkRepairLifecycle.js';
14
15
  import { captureCheckWorkspaceIdentity } from './checkWorkspaceIdentity.js';
15
16
  import { resolveWorktreePath } from './git.js';
16
17
  import { getProjectById, getProjectCheckDefinitions } from './projects.js';
17
18
  import { getRequiredCheckPolicyFingerprint } from './requiredCheckPolicy.js';
18
- import { submitTicketFollowUp } from './ticketFollowUpOperations.js';
19
+ import { dispatchCheckRepair } from './checkRepairDispatch.js';
20
+ import { getChatSession } from './chats.js';
21
+ import { stopChatAgent } from './agent.js';
22
+ import { revokeAgentSpawnPermit } from './agentSpawnPermits.js';
19
23
  import { getBundleAutomationState, resolveAutomationConfig } from './ticketAutomation.js';
20
24
  import { continueAfterBuildCheckpoint } from './automationBuildContinuation.js';
21
25
  import { getAutomationProgression, runAutomationProgression, waitAutomationProgression, waitAutomationProgressionInTransaction, } from './automationProgression.js';
@@ -335,6 +339,70 @@ const resolveOwnerTicket = (projectId, batch, requestedTicketId, progressionRunI
335
339
  }
336
340
  return eligible[0];
337
341
  };
342
+ const resolveRepairOwner = (projectId, batch, sourceRunId, requestedTicketId, progressionRunId) => {
343
+ const primary = db.prepare(`
344
+ SELECT entity_type, entity_id
345
+ FROM execution_run_links
346
+ WHERE execution_run_id = ? AND project_id = ? AND relationship = 'primary'
347
+ AND entity_type IN ('ticket', 'chat_session')
348
+ `).get(sourceRunId, projectId);
349
+ if (primary?.entity_type === 'chat_session') {
350
+ if (requestedTicketId || progressionRunId) {
351
+ throw new CheckRepairError(409, 'Chat Build repair ownership conflicts with Ticket automation');
352
+ }
353
+ const session = getChatSession(primary.entity_id);
354
+ if (!session
355
+ || session.project_id !== projectId
356
+ || session.mode !== 'build'
357
+ || session.target_kind !== batch.target_kind
358
+ || session.target_bundle_id !== batch.target_bundle_id) {
359
+ throw new CheckRepairError(409, 'The causal Chat Build owner is stale or unavailable');
360
+ }
361
+ return { ownerType: 'chat_session', ownerId: session.id, ticket: null, description: session.title };
362
+ }
363
+ const ticket = resolveOwnerTicket(projectId, batch, requestedTicketId ?? (primary?.entity_type === 'ticket' ? primary.entity_id : null), progressionRunId);
364
+ if (primary?.entity_type === 'ticket' && primary.entity_id !== ticket.id) {
365
+ throw new CheckRepairError(409, 'Requested Ticket does not own the causal check batch');
366
+ }
367
+ return {
368
+ ownerType: 'ticket',
369
+ ownerId: ticket.id,
370
+ ticket,
371
+ description: ticket.description || ticket.title,
372
+ };
373
+ };
374
+ const resolveCausalExecution = (projectId, sourceRunId, ownerType, ownerId) => {
375
+ const source = getExecutionRun(projectId, sourceRunId);
376
+ const direct = source?.parent_run_id ? getExecutionRun(projectId, source.parent_run_id) : null;
377
+ const expectedKinds = ownerType === 'ticket' ? ['build', 'build_follow_up'] : ['chat_turn'];
378
+ const directOwner = direct ? db.prepare(`
379
+ SELECT 1 FROM execution_run_links
380
+ WHERE execution_run_id = ? AND project_id = ? AND relationship = 'primary'
381
+ AND entity_type = ? AND entity_id = ?
382
+ `).get(direct.id, projectId, ownerType, ownerId) : null;
383
+ if (direct && expectedKinds.includes(direct.kind) && directOwner) {
384
+ return direct;
385
+ }
386
+ if (ownerType === 'chat_session') {
387
+ throw new CheckRepairError(409, 'The causal Chat Build execution is unavailable');
388
+ }
389
+ const row = db.prepare(`
390
+ SELECT run.id
391
+ FROM execution_runs run
392
+ JOIN execution_run_links link ON link.execution_run_id = run.id
393
+ AND link.project_id = run.project_id AND link.relationship = 'primary'
394
+ AND link.entity_type = 'ticket' AND link.entity_id = ?
395
+ WHERE run.project_id = ? AND run.kind IN ('build', 'build_follow_up')
396
+ AND run.status = 'completed'
397
+ AND EXISTS (SELECT 1 FROM agent_runs agent WHERE agent.execution_run_id = run.id)
398
+ ORDER BY run.created_at DESC, run.id DESC LIMIT 1
399
+ `).get(ownerId, projectId);
400
+ const causal = row ? getExecutionRun(projectId, row.id) : null;
401
+ if (!causal) {
402
+ throw new CheckRepairError(409, 'The causal Ticket Build execution is unavailable');
403
+ }
404
+ return causal;
405
+ };
338
406
  const toRepairDestination = (purpose) => {
339
407
  if (purpose === 'automation_review') {
340
408
  return 'pre_review';
@@ -350,6 +418,12 @@ const toRepairDestination = (purpose) => {
350
418
  }
351
419
  return purpose === null ? 'manual' : 'unknown';
352
420
  };
421
+ const assertNoActiveCheckAutoFixForTarget = (projectId, targetKind, targetBundleId) => {
422
+ const active = findActiveCheckAutoFixForTarget(projectId, targetKind, targetBundleId);
423
+ if (active) {
424
+ throw new CheckRepairError(409, `Check target is busy with active auto-fix ${active}`);
425
+ }
426
+ };
353
427
  export const getCheckRepairCandidateState = async (projectId, batchRunId) => {
354
428
  const project = getProjectById(projectId);
355
429
  const batch = project ? getCheckBatchDetails(projectId, batchRunId) : null;
@@ -357,6 +431,7 @@ export const getCheckRepairCandidateState = async (projectId, batchRunId) => {
357
431
  const purpose = batch?.automation_boundary_purpose ?? null;
358
432
  const base = {
359
433
  candidate_tickets: [],
434
+ candidate_chat_sessions: [],
360
435
  accepts_ticket_id: false,
361
436
  destination: toRepairDestination(purpose),
362
437
  eligible_attempt_run_ids: [],
@@ -431,6 +506,7 @@ export const getCheckRepairCandidateState = async (projectId, batchRunId) => {
431
506
  return { ...base, eligibility: { eligible: false, reason: 'workspace_changed' } };
432
507
  }
433
508
  if (findActiveCheckBatchForTarget(projectId, batch.target_kind, batch.target_bundle_id)
509
+ || findActiveCheckAutoFixForTarget(projectId, batch.target_kind, batch.target_bundle_id)
434
510
  || db.prepare(`
435
511
  SELECT 1 FROM execution_runs repair
436
512
  JOIN check_repair_details details ON details.execution_run_id = repair.id
@@ -443,6 +519,27 @@ export const getCheckRepairCandidateState = async (projectId, batchRunId) => {
443
519
  return { ...base, eligibility: { eligible: false, reason: 'busy' } };
444
520
  }
445
521
  const progressionRunId = sourceRun.initiated_by === 'automation' ? sourceRun.parent_run_id : null;
522
+ const primaryOwner = db.prepare(`
523
+ SELECT entity_type, entity_id FROM execution_run_links
524
+ WHERE execution_run_id = ? AND project_id = ? AND relationship = 'primary'
525
+ `).get(batchRunId, projectId);
526
+ if (primaryOwner?.entity_type === 'chat_session') {
527
+ const session = getChatSession(primaryOwner.entity_id);
528
+ if (!session
529
+ || session.project_id !== projectId
530
+ || session.mode !== 'build'
531
+ || session.target_kind !== batch.target_kind
532
+ || session.target_bundle_id !== batch.target_bundle_id) {
533
+ return { ...base, eligibility: { eligible: false, reason: 'non_repairable' } };
534
+ }
535
+ return {
536
+ ...base,
537
+ eligibility: { eligible: true, reason: null },
538
+ candidate_chat_sessions: [{ id: session.id, title: session.title }],
539
+ eligible_attempt_run_ids: currentStructuredEvidence.map(row => row.execution_run_id),
540
+ eligible_raw_output_attempt_run_ids: currentRawOutputEvidence.map(row => row.execution_run_id),
541
+ };
542
+ }
446
543
  let candidates;
447
544
  if (progressionRunId) {
448
545
  const ticketIds = db.prepare(`
@@ -464,13 +561,14 @@ export const getCheckRepairCandidateState = async (projectId, batchRunId) => {
464
561
  return {
465
562
  eligibility: { eligible: true, reason: null },
466
563
  candidate_tickets: candidateTickets,
564
+ candidate_chat_sessions: [],
467
565
  accepts_ticket_id: !progressionRunId,
468
566
  destination: toRepairDestination(purpose),
469
567
  eligible_attempt_run_ids: currentStructuredEvidence.map(row => row.execution_run_id),
470
568
  eligible_raw_output_attempt_run_ids: currentRawOutputEvidence.map(row => row.execution_run_id),
471
569
  };
472
570
  };
473
- const formatRepairInstruction = (ticket, diagnosticEvidence, rawOutputEvidence) => {
571
+ const formatRepairInstruction = (ownerDescription, diagnosticEvidence, rawOutputEvidence) => {
474
572
  const diagnostics = diagnosticEvidence.map(row => {
475
573
  const location = row.file_path ? `${row.file_path}${row.start_line ? `:${row.start_line}` : ''}` : 'unknown location';
476
574
  return `- [${escapePromptEvidence(row.definition_id)}] ${escapePromptEvidence(location)}: ${escapePromptEvidence(row.message.slice(0, MAX_PROMPT_DIAGNOSTIC_CHARS))}${row.code ? ` (${escapePromptEvidence(row.code)})` : ''}`;
@@ -484,11 +582,11 @@ const formatRepairInstruction = (ticket, diagnosticEvidence, rawOutputEvidence)
484
582
  return `<check_output attempt_id="${escapePromptEvidence(row.attempt_run_id)}" evidence="${rawOnly ? 'raw_only' : 'diagnostic'}" truncated="${truncated}">\n${escapePromptEvidence(row.retained_output.slice(-MAX_PROMPT_OUTPUT_CHARS))}\n</check_output>`;
485
583
  })
486
584
  .join('\n\n');
487
- return `You are repairing persisted command failures for an existing ticket in its current worktree.
585
+ return `You are repairing persisted command failures for an existing Build owner in its resolved workspace.
488
586
 
489
- <ticket>
490
- ${escapePromptEvidence(ticket.description || ticket.title)}
491
- </ticket>
587
+ <build_owner>
588
+ ${escapePromptEvidence(ownerDescription)}
589
+ </build_owner>
492
590
 
493
591
  <check_diagnostics>
494
592
  ${diagnostics}
@@ -618,7 +716,9 @@ const completeRepairFollowUp = async (projectId, repairRunId, io) => {
618
716
  targetLabel: sourceBatch.target_label,
619
717
  selectedDefinitions: selected,
620
718
  availableDefinitions: currentDefinitions,
621
- sourceReference: { kind: 'ticket', id: details.ticket_id },
719
+ sourceReference: details.owner_type === 'ticket'
720
+ ? { kind: 'ticket', id: details.owner_id }
721
+ : { kind: 'chat_session', id: details.owner_id },
622
722
  rerunOfBatchRunId: sourceBatch.execution_run_id,
623
723
  rerunAttemptRunIds,
624
724
  automationParentRunId: details.automation_progression_run_id,
@@ -668,7 +768,7 @@ const completeRepairFollowUp = async (projectId, repairRunId, io) => {
668
768
  });
669
769
  return;
670
770
  }
671
- const ticket = getTicket(details.ticket_id);
771
+ const ticket = details.ticket_id ? getTicket(details.ticket_id) : null;
672
772
  const bundle = getBundle(progressionBundleId, projectId);
673
773
  if (!ticket || !bundle || getAutomationProgression(projectId, bundle.id)?.id !== details.automation_progression_run_id) {
674
774
  throw new Error('Automation ownership changed before repaired checks completed');
@@ -773,7 +873,8 @@ const revalidateBeforeAgentStart = async (projectId, repairRunId, childRunId) =>
773
873
  if (activeBatch) {
774
874
  throw new Error(`Check target became busy before the repair agent could start (${activeBatch})`);
775
875
  }
776
- if (batch.target_bundle_id && getTargetMutationBlocker(projectId, batch.target_bundle_id, details.ticket_id)) {
876
+ assertNoActiveCheckAutoFixForTarget(projectId, batch.target_kind, batch.target_bundle_id);
877
+ if (batch.target_bundle_id && getTargetMutationBlocker(projectId, batch.target_bundle_id, details.ticket_id ?? undefined)) {
777
878
  throw new Error('Check target became busy with another worktree-mutating agent');
778
879
  }
779
880
  if (details.automation_progression_run_id) {
@@ -840,6 +941,7 @@ export const startCheckRepair = async (input) => {
840
941
  if (activeBatch) {
841
942
  throw new CheckRepairError(409, `Check target is busy with active batch ${activeBatch}`);
842
943
  }
944
+ assertNoActiveCheckAutoFixForTarget(project.id, sourceBatch.target_kind, sourceBatch.target_bundle_id);
843
945
  assertNoActiveCheckRepairForTarget(project.id, sourceBatch.target_kind, sourceBatch.target_bundle_id);
844
946
  const progressionRunId = sourceRun.initiated_by === 'automation' ? sourceRun.parent_run_id : null;
845
947
  const boundaryPurpose = progressionRunId ? sourceBatch.automation_boundary_purpose : null;
@@ -886,16 +988,19 @@ export const startCheckRepair = async (input) => {
886
988
  targetBundleId: sourceBatch.target_bundle_id,
887
989
  }, boundaryPurpose)
888
990
  : null;
889
- const ticket = resolveOwnerTicket(project.id, sourceBatch, input.ticketId ?? null, progressionRunId);
890
- const mutationBlocker = getTargetMutationBlocker(project.id, targetBundleId, ticket.id);
991
+ const owner = resolveRepairOwner(project.id, sourceBatch, sourceRun.id, input.ticketId ?? null, progressionRunId);
992
+ const causalExecution = resolveCausalExecution(project.id, sourceRun.id, owner.ownerType, owner.ownerId);
993
+ const causalAgentRun = resolveCausalAgentRun(causalExecution.id);
994
+ const mutationBlocker = getTargetMutationBlocker(project.id, targetBundleId, owner.ticket?.id);
891
995
  if (mutationBlocker) {
892
996
  throw new CheckRepairError(409, `Check target is busy with mutating ticket ${mutationBlocker}`);
893
997
  }
894
998
  const definitionIds = [...new Set(validated.evidence.map(row => row.definition_id))];
895
999
  let repairContext;
896
1000
  withExecutionRunTransaction(transaction => {
1001
+ assertNoActiveCheckAutoFixForTarget(project.id, sourceBatch.target_kind, sourceBatch.target_bundle_id);
897
1002
  assertNoActiveCheckRepairForTarget(project.id, sourceBatch.target_kind, sourceBatch.target_bundle_id);
898
- const transactionMutationBlocker = getTargetMutationBlocker(project.id, targetBundleId, ticket.id);
1003
+ const transactionMutationBlocker = getTargetMutationBlocker(project.id, targetBundleId, owner.ticket?.id);
899
1004
  if (transactionMutationBlocker) {
900
1005
  throw new CheckRepairError(409, `Check target is busy with mutating ticket ${transactionMutationBlocker}`);
901
1006
  }
@@ -908,9 +1013,11 @@ export const startCheckRepair = async (input) => {
908
1013
  initiatedBy: progressionRunId ? 'automation' : 'user',
909
1014
  parentRunId: progressionRunId,
910
1015
  retryOfRunId: input.retryOfRepairRunId ?? undefined,
911
- sourceReference: { kind: 'ticket', id: ticket.id, label: ticket.title },
912
- links: ticket.worktree_bundle_id
913
- ? [{ entityType: 'bundle', entityId: ticket.worktree_bundle_id, relationship: 'context' }]
1016
+ sourceReference: owner.ownerType === 'ticket'
1017
+ ? { kind: 'ticket', id: owner.ownerId, label: owner.ticket?.title }
1018
+ : { kind: 'chat_session', id: owner.ownerId, label: owner.description },
1019
+ links: sourceBatch.target_bundle_id
1020
+ ? [{ entityType: 'bundle', entityId: sourceBatch.target_bundle_id, relationship: 'context' }]
914
1021
  : [],
915
1022
  domainStatus: 'running',
916
1023
  eventType: input.retryOfRepairRunId ? 'check_repair_retry_started' : 'check_repair_created',
@@ -924,12 +1031,13 @@ export const startCheckRepair = async (input) => {
924
1031
  });
925
1032
  db.prepare(`
926
1033
  INSERT INTO check_repair_details (
927
- execution_run_id, source_batch_run_id, target_kind, target_bundle_id, ticket_id,
1034
+ execution_run_id, source_batch_run_id, target_kind, target_bundle_id,
1035
+ owner_type, owner_id, ticket_id, causal_execution_run_id, causal_agent_run_id,
928
1036
  automation_progression_run_id, automation_boundary_purpose, initial_workspace_identity_json,
929
1037
  configuration_fingerprint, effective_policy_fingerprint, definition_ids_json,
930
1038
  retry_of_check_repair_run_id
931
- ) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
932
- `).run(repair.id, sourceBatch.execution_run_id, sourceBatch.target_kind, sourceBatch.target_bundle_id, ticket.id, progressionRunId, boundaryPurpose, JSON.stringify(validated.finalIdentity), sourceBatch.configuration_fingerprint, effectivePolicyFingerprint, JSON.stringify(definitionIds), input.retryOfRepairRunId ?? null);
1039
+ ) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
1040
+ `).run(repair.id, sourceBatch.execution_run_id, sourceBatch.target_kind, sourceBatch.target_bundle_id, owner.ownerType, owner.ownerId, owner.ticket?.id ?? null, causalExecution.id, causalAgentRun.id, progressionRunId, boundaryPurpose, JSON.stringify(validated.finalIdentity), sourceBatch.configuration_fingerprint, effectivePolicyFingerprint, JSON.stringify(definitionIds), input.retryOfRepairRunId ?? null);
933
1041
  const insertProvenance = db.prepare(`
934
1042
  INSERT INTO check_repair_diagnostic_provenance (
935
1043
  check_repair_run_id, ordinal, diagnostic_id, attempt_run_id, definition_id
@@ -946,39 +1054,19 @@ export const startCheckRepair = async (input) => {
946
1054
  }, asBroadcaster(input.io));
947
1055
  const persistedDetails = getCheckRepairDetails(project.id, repairContext.runId);
948
1056
  const persistedEvidence = assertRepairEvidence(project, persistedDetails.diagnostic_ids, persistedDetails.raw_output_attempt_run_ids);
949
- const instruction = formatRepairInstruction(ticket, persistedEvidence.diagnosticEvidence, persistedEvidence.rawOutputEvidence);
950
- const scheduling = submitTicketFollowUp({
951
- ticketId: ticket.id,
952
- requestedProjectId: project.id,
953
- payload: undefined,
1057
+ const instruction = formatRepairInstruction(owner.description, persistedEvidence.diagnosticEvidence, persistedEvidence.rawOutputEvidence);
1058
+ const scheduling = dispatchCheckRepair({
1059
+ details: persistedDetails,
1060
+ instruction,
954
1061
  broadcaster: asBroadcaster(input.io),
955
- persistTriggerMessage: false,
956
- initiation: {
957
- initiator: progressionRunId ? 'automation' : 'user',
958
- causalParentRunId: repairContext.runId,
959
- },
960
- providerContinuation: 'fresh',
961
- trustedTrigger: {
962
- instruction,
963
- onExecutionCreated: context => {
964
- const updated = db.prepare(`
965
- UPDATE check_repair_details SET follow_up_run_id = ?, updated_at = CURRENT_TIMESTAMP
966
- WHERE execution_run_id = ? AND follow_up_run_id IS NULL
967
- `).run(context.runId, repairContext.runId);
968
- if (updated.changes !== 1) {
969
- throw new Error('Check repair follow-up ownership could not be persisted');
970
- }
1062
+ orchestration: {
1063
+ beforeStart: context => revalidateBeforeAgentStart(project.id, repairContext.runId, context.runId),
1064
+ onCompletion: () => completeRepairFollowUp(project.id, repairContext.runId, input.io),
1065
+ onCancellation: () => {
1066
+ failRepair(project.id, repairContext.runId, 'Check repair agent was stopped', 'cancelled', input.io);
971
1067
  },
972
- orchestration: {
973
- prompt: instruction,
974
- beforeStart: context => revalidateBeforeAgentStart(project.id, repairContext.runId, context.runId),
975
- onCompletion: () => completeRepairFollowUp(project.id, repairContext.runId, input.io),
976
- onCancellation: () => {
977
- failRepair(project.id, repairContext.runId, 'Check repair follow-up was stopped', 'cancelled', input.io);
978
- },
979
- onFailure: (_context, message) => {
980
- failRepair(project.id, repairContext.runId, message, 'failed', input.io);
981
- },
1068
+ onFailure: (_context, message) => {
1069
+ failRepair(project.id, repairContext.runId, message, 'failed', input.io);
982
1070
  },
983
1071
  },
984
1072
  });
@@ -1000,7 +1088,7 @@ export const retryCheckRepair = async (projectId, repairRunId, io) => {
1000
1088
  projectId,
1001
1089
  diagnosticIds: source.diagnostic_ids,
1002
1090
  rawOutputAttemptRunIds: source.raw_output_attempt_run_ids,
1003
- ticketId: source.automation_progression_run_id ? null : source.ticket_id,
1091
+ ticketId: source.automation_progression_run_id || source.owner_type === 'chat_session' ? null : source.ticket_id,
1004
1092
  io,
1005
1093
  retryOfRepairRunId: source.execution_run_id,
1006
1094
  });
@@ -1035,11 +1123,12 @@ export const stopCheckRepair = async (projectId, repairRunId, io) => {
1035
1123
  eventType: 'check_repair_follow_up_cancelled',
1036
1124
  });
1037
1125
  terminalizeAgentRunsForExecutionRun(followUp.id, 'stopped', 'Check repair was stopped');
1126
+ const ownerTable = details.owner_type === 'ticket' ? 'tickets' : 'chat_sessions';
1038
1127
  db.prepare(`
1039
- UPDATE tickets SET agent_status = 'stopped', agent_log = NULL,
1128
+ UPDATE ${ownerTable} SET agent_status = 'stopped', agent_log = NULL,
1040
1129
  streaming_response = NULL, updated_at = CURRENT_TIMESTAMP
1041
1130
  WHERE id = ? AND project_id = ? AND agent_status = 'running'
1042
- `).run(details.ticket_id, projectId);
1131
+ `).run(details.owner_id, projectId);
1043
1132
  }
1044
1133
  }
1045
1134
  return true;
@@ -1051,7 +1140,13 @@ export const stopCheckRepair = async (projectId, repairRunId, io) => {
1051
1140
  await stopCheckBatch(projectId, details.rerun_batch_run_id, io ? asBroadcaster(io) : undefined);
1052
1141
  }
1053
1142
  else if (stopFollowUpAgent) {
1054
- await stopBuildAgent(details.ticket_id);
1143
+ revokeAgentSpawnPermit(details.follow_up_run_id);
1144
+ if (details.owner_type === 'ticket') {
1145
+ await stopBuildAgent(details.owner_id);
1146
+ }
1147
+ else {
1148
+ await stopChatAgent(details.owner_id);
1149
+ }
1055
1150
  }
1056
1151
  return getCheckRepairDetails(projectId, repairRunId);
1057
1152
  };