@telora/factory 0.4.5

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 (301) hide show
  1. package/dist/audit.d.ts +69 -0
  2. package/dist/audit.d.ts.map +1 -0
  3. package/dist/audit.js +376 -0
  4. package/dist/audit.js.map +1 -0
  5. package/dist/builder-completion.d.ts +35 -0
  6. package/dist/builder-completion.d.ts.map +1 -0
  7. package/dist/builder-completion.js +375 -0
  8. package/dist/builder-completion.js.map +1 -0
  9. package/dist/builder-spawner.d.ts +40 -0
  10. package/dist/builder-spawner.d.ts.map +1 -0
  11. package/dist/builder-spawner.js +493 -0
  12. package/dist/builder-spawner.js.map +1 -0
  13. package/dist/completion-gate.d.ts +52 -0
  14. package/dist/completion-gate.d.ts.map +1 -0
  15. package/dist/completion-gate.js +336 -0
  16. package/dist/completion-gate.js.map +1 -0
  17. package/dist/completion-report.d.ts +36 -0
  18. package/dist/completion-report.d.ts.map +1 -0
  19. package/dist/completion-report.js +348 -0
  20. package/dist/completion-report.js.map +1 -0
  21. package/dist/completion.d.ts +58 -0
  22. package/dist/completion.d.ts.map +1 -0
  23. package/dist/completion.js +287 -0
  24. package/dist/completion.js.map +1 -0
  25. package/dist/config.d.ts +16 -0
  26. package/dist/config.d.ts.map +1 -0
  27. package/dist/config.js +57 -0
  28. package/dist/config.js.map +1 -0
  29. package/dist/context-manager.d.ts +152 -0
  30. package/dist/context-manager.d.ts.map +1 -0
  31. package/dist/context-manager.js +421 -0
  32. package/dist/context-manager.js.map +1 -0
  33. package/dist/crash-detection.d.ts +70 -0
  34. package/dist/crash-detection.d.ts.map +1 -0
  35. package/dist/crash-detection.js +123 -0
  36. package/dist/crash-detection.js.map +1 -0
  37. package/dist/crash-recovery.d.ts +83 -0
  38. package/dist/crash-recovery.d.ts.map +1 -0
  39. package/dist/crash-recovery.js +522 -0
  40. package/dist/crash-recovery.js.map +1 -0
  41. package/dist/crash-resolution.d.ts +34 -0
  42. package/dist/crash-resolution.d.ts.map +1 -0
  43. package/dist/crash-resolution.js +382 -0
  44. package/dist/crash-resolution.js.map +1 -0
  45. package/dist/escalation.d.ts +150 -0
  46. package/dist/escalation.d.ts.map +1 -0
  47. package/dist/escalation.js +352 -0
  48. package/dist/escalation.js.map +1 -0
  49. package/dist/execution-target.d.ts +31 -0
  50. package/dist/execution-target.d.ts.map +1 -0
  51. package/dist/execution-target.js +71 -0
  52. package/dist/execution-target.js.map +1 -0
  53. package/dist/execution-unit-init.d.ts +28 -0
  54. package/dist/execution-unit-init.d.ts.map +1 -0
  55. package/dist/execution-unit-init.js +115 -0
  56. package/dist/execution-unit-init.js.map +1 -0
  57. package/dist/execution.d.ts +17 -0
  58. package/dist/execution.d.ts.map +1 -0
  59. package/dist/execution.js +20 -0
  60. package/dist/execution.js.map +1 -0
  61. package/dist/factory-engine.d.ts +100 -0
  62. package/dist/factory-engine.d.ts.map +1 -0
  63. package/dist/factory-engine.js +243 -0
  64. package/dist/factory-engine.js.map +1 -0
  65. package/dist/gap-detection.d.ts +43 -0
  66. package/dist/gap-detection.d.ts.map +1 -0
  67. package/dist/gap-detection.js +149 -0
  68. package/dist/gap-detection.js.map +1 -0
  69. package/dist/gate-context.d.ts +23 -0
  70. package/dist/gate-context.d.ts.map +1 -0
  71. package/dist/gate-context.js +63 -0
  72. package/dist/gate-context.js.map +1 -0
  73. package/dist/gate-engine.d.ts +55 -0
  74. package/dist/gate-engine.d.ts.map +1 -0
  75. package/dist/gate-engine.js +191 -0
  76. package/dist/gate-engine.js.map +1 -0
  77. package/dist/gates/adversarial.d.ts +59 -0
  78. package/dist/gates/adversarial.d.ts.map +1 -0
  79. package/dist/gates/adversarial.js +426 -0
  80. package/dist/gates/adversarial.js.map +1 -0
  81. package/dist/gates/adversary-spawner.d.ts +35 -0
  82. package/dist/gates/adversary-spawner.d.ts.map +1 -0
  83. package/dist/gates/adversary-spawner.js +286 -0
  84. package/dist/gates/adversary-spawner.js.map +1 -0
  85. package/dist/gates/adversary-test-dir.d.ts +41 -0
  86. package/dist/gates/adversary-test-dir.d.ts.map +1 -0
  87. package/dist/gates/adversary-test-dir.js +150 -0
  88. package/dist/gates/adversary-test-dir.js.map +1 -0
  89. package/dist/gates/behavioral-parser.d.ts +32 -0
  90. package/dist/gates/behavioral-parser.d.ts.map +1 -0
  91. package/dist/gates/behavioral-parser.js +190 -0
  92. package/dist/gates/behavioral-parser.js.map +1 -0
  93. package/dist/gates/behavioral-runner.d.ts +36 -0
  94. package/dist/gates/behavioral-runner.d.ts.map +1 -0
  95. package/dist/gates/behavioral-runner.js +306 -0
  96. package/dist/gates/behavioral-runner.js.map +1 -0
  97. package/dist/gates/behavioral.d.ts +37 -0
  98. package/dist/gates/behavioral.d.ts.map +1 -0
  99. package/dist/gates/behavioral.js +485 -0
  100. package/dist/gates/behavioral.js.map +1 -0
  101. package/dist/gates/deterministic.d.ts +24 -0
  102. package/dist/gates/deterministic.d.ts.map +1 -0
  103. package/dist/gates/deterministic.js +186 -0
  104. package/dist/gates/deterministic.js.map +1 -0
  105. package/dist/git-factory.d.ts +59 -0
  106. package/dist/git-factory.d.ts.map +1 -0
  107. package/dist/git-factory.js +102 -0
  108. package/dist/git-factory.js.map +1 -0
  109. package/dist/guard-evaluation.d.ts +48 -0
  110. package/dist/guard-evaluation.d.ts.map +1 -0
  111. package/dist/guard-evaluation.js +416 -0
  112. package/dist/guard-evaluation.js.map +1 -0
  113. package/dist/index.d.ts +30 -0
  114. package/dist/index.d.ts.map +1 -0
  115. package/dist/index.js +39 -0
  116. package/dist/index.js.map +1 -0
  117. package/dist/instance-completion.d.ts +34 -0
  118. package/dist/instance-completion.d.ts.map +1 -0
  119. package/dist/instance-completion.js +366 -0
  120. package/dist/instance-completion.js.map +1 -0
  121. package/dist/instance-lifecycle.d.ts +15 -0
  122. package/dist/instance-lifecycle.d.ts.map +1 -0
  123. package/dist/instance-lifecycle.js +18 -0
  124. package/dist/instance-lifecycle.js.map +1 -0
  125. package/dist/instance-phase-dispatch.d.ts +75 -0
  126. package/dist/instance-phase-dispatch.d.ts.map +1 -0
  127. package/dist/instance-phase-dispatch.js +674 -0
  128. package/dist/instance-phase-dispatch.js.map +1 -0
  129. package/dist/instance-poll-loop.d.ts +43 -0
  130. package/dist/instance-poll-loop.d.ts.map +1 -0
  131. package/dist/instance-poll-loop.js +360 -0
  132. package/dist/instance-poll-loop.js.map +1 -0
  133. package/dist/instance-state-machine.d.ts +52 -0
  134. package/dist/instance-state-machine.d.ts.map +1 -0
  135. package/dist/instance-state-machine.js +235 -0
  136. package/dist/instance-state-machine.js.map +1 -0
  137. package/dist/log-manager.d.ts +28 -0
  138. package/dist/log-manager.d.ts.map +1 -0
  139. package/dist/log-manager.js +71 -0
  140. package/dist/log-manager.js.map +1 -0
  141. package/dist/pipeline-evaluator.d.ts +61 -0
  142. package/dist/pipeline-evaluator.d.ts.map +1 -0
  143. package/dist/pipeline-evaluator.js +107 -0
  144. package/dist/pipeline-evaluator.js.map +1 -0
  145. package/dist/pipeline-metrics.d.ts +52 -0
  146. package/dist/pipeline-metrics.d.ts.map +1 -0
  147. package/dist/pipeline-metrics.js +40 -0
  148. package/dist/pipeline-metrics.js.map +1 -0
  149. package/dist/pipeline-traversal.d.ts +43 -0
  150. package/dist/pipeline-traversal.d.ts.map +1 -0
  151. package/dist/pipeline-traversal.js +68 -0
  152. package/dist/pipeline-traversal.js.map +1 -0
  153. package/dist/plan-parser.d.ts +76 -0
  154. package/dist/plan-parser.d.ts.map +1 -0
  155. package/dist/plan-parser.js +223 -0
  156. package/dist/plan-parser.js.map +1 -0
  157. package/dist/planning-phase.d.ts +52 -0
  158. package/dist/planning-phase.d.ts.map +1 -0
  159. package/dist/planning-phase.js +444 -0
  160. package/dist/planning-phase.js.map +1 -0
  161. package/dist/planning-prompt.d.ts +64 -0
  162. package/dist/planning-prompt.d.ts.map +1 -0
  163. package/dist/planning-prompt.js +251 -0
  164. package/dist/planning-prompt.js.map +1 -0
  165. package/dist/planning.d.ts +16 -0
  166. package/dist/planning.d.ts.map +1 -0
  167. package/dist/planning.js +17 -0
  168. package/dist/planning.js.map +1 -0
  169. package/dist/process-runner.d.ts +41 -0
  170. package/dist/process-runner.d.ts.map +1 -0
  171. package/dist/process-runner.js +81 -0
  172. package/dist/process-runner.js.map +1 -0
  173. package/dist/product-config.d.ts +34 -0
  174. package/dist/product-config.d.ts.map +1 -0
  175. package/dist/product-config.js +43 -0
  176. package/dist/product-config.js.map +1 -0
  177. package/dist/queries/cycle-evaluations.d.ts +23 -0
  178. package/dist/queries/cycle-evaluations.d.ts.map +1 -0
  179. package/dist/queries/cycle-evaluations.js +37 -0
  180. package/dist/queries/cycle-evaluations.js.map +1 -0
  181. package/dist/queries/escalations.d.ts +30 -0
  182. package/dist/queries/escalations.d.ts.map +1 -0
  183. package/dist/queries/escalations.js +42 -0
  184. package/dist/queries/escalations.js.map +1 -0
  185. package/dist/queries/execution-units.d.ts +76 -0
  186. package/dist/queries/execution-units.d.ts.map +1 -0
  187. package/dist/queries/execution-units.js +109 -0
  188. package/dist/queries/execution-units.js.map +1 -0
  189. package/dist/queries/gate-results.d.ts +32 -0
  190. package/dist/queries/gate-results.d.ts.map +1 -0
  191. package/dist/queries/gate-results.js +44 -0
  192. package/dist/queries/gate-results.js.map +1 -0
  193. package/dist/queries/instances.d.ts +51 -0
  194. package/dist/queries/instances.d.ts.map +1 -0
  195. package/dist/queries/instances.js +77 -0
  196. package/dist/queries/instances.js.map +1 -0
  197. package/dist/queries/sessions.d.ts +50 -0
  198. package/dist/queries/sessions.d.ts.map +1 -0
  199. package/dist/queries/sessions.js +81 -0
  200. package/dist/queries/sessions.js.map +1 -0
  201. package/dist/queries/shared.d.ts +38 -0
  202. package/dist/queries/shared.d.ts.map +1 -0
  203. package/dist/queries/shared.js +119 -0
  204. package/dist/queries/shared.js.map +1 -0
  205. package/dist/queries/specs.d.ts +12 -0
  206. package/dist/queries/specs.d.ts.map +1 -0
  207. package/dist/queries/specs.js +21 -0
  208. package/dist/queries/specs.js.map +1 -0
  209. package/dist/queries/strategies.d.ts +14 -0
  210. package/dist/queries/strategies.d.ts.map +1 -0
  211. package/dist/queries/strategies.js +18 -0
  212. package/dist/queries/strategies.js.map +1 -0
  213. package/dist/queries/work-units.d.ts +42 -0
  214. package/dist/queries/work-units.d.ts.map +1 -0
  215. package/dist/queries/work-units.js +57 -0
  216. package/dist/queries/work-units.js.map +1 -0
  217. package/dist/queries/workflows.d.ts +29 -0
  218. package/dist/queries/workflows.d.ts.map +1 -0
  219. package/dist/queries/workflows.js +103 -0
  220. package/dist/queries/workflows.js.map +1 -0
  221. package/dist/remediation-units.d.ts +40 -0
  222. package/dist/remediation-units.d.ts.map +1 -0
  223. package/dist/remediation-units.js +263 -0
  224. package/dist/remediation-units.js.map +1 -0
  225. package/dist/replanning.d.ts +72 -0
  226. package/dist/replanning.d.ts.map +1 -0
  227. package/dist/replanning.js +403 -0
  228. package/dist/replanning.js.map +1 -0
  229. package/dist/resource-limits.d.ts +62 -0
  230. package/dist/resource-limits.d.ts.map +1 -0
  231. package/dist/resource-limits.js +322 -0
  232. package/dist/resource-limits.js.map +1 -0
  233. package/dist/scheduler.d.ts +98 -0
  234. package/dist/scheduler.d.ts.map +1 -0
  235. package/dist/scheduler.js +203 -0
  236. package/dist/scheduler.js.map +1 -0
  237. package/dist/session-adapter.d.ts +89 -0
  238. package/dist/session-adapter.d.ts.map +1 -0
  239. package/dist/session-adapter.js +108 -0
  240. package/dist/session-adapter.js.map +1 -0
  241. package/dist/sop-generator.d.ts +29 -0
  242. package/dist/sop-generator.d.ts.map +1 -0
  243. package/dist/sop-generator.js +235 -0
  244. package/dist/sop-generator.js.map +1 -0
  245. package/dist/spec-profiles.d.ts +41 -0
  246. package/dist/spec-profiles.d.ts.map +1 -0
  247. package/dist/spec-profiles.js +131 -0
  248. package/dist/spec-profiles.js.map +1 -0
  249. package/dist/strategy-design-graph.d.ts +23 -0
  250. package/dist/strategy-design-graph.d.ts.map +1 -0
  251. package/dist/strategy-design-graph.js +205 -0
  252. package/dist/strategy-design-graph.js.map +1 -0
  253. package/dist/strategy-design-prompt.d.ts +28 -0
  254. package/dist/strategy-design-prompt.d.ts.map +1 -0
  255. package/dist/strategy-design-prompt.js +108 -0
  256. package/dist/strategy-design-prompt.js.map +1 -0
  257. package/dist/strategy-design-schema.d.ts +767 -0
  258. package/dist/strategy-design-schema.d.ts.map +1 -0
  259. package/dist/strategy-design-schema.js +126 -0
  260. package/dist/strategy-design-schema.js.map +1 -0
  261. package/dist/strategy-design.d.ts +69 -0
  262. package/dist/strategy-design.d.ts.map +1 -0
  263. package/dist/strategy-design.js +411 -0
  264. package/dist/strategy-design.js.map +1 -0
  265. package/dist/strategy-gating.d.ts +31 -0
  266. package/dist/strategy-gating.d.ts.map +1 -0
  267. package/dist/strategy-gating.js +276 -0
  268. package/dist/strategy-gating.js.map +1 -0
  269. package/dist/team-prompt-builder.d.ts +47 -0
  270. package/dist/team-prompt-builder.d.ts.map +1 -0
  271. package/dist/team-prompt-builder.js +362 -0
  272. package/dist/team-prompt-builder.js.map +1 -0
  273. package/dist/trace-engine.d.ts +40 -0
  274. package/dist/trace-engine.d.ts.map +1 -0
  275. package/dist/trace-engine.js +344 -0
  276. package/dist/trace-engine.js.map +1 -0
  277. package/dist/types.d.ts +612 -0
  278. package/dist/types.d.ts.map +1 -0
  279. package/dist/types.js +9 -0
  280. package/dist/types.js.map +1 -0
  281. package/dist/unit-session-lifecycle.d.ts +78 -0
  282. package/dist/unit-session-lifecycle.d.ts.map +1 -0
  283. package/dist/unit-session-lifecycle.js +141 -0
  284. package/dist/unit-session-lifecycle.js.map +1 -0
  285. package/dist/unit-session.d.ts +30 -0
  286. package/dist/unit-session.d.ts.map +1 -0
  287. package/dist/unit-session.js +370 -0
  288. package/dist/unit-session.js.map +1 -0
  289. package/dist/watchdogs.d.ts +33 -0
  290. package/dist/watchdogs.d.ts.map +1 -0
  291. package/dist/watchdogs.js +170 -0
  292. package/dist/watchdogs.js.map +1 -0
  293. package/dist/work-unit-scheduler.d.ts +34 -0
  294. package/dist/work-unit-scheduler.d.ts.map +1 -0
  295. package/dist/work-unit-scheduler.js +91 -0
  296. package/dist/work-unit-scheduler.js.map +1 -0
  297. package/dist/workflow-transition.d.ts +90 -0
  298. package/dist/workflow-transition.d.ts.map +1 -0
  299. package/dist/workflow-transition.js +340 -0
  300. package/dist/workflow-transition.js.map +1 -0
  301. package/package.json +65 -0
@@ -0,0 +1,287 @@
1
+ /**
2
+ * Factory instance completion detection and handling.
3
+ *
4
+ * Checks whether all work units in a factory instance have reached the
5
+ * 'completed' status, and if so, transitions the instance to 'completed'
6
+ * with a summary message.
7
+ *
8
+ * Also provides a WIP commit helper for pause/shutdown scenarios to
9
+ * preserve uncommitted work before the orchestrator stops.
10
+ */
11
+ import { getInstanceWorkUnits } from './queries/work-units.js';
12
+ import { updateInstanceStatus } from './queries/instances.js';
13
+ import { getActiveSessionsForInstance, updateFactorySession } from './queries/sessions.js';
14
+ import { commitWip } from './git-factory.js';
15
+ // ============================================================================
16
+ // Completion detection
17
+ // ============================================================================
18
+ /**
19
+ * Check whether all work units for a factory instance are completed.
20
+ *
21
+ * If every work unit has status 'completed', this function:
22
+ * 1. Sets the instance status to 'completed'.
23
+ * 2. Records a completion_message summarizing the work.
24
+ * 3. Sets completed_at to the current timestamp.
25
+ *
26
+ * Work stays on its branch -- no merge, no PR creation.
27
+ *
28
+ * @param instanceId - The factory instance to check.
29
+ * @param config - Factory configuration (used for logging context).
30
+ * @returns A CompletionResult describing the outcome.
31
+ */
32
+ export async function detectCompletion(instanceId, config) {
33
+ // Fetch all work units for this instance
34
+ const workUnits = await getInstanceWorkUnits(instanceId);
35
+ if (workUnits.length === 0) {
36
+ console.warn(`[completion] Instance ${instanceId} has no work units -- cannot complete`);
37
+ return {
38
+ isComplete: false,
39
+ completedCount: 0,
40
+ totalCount: 0,
41
+ completionMessage: null,
42
+ };
43
+ }
44
+ const completedUnits = workUnits.filter((wu) => wu.status === 'completed');
45
+ const totalCount = workUnits.length;
46
+ const completedCount = completedUnits.length;
47
+ // Strategy-aware completion: fetch strategies if work units have strategy tags
48
+ const hasStrategies = workUnits.some((wu) => wu.strategyId !== null);
49
+ let strategies = [];
50
+ if (hasStrategies) {
51
+ try {
52
+ const { getStrategiesByFactoryInstance } = await import('./strategy-design.js');
53
+ strategies = await getStrategiesByFactoryInstance(instanceId);
54
+ }
55
+ catch {
56
+ // Non-fatal: fall through to standard completion detection
57
+ }
58
+ }
59
+ if (hasStrategies && strategies.length > 0) {
60
+ // Strategy-aware completion detection
61
+ return detectStrategyAwareCompletion(instanceId, workUnits, strategies, completedCount, totalCount, config);
62
+ }
63
+ // Legacy (non-strategy) completion detection
64
+ if (completedCount < totalCount) {
65
+ const pendingStatuses = summarizeStatuses(workUnits);
66
+ console.log(`[completion] Instance ${instanceId}: ${completedCount}/${totalCount} work units completed (${pendingStatuses})`);
67
+ return {
68
+ isComplete: false,
69
+ completedCount,
70
+ totalCount,
71
+ completionMessage: null,
72
+ };
73
+ }
74
+ // All work units are completed -- finalize the instance
75
+ const completionMessage = buildCompletionMessage(workUnits, config);
76
+ await updateInstanceStatus(instanceId, 'completed', {
77
+ completionMessage,
78
+ completedAt: new Date().toISOString(),
79
+ });
80
+ console.log(`[completion] Instance ${instanceId} completed: all ${totalCount} work unit(s) passed all gates`);
81
+ return {
82
+ isComplete: true,
83
+ completedCount,
84
+ totalCount,
85
+ completionMessage,
86
+ };
87
+ }
88
+ /**
89
+ * Strategy-aware completion detection.
90
+ *
91
+ * Checks completion at the strategy level:
92
+ * - Instance complete: ALL strategies have executionStatus 'completed'
93
+ * - Instance failed: a strategy failed and blocks downstream progress
94
+ * - In progress: some strategies still running or eligible
95
+ */
96
+ async function detectStrategyAwareCompletion(instanceId, workUnits, strategies, completedCount, totalCount, config) {
97
+ const completedStrategies = strategies.filter((s) => s.executionStatus === 'completed');
98
+ const failedStrategies = strategies.filter((s) => s.executionStatus === 'failed');
99
+ const activeStrategies = strategies.filter((s) => s.executionStatus === 'in_progress' || s.executionStatus === 'pending' ||
100
+ s.executionStatus === 'gating_deterministic' ||
101
+ s.executionStatus === 'gating_behavioral' ||
102
+ s.executionStatus === 'gating_adversarial' ||
103
+ s.executionStatus === 'gate_fix_pending');
104
+ // All strategies completed
105
+ if (completedStrategies.length === strategies.length) {
106
+ const completionMessage = buildStrategyCompletionMessage(workUnits, strategies, config);
107
+ await updateInstanceStatus(instanceId, 'completed', {
108
+ completionMessage,
109
+ completedAt: new Date().toISOString(),
110
+ });
111
+ console.log(`[completion] Instance ${instanceId} completed: all ${strategies.length} strategy(ies) ` +
112
+ `and ${totalCount} work unit(s) done`);
113
+ return {
114
+ isComplete: true,
115
+ completedCount,
116
+ totalCount,
117
+ completionMessage,
118
+ };
119
+ }
120
+ // Check if failed strategies block all remaining progress
121
+ if (failedStrategies.length > 0 && activeStrategies.length === 0) {
122
+ // All non-completed strategies have failed -- no more progress possible
123
+ const blockedNames = failedStrategies.map((s) => s.name).join(', ');
124
+ const completionMessage = `Factory instance failed. ${failedStrategies.length} strategy(ies) failed: ${blockedNames}. ` +
125
+ `${completedStrategies.length}/${strategies.length} strategies completed. ` +
126
+ `${completedCount}/${totalCount} work units completed.`;
127
+ await updateInstanceStatus(instanceId, 'failed', {
128
+ completionMessage,
129
+ completedAt: new Date().toISOString(),
130
+ });
131
+ console.log(`[completion] Instance ${instanceId} failed: ${failedStrategies.length} strategy(ies) failed, ` +
132
+ `no active strategies remaining`);
133
+ return {
134
+ isComplete: true,
135
+ completedCount,
136
+ totalCount,
137
+ completionMessage,
138
+ };
139
+ }
140
+ // Check if failed strategies block all remaining eligible strategies
141
+ if (failedStrategies.length > 0) {
142
+ const failedIds = new Set(failedStrategies.map((s) => s.id));
143
+ const blockedByFailure = activeStrategies.filter((s) => s.dependsOn.some((depId) => failedIds.has(depId)));
144
+ // If all active strategies are blocked by failed ones, no progress is possible
145
+ if (blockedByFailure.length === activeStrategies.length) {
146
+ const failedNames = failedStrategies.map((s) => s.name).join(', ');
147
+ const blockedNames = blockedByFailure.map((s) => s.name).join(', ');
148
+ const completionMessage = `Factory instance failed. Strategy(ies) failed: ${failedNames}. ` +
149
+ `Blocked downstream: ${blockedNames}. ` +
150
+ `${completedStrategies.length}/${strategies.length} strategies completed. ` +
151
+ `${completedCount}/${totalCount} work units completed.`;
152
+ await updateInstanceStatus(instanceId, 'failed', {
153
+ completionMessage,
154
+ completedAt: new Date().toISOString(),
155
+ });
156
+ console.log(`[completion] Instance ${instanceId} failed: ${failedStrategies.length} failed, ` +
157
+ `${blockedByFailure.length} blocked -- no progress possible`);
158
+ return {
159
+ isComplete: true,
160
+ completedCount,
161
+ totalCount,
162
+ completionMessage,
163
+ };
164
+ }
165
+ }
166
+ // Still in progress
167
+ console.log(`[completion] Instance ${instanceId}: ` +
168
+ `${completedStrategies.length}/${strategies.length} strategies completed, ` +
169
+ `${failedStrategies.length} failed, ${activeStrategies.length} active. ` +
170
+ `${completedCount}/${totalCount} work units completed.`);
171
+ return {
172
+ isComplete: false,
173
+ completedCount,
174
+ totalCount,
175
+ completionMessage: null,
176
+ };
177
+ }
178
+ // ============================================================================
179
+ // WIP commit on pause/shutdown
180
+ // ============================================================================
181
+ /**
182
+ * Perform a WIP safety commit for an active factory instance.
183
+ *
184
+ * Used during pause or graceful shutdown to preserve any uncommitted
185
+ * changes in the instance's worktree. Also marks active sessions as
186
+ * cancelled so they are not treated as running after restart.
187
+ *
188
+ * @param instanceId - The factory instance ID.
189
+ * @param worktreePath - Absolute path to the instance's worktree.
190
+ * @param label - Human-readable label for the WIP commit message.
191
+ * @returns A ShutdownWipResult with commit info and session counts.
192
+ */
193
+ export async function commitWipOnShutdown(instanceId, worktreePath, label) {
194
+ // Step 1: WIP commit any uncommitted changes
195
+ const commitSha = commitWip(worktreePath, label);
196
+ if (commitSha) {
197
+ console.log(`[completion] WIP commit for instance ${instanceId}: ${commitSha.slice(0, 8)}`);
198
+ }
199
+ else {
200
+ console.log(`[completion] No uncommitted changes for instance ${instanceId} -- no WIP commit needed`);
201
+ }
202
+ // Step 2: Mark active sessions as cancelled
203
+ let sessionsCancelled = 0;
204
+ try {
205
+ const activeSessions = await getActiveSessionsForInstance(instanceId);
206
+ for (const session of activeSessions) {
207
+ try {
208
+ await updateFactorySession(session.id, {
209
+ status: 'cancelled',
210
+ endedAt: new Date().toISOString(),
211
+ });
212
+ sessionsCancelled++;
213
+ }
214
+ catch (err) {
215
+ console.warn(`[completion] Failed to cancel session ${session.id}: ` +
216
+ `${err instanceof Error ? err.message : String(err)}`);
217
+ }
218
+ }
219
+ if (sessionsCancelled > 0) {
220
+ console.log(`[completion] Cancelled ${sessionsCancelled} active session(s) for instance ${instanceId}`);
221
+ }
222
+ }
223
+ catch (err) {
224
+ console.warn(`[completion] Failed to query active sessions for instance ${instanceId}: ` +
225
+ `${err instanceof Error ? err.message : String(err)}`);
226
+ }
227
+ return {
228
+ instanceId,
229
+ commitSha,
230
+ sessionsCancelled,
231
+ };
232
+ }
233
+ // ============================================================================
234
+ // Internal helpers
235
+ // ============================================================================
236
+ /**
237
+ * Build a strategy-aware completion message.
238
+ */
239
+ function buildStrategyCompletionMessage(workUnits, strategies, _config) {
240
+ const sortedStrategies = [...strategies].sort((a, b) => a.priorityRank - b.priorityRank);
241
+ const strategySummaries = sortedStrategies.map((s) => {
242
+ const strategyUnits = workUnits
243
+ .filter((wu) => wu.strategyId === s.id)
244
+ .sort((a, b) => a.sortOrder - b.sortOrder);
245
+ const totalIter = strategyUnits.reduce((sum, wu) => sum + wu.iterationCount, 0);
246
+ const unitList = strategyUnits
247
+ .map((wu) => ` - ${wu.title} (${wu.iterationCount} iteration(s))`)
248
+ .join('\n');
249
+ return ` Strategy "${s.name}" (${strategyUnits.length} work unit(s), ${totalIter} iteration(s)):\n${unitList}`;
250
+ }).join('\n');
251
+ const totalIterations = workUnits.reduce((sum, wu) => sum + wu.iterationCount, 0);
252
+ return (`Factory instance completed successfully.\n` +
253
+ `${strategies.length} strategy(ies), ${workUnits.length} work unit(s), ` +
254
+ `${totalIterations} total iteration(s):\n` +
255
+ strategySummaries);
256
+ }
257
+ /**
258
+ * Build a human-readable completion message summarizing the instance's work.
259
+ */
260
+ function buildCompletionMessage(workUnits, _config) {
261
+ const unitSummaries = workUnits
262
+ .sort((a, b) => a.sortOrder - b.sortOrder)
263
+ .map((wu) => ` - ${wu.title} (${wu.iterationCount} iteration(s))`)
264
+ .join('\n');
265
+ const totalIterations = workUnits.reduce((sum, wu) => sum + wu.iterationCount, 0);
266
+ return (`Factory instance completed successfully.\n` +
267
+ `${workUnits.length} work unit(s) completed across ${totalIterations} total iteration(s):\n` +
268
+ unitSummaries);
269
+ }
270
+ /**
271
+ * Summarize the status distribution of work units that are not yet completed.
272
+ * Returns a string like "3 pending, 1 in_progress, 2 ready".
273
+ */
274
+ function summarizeStatuses(workUnits) {
275
+ const statusCounts = new Map();
276
+ for (const wu of workUnits) {
277
+ if (wu.status === 'completed')
278
+ continue;
279
+ statusCounts.set(wu.status, (statusCounts.get(wu.status) ?? 0) + 1);
280
+ }
281
+ if (statusCounts.size === 0)
282
+ return 'all completed';
283
+ return Array.from(statusCounts.entries())
284
+ .map(([status, count]) => `${count} ${status}`)
285
+ .join(', ');
286
+ }
287
+ //# sourceMappingURL=completion.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"completion.js","sourceRoot":"","sources":["../src/completion.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AAGH,OAAO,EAAE,oBAAoB,EAAE,MAAM,yBAAyB,CAAC;AAC/D,OAAO,EAAE,oBAAoB,EAAE,MAAM,wBAAwB,CAAC;AAC9D,OAAO,EAAE,4BAA4B,EAAE,oBAAoB,EAAE,MAAM,uBAAuB,CAAC;AAC3F,OAAO,EAAE,SAAS,EAAE,MAAM,kBAAkB,CAAC;AA2B7C,+EAA+E;AAC/E,uBAAuB;AACvB,+EAA+E;AAE/E;;;;;;;;;;;;;GAaG;AACH,MAAM,CAAC,KAAK,UAAU,gBAAgB,CACpC,UAAkB,EAClB,MAAqB;IAErB,yCAAyC;IACzC,MAAM,SAAS,GAAG,MAAM,oBAAoB,CAAC,UAAU,CAAC,CAAC;IAEzD,IAAI,SAAS,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;QAC3B,OAAO,CAAC,IAAI,CACV,yBAAyB,UAAU,uCAAuC,CAC3E,CAAC;QACF,OAAO;YACL,UAAU,EAAE,KAAK;YACjB,cAAc,EAAE,CAAC;YACjB,UAAU,EAAE,CAAC;YACb,iBAAiB,EAAE,IAAI;SACxB,CAAC;IACJ,CAAC;IAED,MAAM,cAAc,GAAG,SAAS,CAAC,MAAM,CAAC,CAAC,EAAE,EAAE,EAAE,CAAC,EAAE,CAAC,MAAM,KAAK,WAAW,CAAC,CAAC;IAC3E,MAAM,UAAU,GAAG,SAAS,CAAC,MAAM,CAAC;IACpC,MAAM,cAAc,GAAG,cAAc,CAAC,MAAM,CAAC;IAE7C,+EAA+E;IAC/E,MAAM,aAAa,GAAG,SAAS,CAAC,IAAI,CAAC,CAAC,EAAE,EAAE,EAAE,CAAC,EAAE,CAAC,UAAU,KAAK,IAAI,CAAC,CAAC;IACrE,IAAI,UAAU,GAAwB,EAAE,CAAC;IACzC,IAAI,aAAa,EAAE,CAAC;QAClB,IAAI,CAAC;YACH,MAAM,EAAE,8BAA8B,EAAE,GAAG,MAAM,MAAM,CAAC,sBAAsB,CAAC,CAAC;YAChF,UAAU,GAAG,MAAM,8BAA8B,CAAC,UAAU,CAAC,CAAC;QAChE,CAAC;QAAC,MAAM,CAAC;YACP,2DAA2D;QAC7D,CAAC;IACH,CAAC;IAED,IAAI,aAAa,IAAI,UAAU,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;QAC3C,sCAAsC;QACtC,OAAO,6BAA6B,CAClC,UAAU,EAAE,SAAS,EAAE,UAAU,EAAE,cAAc,EAAE,UAAU,EAAE,MAAM,CACtE,CAAC;IACJ,CAAC;IAED,6CAA6C;IAC7C,IAAI,cAAc,GAAG,UAAU,EAAE,CAAC;QAChC,MAAM,eAAe,GAAG,iBAAiB,CAAC,SAAS,CAAC,CAAC;QACrD,OAAO,CAAC,GAAG,CACT,yBAAyB,UAAU,KAAK,cAAc,IAAI,UAAU,0BAA0B,eAAe,GAAG,CACjH,CAAC;QACF,OAAO;YACL,UAAU,EAAE,KAAK;YACjB,cAAc;YACd,UAAU;YACV,iBAAiB,EAAE,IAAI;SACxB,CAAC;IACJ,CAAC;IAED,wDAAwD;IACxD,MAAM,iBAAiB,GAAG,sBAAsB,CAAC,SAAS,EAAE,MAAM,CAAC,CAAC;IAEpE,MAAM,oBAAoB,CAAC,UAAU,EAAE,WAAW,EAAE;QAClD,iBAAiB;QACjB,WAAW,EAAE,IAAI,IAAI,EAAE,CAAC,WAAW,EAAE;KACtC,CAAC,CAAC;IAEH,OAAO,CAAC,GAAG,CACT,yBAAyB,UAAU,mBAAmB,UAAU,gCAAgC,CACjG,CAAC;IAEF,OAAO;QACL,UAAU,EAAE,IAAI;QAChB,cAAc;QACd,UAAU;QACV,iBAAiB;KAClB,CAAC;AACJ,CAAC;AAED;;;;;;;GAOG;AACH,KAAK,UAAU,6BAA6B,CAC1C,UAAkB,EAClB,SAA4B,EAC5B,UAA+B,EAC/B,cAAsB,EACtB,UAAkB,EAClB,MAAqB;IAErB,MAAM,mBAAmB,GAAG,UAAU,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,eAAe,KAAK,WAAW,CAAC,CAAC;IACxF,MAAM,gBAAgB,GAAG,UAAU,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,eAAe,KAAK,QAAQ,CAAC,CAAC;IAClF,MAAM,gBAAgB,GAAG,UAAU,CAAC,MAAM,CACxC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,eAAe,KAAK,aAAa,IAAI,CAAC,CAAC,eAAe,KAAK,SAAS;QACtE,CAAC,CAAC,eAAe,KAAK,sBAAsB;QAC5C,CAAC,CAAC,eAAe,KAAK,mBAAmB;QACzC,CAAC,CAAC,eAAe,KAAK,oBAAoB;QAC1C,CAAC,CAAC,eAAe,KAAK,kBAAkB,CAChD,CAAC;IAEF,2BAA2B;IAC3B,IAAI,mBAAmB,CAAC,MAAM,KAAK,UAAU,CAAC,MAAM,EAAE,CAAC;QACrD,MAAM,iBAAiB,GAAG,8BAA8B,CAAC,SAAS,EAAE,UAAU,EAAE,MAAM,CAAC,CAAC;QAExF,MAAM,oBAAoB,CAAC,UAAU,EAAE,WAAW,EAAE;YAClD,iBAAiB;YACjB,WAAW,EAAE,IAAI,IAAI,EAAE,CAAC,WAAW,EAAE;SACtC,CAAC,CAAC;QAEH,OAAO,CAAC,GAAG,CACT,yBAAyB,UAAU,mBAAmB,UAAU,CAAC,MAAM,iBAAiB;YACxF,OAAO,UAAU,oBAAoB,CACtC,CAAC;QAEF,OAAO;YACL,UAAU,EAAE,IAAI;YAChB,cAAc;YACd,UAAU;YACV,iBAAiB;SAClB,CAAC;IACJ,CAAC;IAED,0DAA0D;IAC1D,IAAI,gBAAgB,CAAC,MAAM,GAAG,CAAC,IAAI,gBAAgB,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;QACjE,wEAAwE;QACxE,MAAM,YAAY,GAAG,gBAAgB,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;QACpE,MAAM,iBAAiB,GACrB,4BAA4B,gBAAgB,CAAC,MAAM,0BAA0B,YAAY,IAAI;YAC7F,GAAG,mBAAmB,CAAC,MAAM,IAAI,UAAU,CAAC,MAAM,yBAAyB;YAC3E,GAAG,cAAc,IAAI,UAAU,wBAAwB,CAAC;QAE1D,MAAM,oBAAoB,CAAC,UAAU,EAAE,QAAQ,EAAE;YAC/C,iBAAiB;YACjB,WAAW,EAAE,IAAI,IAAI,EAAE,CAAC,WAAW,EAAE;SACtC,CAAC,CAAC;QAEH,OAAO,CAAC,GAAG,CACT,yBAAyB,UAAU,YAAY,gBAAgB,CAAC,MAAM,yBAAyB;YAC/F,gCAAgC,CACjC,CAAC;QAEF,OAAO;YACL,UAAU,EAAE,IAAI;YAChB,cAAc;YACd,UAAU;YACV,iBAAiB;SAClB,CAAC;IACJ,CAAC;IAED,qEAAqE;IACrE,IAAI,gBAAgB,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;QAChC,MAAM,SAAS,GAAG,IAAI,GAAG,CAAC,gBAAgB,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC;QAC7D,MAAM,gBAAgB,GAAG,gBAAgB,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CACrD,CAAC,CAAC,SAAS,CAAC,IAAI,CAAC,CAAC,KAAK,EAAE,EAAE,CAAC,SAAS,CAAC,GAAG,CAAC,KAAK,CAAC,CAAC,CAClD,CAAC;QAEF,+EAA+E;QAC/E,IAAI,gBAAgB,CAAC,MAAM,KAAK,gBAAgB,CAAC,MAAM,EAAE,CAAC;YACxD,MAAM,WAAW,GAAG,gBAAgB,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;YACnE,MAAM,YAAY,GAAG,gBAAgB,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;YACpE,MAAM,iBAAiB,GACrB,kDAAkD,WAAW,IAAI;gBACjE,uBAAuB,YAAY,IAAI;gBACvC,GAAG,mBAAmB,CAAC,MAAM,IAAI,UAAU,CAAC,MAAM,yBAAyB;gBAC3E,GAAG,cAAc,IAAI,UAAU,wBAAwB,CAAC;YAE1D,MAAM,oBAAoB,CAAC,UAAU,EAAE,QAAQ,EAAE;gBAC/C,iBAAiB;gBACjB,WAAW,EAAE,IAAI,IAAI,EAAE,CAAC,WAAW,EAAE;aACtC,CAAC,CAAC;YAEH,OAAO,CAAC,GAAG,CACT,yBAAyB,UAAU,YAAY,gBAAgB,CAAC,MAAM,WAAW;gBACjF,GAAG,gBAAgB,CAAC,MAAM,kCAAkC,CAC7D,CAAC;YAEF,OAAO;gBACL,UAAU,EAAE,IAAI;gBAChB,cAAc;gBACd,UAAU;gBACV,iBAAiB;aAClB,CAAC;QACJ,CAAC;IACH,CAAC;IAED,oBAAoB;IACpB,OAAO,CAAC,GAAG,CACT,yBAAyB,UAAU,IAAI;QACvC,GAAG,mBAAmB,CAAC,MAAM,IAAI,UAAU,CAAC,MAAM,yBAAyB;QAC3E,GAAG,gBAAgB,CAAC,MAAM,YAAY,gBAAgB,CAAC,MAAM,WAAW;QACxE,GAAG,cAAc,IAAI,UAAU,wBAAwB,CACxD,CAAC;IAEF,OAAO;QACL,UAAU,EAAE,KAAK;QACjB,cAAc;QACd,UAAU;QACV,iBAAiB,EAAE,IAAI;KACxB,CAAC;AACJ,CAAC;AAED,+EAA+E;AAC/E,+BAA+B;AAC/B,+EAA+E;AAE/E;;;;;;;;;;;GAWG;AACH,MAAM,CAAC,KAAK,UAAU,mBAAmB,CACvC,UAAkB,EAClB,YAAoB,EACpB,KAAa;IAEb,6CAA6C;IAC7C,MAAM,SAAS,GAAG,SAAS,CAAC,YAAY,EAAE,KAAK,CAAC,CAAC;IACjD,IAAI,SAAS,EAAE,CAAC;QACd,OAAO,CAAC,GAAG,CACT,wCAAwC,UAAU,KAAK,SAAS,CAAC,KAAK,CAAC,CAAC,EAAE,CAAC,CAAC,EAAE,CAC/E,CAAC;IACJ,CAAC;SAAM,CAAC;QACN,OAAO,CAAC,GAAG,CACT,oDAAoD,UAAU,0BAA0B,CACzF,CAAC;IACJ,CAAC;IAED,4CAA4C;IAC5C,IAAI,iBAAiB,GAAG,CAAC,CAAC;IAC1B,IAAI,CAAC;QACH,MAAM,cAAc,GAAG,MAAM,4BAA4B,CAAC,UAAU,CAAC,CAAC;QACtE,KAAK,MAAM,OAAO,IAAI,cAAc,EAAE,CAAC;YACrC,IAAI,CAAC;gBACH,MAAM,oBAAoB,CAAC,OAAO,CAAC,EAAE,EAAE;oBACrC,MAAM,EAAE,WAAW;oBACnB,OAAO,EAAE,IAAI,IAAI,EAAE,CAAC,WAAW,EAAE;iBAClC,CAAC,CAAC;gBACH,iBAAiB,EAAE,CAAC;YACtB,CAAC;YAAC,OAAO,GAAG,EAAE,CAAC;gBACb,OAAO,CAAC,IAAI,CACV,yCAAyC,OAAO,CAAC,EAAE,IAAI;oBACvD,GAAG,GAAG,YAAY,KAAK,CAAC,CAAC,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,GAAG,CAAC,EAAE,CACtD,CAAC;YACJ,CAAC;QACH,CAAC;QAED,IAAI,iBAAiB,GAAG,CAAC,EAAE,CAAC;YAC1B,OAAO,CAAC,GAAG,CACT,0BAA0B,iBAAiB,mCAAmC,UAAU,EAAE,CAC3F,CAAC;QACJ,CAAC;IACH,CAAC;IAAC,OAAO,GAAG,EAAE,CAAC;QACb,OAAO,CAAC,IAAI,CACV,6DAA6D,UAAU,IAAI;YAC3E,GAAG,GAAG,YAAY,KAAK,CAAC,CAAC,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,GAAG,CAAC,EAAE,CACtD,CAAC;IACJ,CAAC;IAED,OAAO;QACL,UAAU;QACV,SAAS;QACT,iBAAiB;KAClB,CAAC;AACJ,CAAC;AAED,+EAA+E;AAC/E,mBAAmB;AACnB,+EAA+E;AAE/E;;GAEG;AACH,SAAS,8BAA8B,CACrC,SAA4B,EAC5B,UAA+B,EAC/B,OAAsB;IAEtB,MAAM,gBAAgB,GAAG,CAAC,GAAG,UAAU,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,YAAY,GAAG,CAAC,CAAC,YAAY,CAAC,CAAC;IAEzF,MAAM,iBAAiB,GAAG,gBAAgB,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE;QACnD,MAAM,aAAa,GAAG,SAAS;aAC5B,MAAM,CAAC,CAAC,EAAE,EAAE,EAAE,CAAC,EAAE,CAAC,UAAU,KAAK,CAAC,CAAC,EAAE,CAAC;aACtC,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,SAAS,GAAG,CAAC,CAAC,SAAS,CAAC,CAAC;QAC7C,MAAM,SAAS,GAAG,aAAa,CAAC,MAAM,CAAC,CAAC,GAAG,EAAE,EAAE,EAAE,EAAE,CAAC,GAAG,GAAG,EAAE,CAAC,cAAc,EAAE,CAAC,CAAC,CAAC;QAChF,MAAM,QAAQ,GAAG,aAAa;aAC3B,GAAG,CAAC,CAAC,EAAE,EAAE,EAAE,CAAC,SAAS,EAAE,CAAC,KAAK,KAAK,EAAE,CAAC,cAAc,gBAAgB,CAAC;aACpE,IAAI,CAAC,IAAI,CAAC,CAAC;QACd,OAAO,eAAe,CAAC,CAAC,IAAI,MAAM,aAAa,CAAC,MAAM,kBAAkB,SAAS,oBAAoB,QAAQ,EAAE,CAAC;IAClH,CAAC,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;IAEd,MAAM,eAAe,GAAG,SAAS,CAAC,MAAM,CAAC,CAAC,GAAG,EAAE,EAAE,EAAE,EAAE,CAAC,GAAG,GAAG,EAAE,CAAC,cAAc,EAAE,CAAC,CAAC,CAAC;IAElF,OAAO,CACL,4CAA4C;QAC5C,GAAG,UAAU,CAAC,MAAM,mBAAmB,SAAS,CAAC,MAAM,iBAAiB;QACxE,GAAG,eAAe,wBAAwB;QAC1C,iBAAiB,CAClB,CAAC;AACJ,CAAC;AAED;;GAEG;AACH,SAAS,sBAAsB,CAC7B,SAA4B,EAC5B,OAAsB;IAEtB,MAAM,aAAa,GAAG,SAAS;SAC5B,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,SAAS,GAAG,CAAC,CAAC,SAAS,CAAC;SACzC,GAAG,CAAC,CAAC,EAAE,EAAE,EAAE,CAAC,OAAO,EAAE,CAAC,KAAK,KAAK,EAAE,CAAC,cAAc,gBAAgB,CAAC;SAClE,IAAI,CAAC,IAAI,CAAC,CAAC;IAEd,MAAM,eAAe,GAAG,SAAS,CAAC,MAAM,CACtC,CAAC,GAAG,EAAE,EAAE,EAAE,EAAE,CAAC,GAAG,GAAG,EAAE,CAAC,cAAc,EACpC,CAAC,CACF,CAAC;IAEF,OAAO,CACL,4CAA4C;QAC5C,GAAG,SAAS,CAAC,MAAM,kCAAkC,eAAe,wBAAwB;QAC5F,aAAa,CACd,CAAC;AACJ,CAAC;AAED;;;GAGG;AACH,SAAS,iBAAiB,CAAC,SAA4B;IACrD,MAAM,YAAY,GAAG,IAAI,GAAG,EAAkB,CAAC;IAE/C,KAAK,MAAM,EAAE,IAAI,SAAS,EAAE,CAAC;QAC3B,IAAI,EAAE,CAAC,MAAM,KAAK,WAAW;YAAE,SAAS;QACxC,YAAY,CAAC,GAAG,CAAC,EAAE,CAAC,MAAM,EAAE,CAAC,YAAY,CAAC,GAAG,CAAC,EAAE,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC;IACtE,CAAC;IAED,IAAI,YAAY,CAAC,IAAI,KAAK,CAAC;QAAE,OAAO,eAAe,CAAC;IAEpD,OAAO,KAAK,CAAC,IAAI,CAAC,YAAY,CAAC,OAAO,EAAE,CAAC;SACtC,GAAG,CAAC,CAAC,CAAC,MAAM,EAAE,KAAK,CAAC,EAAE,EAAE,CAAC,GAAG,KAAK,IAAI,MAAM,EAAE,CAAC;SAC9C,IAAI,CAAC,IAAI,CAAC,CAAC;AAChB,CAAC"}
@@ -0,0 +1,16 @@
1
+ /**
2
+ * Factory configuration validation.
3
+ *
4
+ * The daemon constructs a FactoryConfig from its unified config file.
5
+ * This module validates the resulting config at engine init time.
6
+ *
7
+ * Config loading, resolution, and base validation are delegated to
8
+ * @telora/daemon-core. Factory-specific validation is layered on top.
9
+ */
10
+ import type { FactoryConfig } from './types.js';
11
+ /**
12
+ * Validate factory configuration values at startup.
13
+ * Collects all validation failures and throws a single error.
14
+ */
15
+ export declare function validateConfig(config: FactoryConfig): void;
16
+ //# sourceMappingURL=config.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"config.d.ts","sourceRoot":"","sources":["../src/config.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAKH,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,YAAY,CAAC;AAEhD;;;GAGG;AACH,wBAAgB,cAAc,CAAC,MAAM,EAAE,aAAa,GAAG,IAAI,CA6C1D"}
package/dist/config.js ADDED
@@ -0,0 +1,57 @@
1
+ /**
2
+ * Factory configuration validation.
3
+ *
4
+ * The daemon constructs a FactoryConfig from its unified config file.
5
+ * This module validates the resulting config at engine init time.
6
+ *
7
+ * Config loading, resolution, and base validation are delegated to
8
+ * @telora/daemon-core. Factory-specific validation is layered on top.
9
+ */
10
+ import { resolve } from 'node:path';
11
+ import { existsSync, accessSync, constants } from 'node:fs';
12
+ import { validateBaseConfig } from '@telora/daemon-core';
13
+ /**
14
+ * Validate factory configuration values at startup.
15
+ * Collects all validation failures and throws a single error.
16
+ */
17
+ export function validateConfig(config) {
18
+ // Start with shared base validation
19
+ const errors = validateBaseConfig(config);
20
+ // Add factory-specific validation
21
+ // Validate each product's repoPath is a git repository
22
+ for (const product of config.products) {
23
+ if (product.repoPath && existsSync(product.repoPath)) {
24
+ const gitDir = resolve(product.repoPath, '.git');
25
+ if (!existsSync(gitDir)) {
26
+ errors.push(`Product ${product.id}: repoPath is not a git repository (no .git found): "${product.repoPath}"`);
27
+ }
28
+ }
29
+ else if (product.repoPath) {
30
+ errors.push(`Product ${product.id}: repoPath does not exist: "${product.repoPath}"`);
31
+ }
32
+ }
33
+ const worktreeParent = resolve(config.factoryWorktreeDir, '..');
34
+ if (!existsSync(worktreeParent)) {
35
+ errors.push(`factoryWorktreeDir parent directory does not exist: "${worktreeParent}"`);
36
+ }
37
+ else {
38
+ try {
39
+ accessSync(worktreeParent, constants.W_OK);
40
+ }
41
+ catch {
42
+ errors.push(`factoryWorktreeDir parent directory is not writable: "${worktreeParent}"`);
43
+ }
44
+ }
45
+ if (config.maxConcurrentInstances < 1) {
46
+ errors.push(`maxConcurrentInstances must be at least 1, got ${config.maxConcurrentInstances}`);
47
+ }
48
+ if (config.sessionTimeoutMs < 60000) {
49
+ errors.push(`sessionTimeoutMs must be at least 60000 (1 minute), got ${config.sessionTimeoutMs}`);
50
+ }
51
+ if (errors.length > 0) {
52
+ throw new Error(`Factory configuration validation failed (${errors.length} error(s)):\n` +
53
+ errors.map(e => ` - ${e}`).join('\n'));
54
+ }
55
+ console.log('Configuration validation passed');
56
+ }
57
+ //# sourceMappingURL=config.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"config.js","sourceRoot":"","sources":["../src/config.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAEH,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AACpC,OAAO,EAAE,UAAU,EAAE,UAAU,EAAE,SAAS,EAAE,MAAM,SAAS,CAAC;AAC5D,OAAO,EAAE,kBAAkB,EAAE,MAAM,qBAAqB,CAAC;AAGzD;;;GAGG;AACH,MAAM,UAAU,cAAc,CAAC,MAAqB;IAClD,oCAAoC;IACpC,MAAM,MAAM,GAAG,kBAAkB,CAAC,MAAM,CAAC,CAAC;IAE1C,kCAAkC;IAElC,uDAAuD;IACvD,KAAK,MAAM,OAAO,IAAI,MAAM,CAAC,QAAQ,EAAE,CAAC;QACtC,IAAI,OAAO,CAAC,QAAQ,IAAI,UAAU,CAAC,OAAO,CAAC,QAAQ,CAAC,EAAE,CAAC;YACrD,MAAM,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC,QAAQ,EAAE,MAAM,CAAC,CAAC;YACjD,IAAI,CAAC,UAAU,CAAC,MAAM,CAAC,EAAE,CAAC;gBACxB,MAAM,CAAC,IAAI,CAAC,WAAW,OAAO,CAAC,EAAE,wDAAwD,OAAO,CAAC,QAAQ,GAAG,CAAC,CAAC;YAChH,CAAC;QACH,CAAC;aAAM,IAAI,OAAO,CAAC,QAAQ,EAAE,CAAC;YAC5B,MAAM,CAAC,IAAI,CAAC,WAAW,OAAO,CAAC,EAAE,+BAA+B,OAAO,CAAC,QAAQ,GAAG,CAAC,CAAC;QACvF,CAAC;IACH,CAAC;IAED,MAAM,cAAc,GAAG,OAAO,CAAC,MAAM,CAAC,kBAAkB,EAAE,IAAI,CAAC,CAAC;IAChE,IAAI,CAAC,UAAU,CAAC,cAAc,CAAC,EAAE,CAAC;QAChC,MAAM,CAAC,IAAI,CAAC,wDAAwD,cAAc,GAAG,CAAC,CAAC;IACzF,CAAC;SAAM,CAAC;QACN,IAAI,CAAC;YACH,UAAU,CAAC,cAAc,EAAE,SAAS,CAAC,IAAI,CAAC,CAAC;QAC7C,CAAC;QAAC,MAAM,CAAC;YACP,MAAM,CAAC,IAAI,CAAC,yDAAyD,cAAc,GAAG,CAAC,CAAC;QAC1F,CAAC;IACH,CAAC;IAED,IAAI,MAAM,CAAC,sBAAsB,GAAG,CAAC,EAAE,CAAC;QACtC,MAAM,CAAC,IAAI,CAAC,kDAAkD,MAAM,CAAC,sBAAsB,EAAE,CAAC,CAAC;IACjG,CAAC;IAED,IAAI,MAAM,CAAC,gBAAgB,GAAG,KAAK,EAAE,CAAC;QACpC,MAAM,CAAC,IAAI,CAAC,2DAA2D,MAAM,CAAC,gBAAgB,EAAE,CAAC,CAAC;IACpG,CAAC;IAED,IAAI,MAAM,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;QACtB,MAAM,IAAI,KAAK,CACb,4CAA4C,MAAM,CAAC,MAAM,eAAe;YACxE,MAAM,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,CAAC,OAAO,CAAC,EAAE,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CACvC,CAAC;IACJ,CAAC;IAED,OAAO,CAAC,GAAG,CAAC,iCAAiC,CAAC,CAAC;AACjD,CAAC"}
@@ -0,0 +1,152 @@
1
+ /**
2
+ * Factory context management module.
3
+ *
4
+ * Builds message payloads for managing AI builder context during the
5
+ * build-gate execution cycle. Supports three operations:
6
+ *
7
+ * - compact: Instruct a running builder to summarize and compact its context
8
+ * - load_files: Instruct a running builder to read specific files into context
9
+ * - reset: Build a fresh prompt for re-spawning a builder with clean context
10
+ *
11
+ * Key design principle: this module produces PAYLOADS only. It never touches
12
+ * ChildProcess, streams, or any process management. The execution module
13
+ * (execution.ts) is responsible for sending payloads to builder processes.
14
+ */
15
+ import type { ContextDirective, ContextManager, ContextOperation, ContextOperationResult, ContextPayload, ContextContractItem, FactoryWorkUnit, FactoryInstanceState, FactoryBlueprint, GateCheckResult } from './types.js';
16
+ /**
17
+ * Default number of iterations before triggering a context reset.
18
+ * Can be overridden by blueprint configuration.
19
+ */
20
+ export declare const DEFAULT_CONTEXT_RESET_AFTER_ITERATIONS = 3;
21
+ /**
22
+ * Build a compact operation payload.
23
+ *
24
+ * Instructs a running builder to summarize its current context and continue
25
+ * working from the summary, dropping conversation history before the summary.
26
+ *
27
+ * @returns The message string to send to the builder's stdin via stream-json.
28
+ */
29
+ export declare function buildCompactPayload(): string;
30
+ /**
31
+ * Build a load_files operation payload.
32
+ *
33
+ * Instructs a running builder to read specific files into its context.
34
+ * The file list is formatted one-per-line for readability.
35
+ *
36
+ * @param files Array of file paths to load.
37
+ * @returns The message string to send to the builder's stdin via stream-json.
38
+ */
39
+ export declare function buildLoadFilesPayload(files: string[]): string;
40
+ /**
41
+ * Build a reset payload containing the full context for re-spawning a builder.
42
+ *
43
+ * Used when a work unit has iterated multiple times and needs a fresh context
44
+ * instead of accumulating stale conversation history. Includes:
45
+ * - The work unit spec and description
46
+ * - Instance specification
47
+ * - Operational notes from the blueprint
48
+ * - Summary of previous iteration results (gate feedback)
49
+ *
50
+ * @param workUnit The work unit being reset.
51
+ * @param state The parent factory instance state.
52
+ * @param gateOutput The gate failure output from the most recent iteration (if any).
53
+ * @returns A structured payload object with the fresh prompt.
54
+ */
55
+ export declare function buildResetPayload(workUnit: FactoryWorkUnit, state: FactoryInstanceState, gateOutput: string | null): ResetPayload;
56
+ /**
57
+ * Build a context payload for a given work unit from the current factory
58
+ * instance state.
59
+ *
60
+ * Extracts the work unit's title, description, strategy scope, interface
61
+ * contracts, recent gate results, relevant files, and operational notes
62
+ * into a self-contained payload that can be used to build a fresh prompt
63
+ * via the ContextManager interface.
64
+ */
65
+ export declare function buildContextPayload(state: FactoryInstanceState, workUnitId: string): ContextPayload;
66
+ /**
67
+ * Build a context payload with full work unit data.
68
+ *
69
+ * This is the preferred overload when the caller has the work unit metadata
70
+ * and gate results available (which avoids async DB lookups in the pure
71
+ * payload builder).
72
+ */
73
+ export declare function buildContextPayloadWithData(state: FactoryInstanceState, workUnitTitle: string, workUnitDescription: string, strategyScope: string, interfaceContracts: {
74
+ produces: ContextContractItem[];
75
+ consumes: ContextContractItem[];
76
+ }, recentGateResults: GateCheckResult[], relevantFiles: string[]): ContextPayload;
77
+ /**
78
+ * Build a fresh prompt for a work unit that needs a context reset.
79
+ *
80
+ * This replaces the standard buildWorkUnitPrompt when iterationCount has
81
+ * exceeded the context reset threshold. It provides all necessary context
82
+ * in a single prompt without relying on prior conversation history.
83
+ *
84
+ * @param workUnit The work unit to build the prompt for.
85
+ * @param state The parent factory instance state.
86
+ * @param gateOutput The gate failure output from the most recent iteration (if any).
87
+ * @returns The full prompt string for a fresh builder session.
88
+ */
89
+ export declare function buildFreshContextPrompt(workUnit: FactoryWorkUnit, state: FactoryInstanceState, gateOutput: string | null): string;
90
+ /**
91
+ * Build a fresh context prompt from a ContextPayload.
92
+ *
93
+ * Used by the FactoryContextManager class when handling reset operations
94
+ * via the ContextManager interface.
95
+ */
96
+ export declare function buildFreshContextPromptFromPayload(payload: ContextPayload, blueprint: FactoryBlueprint, operationalNotes?: string | null): string;
97
+ /**
98
+ * Execute a context management directive by building the appropriate payload.
99
+ *
100
+ * This is the entry point called by the trigger execution system
101
+ * (workflow-transition.ts) when a manage_context trigger fires. It routes
102
+ * the directive to the correct payload builder.
103
+ *
104
+ * @param directive The context directive from the workflow trigger.
105
+ * @returns The message payload to send to the builder, or null if no action needed.
106
+ */
107
+ export declare function executeDirective(directive: ContextDirective): string | null;
108
+ /**
109
+ * Factory context manager implementation.
110
+ *
111
+ * Translates context operations into message payloads. The actual process
112
+ * I/O (sending messages, restarting processes) is handled by the caller
113
+ * (execution.ts).
114
+ */
115
+ export declare class FactoryContextManager implements ContextManager {
116
+ private readonly blueprint;
117
+ constructor(blueprint: FactoryBlueprint);
118
+ /**
119
+ * Execute a context management operation.
120
+ *
121
+ * Returns a ContextOperationResult containing the message text to send
122
+ * to the builder session. The caller is responsible for actually
123
+ * delivering the message (via stdin for compact/load_files, or by
124
+ * restarting the process for reset).
125
+ */
126
+ executeOperation(sessionId: string, operation: ContextOperation): Promise<ContextOperationResult>;
127
+ /**
128
+ * Build a context payload from the current factory instance state for
129
+ * a given work unit.
130
+ */
131
+ buildResetPayload(state: FactoryInstanceState, workUnitId: string): ContextPayload;
132
+ private handleCompact;
133
+ private handleReset;
134
+ private handleLoadFiles;
135
+ }
136
+ /** Payload returned by buildResetPayload, ready for the execution module. */
137
+ export interface ResetPayload {
138
+ /** The fresh prompt to send to a newly spawned builder. */
139
+ freshPrompt: string;
140
+ /** Human-readable reason for the reset (for logging). */
141
+ reason: string;
142
+ }
143
+ /**
144
+ * Determine whether a work unit needs a context reset based on its
145
+ * iteration count and the configured threshold.
146
+ *
147
+ * @param iterationCount The current iteration count of the work unit.
148
+ * @param threshold The configured context reset threshold (default: 3).
149
+ * @returns True if the work unit should get a fresh context on next spawn.
150
+ */
151
+ export declare function needsContextReset(iterationCount: number, threshold?: number): boolean;
152
+ //# sourceMappingURL=context-manager.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"context-manager.d.ts","sourceRoot":"","sources":["../src/context-manager.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;GAaG;AAEH,OAAO,KAAK,EACV,gBAAgB,EAChB,cAAc,EACd,gBAAgB,EAChB,sBAAsB,EACtB,cAAc,EACd,mBAAmB,EACnB,eAAe,EACf,oBAAoB,EACpB,gBAAgB,EAChB,eAAe,EAChB,MAAM,YAAY,CAAC;AASpB;;;GAGG;AACH,eAAO,MAAM,sCAAsC,IAAI,CAAC;AASxD;;;;;;;GAOG;AACH,wBAAgB,mBAAmB,IAAI,MAAM,CAO5C;AAED;;;;;;;;GAQG;AACH,wBAAgB,qBAAqB,CAAC,KAAK,EAAE,MAAM,EAAE,GAAG,MAAM,CAW7D;AAED;;;;;;;;;;;;;;GAcG;AACH,wBAAgB,iBAAiB,CAC/B,QAAQ,EAAE,eAAe,EACzB,KAAK,EAAE,oBAAoB,EAC3B,UAAU,EAAE,MAAM,GAAG,IAAI,GACxB,YAAY,CAKd;AAED;;;;;;;;GAQG;AACH,wBAAgB,mBAAmB,CACjC,KAAK,EAAE,oBAAoB,EAC3B,UAAU,EAAE,MAAM,GACjB,cAAc,CAyChB;AAED;;;;;;GAMG;AACH,wBAAgB,2BAA2B,CACzC,KAAK,EAAE,oBAAoB,EAC3B,aAAa,EAAE,MAAM,EACrB,mBAAmB,EAAE,MAAM,EAC3B,aAAa,EAAE,MAAM,EACrB,kBAAkB,EAAE;IAAE,QAAQ,EAAE,mBAAmB,EAAE,CAAC;IAAC,QAAQ,EAAE,mBAAmB,EAAE,CAAA;CAAE,EACxF,iBAAiB,EAAE,eAAe,EAAE,EACpC,aAAa,EAAE,MAAM,EAAE,GACtB,cAAc,CAUhB;AAMD;;;;;;;;;;;GAWG;AACH,wBAAgB,uBAAuB,CACrC,QAAQ,EAAE,eAAe,EACzB,KAAK,EAAE,oBAAoB,EAC3B,UAAU,EAAE,MAAM,GAAG,IAAI,GACxB,MAAM,CAkER;AAED;;;;;GAKG;AACH,wBAAgB,kCAAkC,CAChD,OAAO,EAAE,cAAc,EACvB,SAAS,EAAE,gBAAgB,EAC3B,gBAAgB,CAAC,EAAE,MAAM,GAAG,IAAI,GAC/B,MAAM,CAuHR;AAMD;;;;;;;;;GASG;AACH,wBAAgB,gBAAgB,CAAC,SAAS,EAAE,gBAAgB,GAAG,MAAM,GAAG,IAAI,CA4B3E;AAMD;;;;;;GAMG;AACH,qBAAa,qBAAsB,YAAW,cAAc;IAC1D,OAAO,CAAC,QAAQ,CAAC,SAAS,CAAmB;gBAEjC,SAAS,EAAE,gBAAgB;IAIvC;;;;;;;OAOG;IACG,gBAAgB,CACpB,SAAS,EAAE,MAAM,EACjB,SAAS,EAAE,gBAAgB,GAC1B,OAAO,CAAC,sBAAsB,CAAC;IAsBlC;;;OAGG;IACH,iBAAiB,CACf,KAAK,EAAE,oBAAoB,EAC3B,UAAU,EAAE,MAAM,GACjB,cAAc;IAQjB,OAAO,CAAC,aAAa;IASrB,OAAO,CAAC,WAAW;IAmBnB,OAAO,CAAC,eAAe;CAsBxB;AAMD,6EAA6E;AAC7E,MAAM,WAAW,YAAY;IAC3B,2DAA2D;IAC3D,WAAW,EAAE,MAAM,CAAC;IACpB,yDAAyD;IACzD,MAAM,EAAE,MAAM,CAAC;CAChB;AAMD;;;;;;;GAOG;AACH,wBAAgB,iBAAiB,CAC/B,cAAc,EAAE,MAAM,EACtB,SAAS,GAAE,MAA+C,GACzD,OAAO,CAET"}