@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,78 @@
1
+ /**
2
+ * Execution unit session lifecycle -- pure functions and process management.
3
+ *
4
+ * This module contains the testable parts of the unit session lifecycle
5
+ * that do NOT depend on @telora/daemon-core:
6
+ * - shouldResumeSession: resume-vs-fresh decision logic
7
+ * - terminateUnitSession: graceful session termination
8
+ * - terminateAllUnits: terminate all running units for an instance
9
+ *
10
+ * The spawn function (spawnUnitSession) lives in unit-session.ts since
11
+ * it depends on daemon-core for StreamJsonParser, ActivityTracker, etc.
12
+ */
13
+ import type { ExecutionUnitState, FactoryInstanceState } from './types.js';
14
+ /** Context about the strategy being assigned to a unit. */
15
+ export interface UnitStrategyContext {
16
+ strategyId: string;
17
+ strategyName: string;
18
+ dependsOn: string[];
19
+ }
20
+ /**
21
+ * Determine whether to resume an existing session or start fresh.
22
+ *
23
+ * Resume when:
24
+ * 1. The unit has a claudeSessionId from a previous run
25
+ * 2. The new strategy's dependsOn contains the unit's previousStrategyId
26
+ *
27
+ * This preserves valuable context when consecutive strategies are related.
28
+ */
29
+ export declare function shouldResumeSession(unit: ExecutionUnitState, strategy: UnitStrategyContext): {
30
+ resume: boolean;
31
+ reason: string;
32
+ };
33
+ /**
34
+ * Gracefully terminate a running unit session.
35
+ *
36
+ * Closes stdin and sends SIGTERM. Used on instance cancellation,
37
+ * daemon shutdown, or unrecoverable error.
38
+ */
39
+ export declare function terminateUnitSession(unit: ExecutionUnitState): void;
40
+ /**
41
+ * Terminate all running unit sessions for an instance.
42
+ *
43
+ * Used during instance cancellation or daemon shutdown.
44
+ */
45
+ export declare function terminateAllUnits(state: FactoryInstanceState): void;
46
+ /**
47
+ * Validate that a claude_session_id still exists in active (non-terminal)
48
+ * factory sessions before attempting --resume.
49
+ *
50
+ * If the session is stale or the query fails, returns { valid: false } so
51
+ * the caller can fall back to a fresh spawn. The fetchActiveSessions callback
52
+ * is injected for testability (avoids daemon-core transitive dependency).
53
+ *
54
+ * @param claudeSessionId - The stored claude_session_id to validate.
55
+ * @param instanceId - The factory instance to search sessions for.
56
+ * @param slotIndex - The unit's slot index (for logging).
57
+ * @param fetchActiveSessions - Callback that returns active sessions for an instance.
58
+ * @returns { valid: true } if session found, { valid: false, reason } otherwise.
59
+ */
60
+ export declare function validateSessionForResume(claudeSessionId: string, instanceId: string, slotIndex: number, fetchActiveSessions: (instanceId: string) => Promise<Array<{
61
+ claudeSessionId: string | null;
62
+ }>>): Promise<{
63
+ valid: boolean;
64
+ reason: string;
65
+ }>;
66
+ /**
67
+ * Consume pending gate failure feedback for a unit's assigned strategy.
68
+ *
69
+ * If the unit has an assigned strategy and state.gateFailureFeedback has
70
+ * stored feedback for it, returns the feedback and removes it from the map
71
+ * (but only when stdinAvailable is true -- otherwise the feedback is kept
72
+ * for the next spawn attempt).
73
+ *
74
+ * Returns the feedback string to send, or null if no feedback is pending
75
+ * or stdin is not available.
76
+ */
77
+ export declare function consumeGateFailureFeedback(state: FactoryInstanceState, strategyId: string | null, stdinAvailable: boolean): string | null;
78
+ //# sourceMappingURL=unit-session-lifecycle.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"unit-session-lifecycle.d.ts","sourceRoot":"","sources":["../src/unit-session-lifecycle.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;AAEH,OAAO,KAAK,EACV,kBAAkB,EAClB,oBAAoB,EACrB,MAAM,YAAY,CAAC;AAQpB,2DAA2D;AAC3D,MAAM,WAAW,mBAAmB;IAClC,UAAU,EAAE,MAAM,CAAC;IACnB,YAAY,EAAE,MAAM,CAAC;IACrB,SAAS,EAAE,MAAM,EAAE,CAAC;CACrB;AAMD;;;;;;;;GAQG;AACH,wBAAgB,mBAAmB,CACjC,IAAI,EAAE,kBAAkB,EACxB,QAAQ,EAAE,mBAAmB,GAC5B;IAAE,MAAM,EAAE,OAAO,CAAC;IAAC,MAAM,EAAE,MAAM,CAAA;CAAE,CAiBrC;AAMD;;;;;GAKG;AACH,wBAAgB,oBAAoB,CAAC,IAAI,EAAE,kBAAkB,GAAG,IAAI,CAoBnE;AAED;;;;GAIG;AACH,wBAAgB,iBAAiB,CAAC,KAAK,EAAE,oBAAoB,GAAG,IAAI,CAMnE;AAMD;;;;;;;;;;;;;GAaG;AACH,wBAAsB,wBAAwB,CAC5C,eAAe,EAAE,MAAM,EACvB,UAAU,EAAE,MAAM,EAClB,SAAS,EAAE,MAAM,EACjB,mBAAmB,EAAE,CAAC,UAAU,EAAE,MAAM,KAAK,OAAO,CAAC,KAAK,CAAC;IAAE,eAAe,EAAE,MAAM,GAAG,IAAI,CAAA;CAAE,CAAC,CAAC,GAC9F,OAAO,CAAC;IAAE,KAAK,EAAE,OAAO,CAAC;IAAC,MAAM,EAAE,MAAM,CAAA;CAAE,CAAC,CAmB7C;AAMD;;;;;;;;;;GAUG;AACH,wBAAgB,0BAA0B,CACxC,KAAK,EAAE,oBAAoB,EAC3B,UAAU,EAAE,MAAM,GAAG,IAAI,EACzB,cAAc,EAAE,OAAO,GACtB,MAAM,GAAG,IAAI,CASf"}
@@ -0,0 +1,141 @@
1
+ /**
2
+ * Execution unit session lifecycle -- pure functions and process management.
3
+ *
4
+ * This module contains the testable parts of the unit session lifecycle
5
+ * that do NOT depend on @telora/daemon-core:
6
+ * - shouldResumeSession: resume-vs-fresh decision logic
7
+ * - terminateUnitSession: graceful session termination
8
+ * - terminateAllUnits: terminate all running units for an instance
9
+ *
10
+ * The spawn function (spawnUnitSession) lives in unit-session.ts since
11
+ * it depends on daemon-core for StreamJsonParser, ActivityTracker, etc.
12
+ */
13
+ const LOG_PREFIX = '[unit-session]';
14
+ // ============================================================================
15
+ // Resume-vs-fresh decision
16
+ // ============================================================================
17
+ /**
18
+ * Determine whether to resume an existing session or start fresh.
19
+ *
20
+ * Resume when:
21
+ * 1. The unit has a claudeSessionId from a previous run
22
+ * 2. The new strategy's dependsOn contains the unit's previousStrategyId
23
+ *
24
+ * This preserves valuable context when consecutive strategies are related.
25
+ */
26
+ export function shouldResumeSession(unit, strategy) {
27
+ if (!unit.claudeSessionId) {
28
+ return { resume: false, reason: 'no prior session' };
29
+ }
30
+ if (!unit.previousStrategyId) {
31
+ return { resume: false, reason: 'no previous strategy' };
32
+ }
33
+ if (strategy.dependsOn.includes(unit.previousStrategyId)) {
34
+ return {
35
+ resume: true,
36
+ reason: `strategy "${strategy.strategyName}" depends on prior work`,
37
+ };
38
+ }
39
+ return { resume: false, reason: 'no dependency on prior work' };
40
+ }
41
+ // ============================================================================
42
+ // Session termination
43
+ // ============================================================================
44
+ /**
45
+ * Gracefully terminate a running unit session.
46
+ *
47
+ * Closes stdin and sends SIGTERM. Used on instance cancellation,
48
+ * daemon shutdown, or unrecoverable error.
49
+ */
50
+ export function terminateUnitSession(unit) {
51
+ if (!unit.pid)
52
+ return;
53
+ // Close stdin
54
+ if (unit.stdin && !unit.stdin.destroyed) {
55
+ unit.stdin.end();
56
+ }
57
+ // Send SIGTERM
58
+ try {
59
+ process.kill(unit.pid, 'SIGTERM');
60
+ console.log(`${LOG_PREFIX} Sent SIGTERM to unit ${unit.slotIndex} (pid: ${unit.pid})`);
61
+ }
62
+ catch {
63
+ // Process already exited
64
+ }
65
+ // Mark as terminated (the close handler will reset to idle)
66
+ unit.status = 'terminated';
67
+ }
68
+ /**
69
+ * Terminate all running unit sessions for an instance.
70
+ *
71
+ * Used during instance cancellation or daemon shutdown.
72
+ */
73
+ export function terminateAllUnits(state) {
74
+ for (const unit of state.executionUnits.values()) {
75
+ if (unit.status === 'running') {
76
+ terminateUnitSession(unit);
77
+ }
78
+ }
79
+ }
80
+ // ============================================================================
81
+ // Session validation for resume
82
+ // ============================================================================
83
+ /**
84
+ * Validate that a claude_session_id still exists in active (non-terminal)
85
+ * factory sessions before attempting --resume.
86
+ *
87
+ * If the session is stale or the query fails, returns { valid: false } so
88
+ * the caller can fall back to a fresh spawn. The fetchActiveSessions callback
89
+ * is injected for testability (avoids daemon-core transitive dependency).
90
+ *
91
+ * @param claudeSessionId - The stored claude_session_id to validate.
92
+ * @param instanceId - The factory instance to search sessions for.
93
+ * @param slotIndex - The unit's slot index (for logging).
94
+ * @param fetchActiveSessions - Callback that returns active sessions for an instance.
95
+ * @returns { valid: true } if session found, { valid: false, reason } otherwise.
96
+ */
97
+ export async function validateSessionForResume(claudeSessionId, instanceId, slotIndex, fetchActiveSessions) {
98
+ try {
99
+ const sessions = await fetchActiveSessions(instanceId);
100
+ const match = sessions.find((s) => s.claudeSessionId === claudeSessionId);
101
+ if (!match) {
102
+ const reason = `Unit ${slotIndex}: claude_session_id "${claudeSessionId}" ` +
103
+ `not found in active sessions -- falling back to fresh spawn`;
104
+ console.warn(`${LOG_PREFIX} ${reason}`);
105
+ return { valid: false, reason };
106
+ }
107
+ return { valid: true, reason: 'session found in active sessions' };
108
+ }
109
+ catch (err) {
110
+ const reason = `Unit ${slotIndex}: session validation failed -- ` +
111
+ `falling back to fresh spawn: ${err.message}`;
112
+ console.warn(`${LOG_PREFIX} ${reason}`);
113
+ return { valid: false, reason };
114
+ }
115
+ }
116
+ // ============================================================================
117
+ // Gate failure feedback re-delivery
118
+ // ============================================================================
119
+ /**
120
+ * Consume pending gate failure feedback for a unit's assigned strategy.
121
+ *
122
+ * If the unit has an assigned strategy and state.gateFailureFeedback has
123
+ * stored feedback for it, returns the feedback and removes it from the map
124
+ * (but only when stdinAvailable is true -- otherwise the feedback is kept
125
+ * for the next spawn attempt).
126
+ *
127
+ * Returns the feedback string to send, or null if no feedback is pending
128
+ * or stdin is not available.
129
+ */
130
+ export function consumeGateFailureFeedback(state, strategyId, stdinAvailable) {
131
+ if (!strategyId)
132
+ return null;
133
+ const feedback = state.gateFailureFeedback.get(strategyId);
134
+ if (!feedback)
135
+ return null;
136
+ if (!stdinAvailable)
137
+ return null;
138
+ state.gateFailureFeedback.delete(strategyId);
139
+ return feedback;
140
+ }
141
+ //# sourceMappingURL=unit-session-lifecycle.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"unit-session-lifecycle.js","sourceRoot":"","sources":["../src/unit-session-lifecycle.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,30 @@
1
+ /**
2
+ * Execution unit session lifecycle -- spawn, exit handling, and termination.
3
+ *
4
+ * Each execution unit manages its own Claude Code session. The lifecycle is:
5
+ * assigned -> spawnUnitSession -> running -> (exit) -> idle
6
+ *
7
+ * Resume-vs-fresh decision: if the new strategy depends on the unit's
8
+ * previous strategy AND a claude_session_id exists, spawn with --resume.
9
+ * Otherwise start fresh.
10
+ *
11
+ * All communication with the session goes through a SessionCommunicationAdapter.
12
+ */
13
+ import type { ResourceGovernor } from '@telora/daemon-core';
14
+ import type { FactoryConfig, FactoryInstanceState, ExecutionUnitState } from './types.js';
15
+ import type { SessionCommunicationAdapter } from './session-adapter.js';
16
+ import type { UnitStrategyContext } from './unit-session-lifecycle.js';
17
+ export { shouldResumeSession, validateSessionForResume, terminateUnitSession, terminateAllUnits } from './unit-session-lifecycle.js';
18
+ export type { UnitStrategyContext } from './unit-session-lifecycle.js';
19
+ /**
20
+ * Spawn a Claude Code session for an execution unit.
21
+ *
22
+ * Creates a factory_sessions record linked to the unit, launches Claude Code
23
+ * with Agent Teams enabled and stream-json I/O, sets up signal parsing via
24
+ * a SessionCommunicationAdapter, and sends the initial team lead prompt.
25
+ *
26
+ * On process exit: unit returns to 'idle', governor slot released, session
27
+ * marked completed/failed.
28
+ */
29
+ export declare function spawnUnitSession(unit: ExecutionUnitState, strategy: UnitStrategyContext, state: FactoryInstanceState, config: FactoryConfig, governor?: ResourceGovernor | null): Promise<SessionCommunicationAdapter>;
30
+ //# sourceMappingURL=unit-session.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"unit-session.d.ts","sourceRoot":"","sources":["../src/unit-session.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;AAeH,OAAO,KAAK,EAAE,gBAAgB,EAAoB,MAAM,qBAAqB,CAAC;AAE9E,OAAO,KAAK,EACV,aAAa,EACb,oBAAoB,EACpB,kBAAkB,EACnB,MAAM,YAAY,CAAC;AAQpB,OAAO,KAAK,EAAE,2BAA2B,EAAE,MAAM,sBAAsB,CAAC;AAIxE,OAAO,KAAK,EAAE,mBAAmB,EAAE,MAAM,6BAA6B,CAAC;AAGvE,OAAO,EAAE,mBAAmB,EAAE,wBAAwB,EAAE,oBAAoB,EAAE,iBAAiB,EAAE,MAAM,6BAA6B,CAAC;AACrI,YAAY,EAAE,mBAAmB,EAAE,MAAM,6BAA6B,CAAC;AAQvE;;;;;;;;;GASG;AACH,wBAAsB,gBAAgB,CACpC,IAAI,EAAE,kBAAkB,EACxB,QAAQ,EAAE,mBAAmB,EAC7B,KAAK,EAAE,oBAAoB,EAC3B,MAAM,EAAE,aAAa,EACrB,QAAQ,CAAC,EAAE,gBAAgB,GAAG,IAAI,GACjC,OAAO,CAAC,2BAA2B,CAAC,CA+XtC"}
@@ -0,0 +1,370 @@
1
+ /**
2
+ * Execution unit session lifecycle -- spawn, exit handling, and termination.
3
+ *
4
+ * Each execution unit manages its own Claude Code session. The lifecycle is:
5
+ * assigned -> spawnUnitSession -> running -> (exit) -> idle
6
+ *
7
+ * Resume-vs-fresh decision: if the new strategy depends on the unit's
8
+ * previous strategy AND a claude_session_id exists, spawn with --resume.
9
+ * Otherwise start fresh.
10
+ *
11
+ * All communication with the session goes through a SessionCommunicationAdapter.
12
+ */
13
+ import { spawn } from 'node:child_process';
14
+ import { join } from 'node:path';
15
+ import { mkdirSync, existsSync } from 'node:fs';
16
+ import { buildStreamJsonArgs, stripClaudeCodeEnvVars, createLogStream, sendMessage, StreamJsonParser, ActivityTracker, buildOtelEnv, } from '@telora/daemon-core';
17
+ import { updateExecutionUnit } from './queries/execution-units.js';
18
+ import { createFactorySession, updateFactorySession } from './queries/sessions.js';
19
+ import { updateWorkUnitWorkflowStage } from './queries/work-units.js';
20
+ import { TokenSniffingTransform } from './queries/shared.js';
21
+ import { buildTeamLeadPrompt } from './team-prompt-builder.js';
22
+ import { McpAdapter } from './session-adapter.js';
23
+ import { getOrResolveWorkflow } from './workflow-transition.js';
24
+ import { buildWorkBatchDirective } from './team-prompt-builder.js';
25
+ import { shouldResumeSession, validateSessionForResume, terminateUnitSession, consumeGateFailureFeedback } from './unit-session-lifecycle.js';
26
+ // Re-export from lifecycle module (no daemon-core dep, so testable)
27
+ export { shouldResumeSession, validateSessionForResume, terminateUnitSession, terminateAllUnits } from './unit-session-lifecycle.js';
28
+ const LOG_PREFIX = '[unit-session]';
29
+ // ============================================================================
30
+ // Session spawning (TEL-2)
31
+ // ============================================================================
32
+ /**
33
+ * Spawn a Claude Code session for an execution unit.
34
+ *
35
+ * Creates a factory_sessions record linked to the unit, launches Claude Code
36
+ * with Agent Teams enabled and stream-json I/O, sets up signal parsing via
37
+ * a SessionCommunicationAdapter, and sends the initial team lead prompt.
38
+ *
39
+ * On process exit: unit returns to 'idle', governor slot released, session
40
+ * marked completed/failed.
41
+ */
42
+ export async function spawnUnitSession(unit, strategy, state, config, governor) {
43
+ const worktreePath = state.worktreePath;
44
+ if (!worktreePath) {
45
+ throw new Error(`${LOG_PREFIX} Instance ${state.instanceId} has no worktreePath -- ` +
46
+ 'cannot spawn unit session');
47
+ }
48
+ // Ensure log directory exists
49
+ if (!existsSync(config.logDir)) {
50
+ mkdirSync(config.logDir, { recursive: true });
51
+ }
52
+ // Log file paths
53
+ const timestamp = new Date().toISOString().replace(/[:.]/g, '-');
54
+ const logBaseName = `factory-${state.instanceId.slice(0, 8)}-unit${unit.slotIndex}-${timestamp}`;
55
+ const stdoutPath = join(config.logDir, `${logBaseName}.stdout.log`);
56
+ const stderrPath = join(config.logDir, `${logBaseName}.stderr.log`);
57
+ // Create session record in DB, linked to execution unit
58
+ const session = await createFactorySession({
59
+ instanceId: state.instanceId,
60
+ sessionType: 'builder',
61
+ workUnitId: null,
62
+ executionUnitId: unit.unitId,
63
+ stdoutPath,
64
+ stderrPath,
65
+ });
66
+ // Resume-vs-fresh decision
67
+ const decision = shouldResumeSession(unit, strategy);
68
+ let resumeClaudeSessionId = decision.resume ? unit.claudeSessionId : null;
69
+ // Validate the session exists and is not in a terminal state before resuming
70
+ if (resumeClaudeSessionId) {
71
+ const { getActiveSessionsForInstance } = await import('./queries/sessions.js');
72
+ const validation = await validateSessionForResume(resumeClaudeSessionId, state.instanceId, unit.slotIndex, getActiveSessionsForInstance);
73
+ if (!validation.valid) {
74
+ resumeClaudeSessionId = null;
75
+ unit.claudeSessionId = null;
76
+ }
77
+ }
78
+ if (!resumeClaudeSessionId) {
79
+ // Clear stale session ID for a fresh start
80
+ unit.claudeSessionId = null;
81
+ }
82
+ console.log(`${LOG_PREFIX} Unit ${unit.slotIndex}: ${decision.resume ? 'resuming' : 'fresh'} session ` +
83
+ `(${decision.reason}) for strategy "${strategy.strategyName}"`);
84
+ // Build Claude Code arguments
85
+ const args = [];
86
+ if (resumeClaudeSessionId) {
87
+ args.push('--resume', resumeClaudeSessionId);
88
+ }
89
+ args.push(...buildStreamJsonArgs({ mcpConfigPath: config.mcpConfigPath }));
90
+ args.push('--teammate-mode', 'in-process');
91
+ // Acquire a resource governor slot
92
+ let slotAcquired = false;
93
+ if (governor) {
94
+ await governor.acquireSlot('factory');
95
+ slotAcquired = true;
96
+ }
97
+ // Build spawn environment
98
+ const env = buildUnitEnv(config, state);
99
+ const proc = spawn(config.claudeCodePath, args, {
100
+ cwd: worktreePath,
101
+ env,
102
+ stdio: ['pipe', 'pipe', 'pipe'],
103
+ });
104
+ const pid = proc.pid;
105
+ if (pid === undefined) {
106
+ if (slotAcquired)
107
+ governor.releaseSlot('factory');
108
+ await updateFactorySession(session.id, {
109
+ status: 'failed',
110
+ endedAt: new Date().toISOString(),
111
+ });
112
+ throw new Error(`${LOG_PREFIX} Failed to spawn unit process -- pid is undefined`);
113
+ }
114
+ // Update unit state
115
+ unit.pid = pid;
116
+ unit.status = 'running';
117
+ unit.startedAt = new Date();
118
+ unit.previousStrategyId = strategy.strategyId;
119
+ // Update DB records
120
+ await Promise.all([
121
+ updateExecutionUnit(unit.unitId, { status: 'running' }),
122
+ updateFactorySession(session.id, {
123
+ status: 'running',
124
+ pid,
125
+ startedAt: new Date().toISOString(),
126
+ }),
127
+ ]);
128
+ // Pipe stderr to log file
129
+ const stderrStream = createLogStream(stderrPath);
130
+ proc.stderr?.pipe(stderrStream);
131
+ // Raw NDJSON stream log
132
+ const jsonlPath = join(config.logDir, `${logBaseName}.stream.jsonl`);
133
+ const jsonlStream = createLogStream(jsonlPath);
134
+ // Token-sniffing transform
135
+ const tokenParser = new TokenSniffingTransform();
136
+ proc.stdout?.pipe(tokenParser).pipe(jsonlStream);
137
+ // Set up StreamJsonParser
138
+ const streamParser = new StreamJsonParser();
139
+ if (proc.stdout) {
140
+ streamParser.attach(proc.stdout);
141
+ }
142
+ unit.streamParser = streamParser;
143
+ // Track stdout activity for signal silence watchdog
144
+ if (proc.stdout) {
145
+ proc.stdout.on('data', () => {
146
+ unit.lastActivityAt = new Date();
147
+ });
148
+ }
149
+ // Capture Claude session ID from init event
150
+ streamParser.on('init', (event) => {
151
+ unit.claudeSessionId = event.session_id;
152
+ updateFactorySession(session.id, {
153
+ claudeSessionId: event.session_id,
154
+ }).catch((err) => {
155
+ console.warn(`${LOG_PREFIX} Failed to persist Claude session ID for unit ${unit.slotIndex}:`, err.message);
156
+ });
157
+ // Re-deliver pending gate failure feedback if the unit's strategy has any.
158
+ // This ensures a respawned session knows what gate failures to fix.
159
+ const pendingFeedback = consumeGateFailureFeedback(state, unit.assignedStrategyId, !!proc.stdin);
160
+ if (pendingFeedback) {
161
+ sendMessage(proc.stdin, pendingFeedback);
162
+ console.log(`${LOG_PREFIX} Re-delivered gate feedback for strategy ${unit.assignedStrategyId} ` +
163
+ `to unit ${unit.slotIndex} on resume`);
164
+ }
165
+ });
166
+ // Activity tracker
167
+ const activityTracker = new ActivityTracker(session.id, async (snapshot) => {
168
+ await updateFactorySession(session.id, {
169
+ activitySummary: snapshot,
170
+ });
171
+ });
172
+ activityTracker.attach(streamParser);
173
+ unit.activityTracker = activityTracker;
174
+ // Wire narration
175
+ activityTracker.onNarration((text) => {
176
+ updateFactorySession(session.id, {
177
+ lastNarration: text,
178
+ lastNarrationAt: new Date().toISOString(),
179
+ }).catch((err) => {
180
+ console.warn(`${LOG_PREFIX} Failed to update narration for unit ${unit.slotIndex}:`, err.message);
181
+ });
182
+ });
183
+ // Create the MCP communication adapter
184
+ const adapter = new McpAdapter({
185
+ instanceId: state.instanceId,
186
+ stdin: proc.stdin ?? null,
187
+ sendMessageFn: sendMessage,
188
+ buildDirectiveFn: buildWorkBatchDirective,
189
+ });
190
+ unit.adapter = adapter;
191
+ unit.stdin = proc.stdin ?? null;
192
+ // Wire work unit completion through the adapter.
193
+ // The agent already set status='completed' via MCP tool call,
194
+ // so we only update the workflow stage here.
195
+ adapter.onWorkUnitComplete((workUnitId) => {
196
+ console.log(`${LOG_PREFIX} Unit ${unit.slotIndex}: work unit complete for ${workUnitId}`);
197
+ // Remove completed unit from pending set and reset/clear dispatch timer
198
+ unit.dispatchedWorkUnitIds.delete(workUnitId);
199
+ if (unit.dispatchedWorkUnitIds.size > 0) {
200
+ // Restart timeout clock for remaining pending work units
201
+ unit.dispatchedAt = new Date();
202
+ }
203
+ else {
204
+ // All dispatched units completed -- clear the timer
205
+ unit.dispatchedAt = null;
206
+ }
207
+ const completeUnit = async () => {
208
+ const wuWorkflow = await getOrResolveWorkflow('factory_work_unit');
209
+ if (wuWorkflow) {
210
+ const completedStage = wuWorkflow.stageByName.get('completed');
211
+ if (completedStage) {
212
+ await updateWorkUnitWorkflowStage(workUnitId, completedStage.id);
213
+ }
214
+ }
215
+ };
216
+ completeUnit().catch((err) => {
217
+ console.error(`${LOG_PREFIX} Failed to complete work unit ${workUnitId}:`, err.message);
218
+ });
219
+ });
220
+ // Wire result events for cost/token tracking + error detection
221
+ streamParser.on('result', (resultEvent) => {
222
+ const usage = resultEvent.usage;
223
+ const totalCost = resultEvent.total_cost_usd;
224
+ if (usage) {
225
+ const inputTokens = typeof usage.input_tokens === 'number' ? usage.input_tokens : 0;
226
+ const outputTokens = typeof usage.output_tokens === 'number' ? usage.output_tokens : 0;
227
+ unit.tokensUsed += inputTokens + outputTokens;
228
+ state.tokensUsed += inputTokens + outputTokens;
229
+ }
230
+ if (typeof totalCost === 'number') {
231
+ unit.costUsed += totalCost;
232
+ state.costUsed += totalCost;
233
+ }
234
+ // Detect error results
235
+ if (resultEvent.is_error === true) {
236
+ const subtype = resultEvent.subtype ?? 'unknown';
237
+ const errors = Array.isArray(resultEvent.errors) ? resultEvent.errors : [];
238
+ console.error(`${LOG_PREFIX} Unit ${unit.slotIndex} result error (${subtype}): ${errors.join('; ') || 'no details'}`);
239
+ terminateUnitSession(unit);
240
+ }
241
+ });
242
+ // Capture the strategy this session was spawned for. Used in the close handler
243
+ // to detect if the unit was eagerly re-assigned after gate pass, and skip
244
+ // overwriting the new assignment's state.
245
+ const sessionStrategyId = unit.assignedStrategyId;
246
+ // Handle process exit (TEL-4)
247
+ proc.on('close', (code) => {
248
+ if (slotAcquired)
249
+ governor.releaseSlot('factory');
250
+ // Null out process handles (safe regardless of assignment state)
251
+ unit.stdin = null;
252
+ unit.pid = null;
253
+ adapter.updateStdin(null);
254
+ console.log(`${LOG_PREFIX} Unit ${unit.slotIndex} session exited (code: ${code}, session: ${session.id})`);
255
+ const sessionStatus = code === 0 ? 'completed' : 'failed';
256
+ // Guard: if the unit has been eagerly released and re-assigned to a new
257
+ // strategy since this session was spawned, don't overwrite the new state.
258
+ if (unit.assignedStrategyId !== sessionStrategyId) {
259
+ console.log(`${LOG_PREFIX} Unit ${unit.slotIndex} was re-assigned since session start ` +
260
+ `-- skipping unit state reset`);
261
+ updateFactorySession(session.id, {
262
+ status: sessionStatus,
263
+ endedAt: new Date().toISOString(),
264
+ tokenCount: tokenParser.totalTokens || undefined,
265
+ costEstimate: tokenParser.usage?.totalCostUsd ?? undefined,
266
+ }).catch((err) => {
267
+ console.error(`${LOG_PREFIX} Failed to update session on unit ${unit.slotIndex} exit:`, err.message);
268
+ });
269
+ }
270
+ else {
271
+ // Normal path: release unit back to idle
272
+ unit.status = 'idle';
273
+ unit.assignedStrategyId = null;
274
+ unit.assignedAt = null;
275
+ unit.startedAt = null;
276
+ Promise.all([
277
+ updateExecutionUnit(unit.unitId, {
278
+ status: 'idle',
279
+ assignedStrategyId: null,
280
+ assignedAt: null,
281
+ }),
282
+ updateFactorySession(session.id, {
283
+ status: sessionStatus,
284
+ endedAt: new Date().toISOString(),
285
+ tokenCount: tokenParser.totalTokens || undefined,
286
+ costEstimate: tokenParser.usage?.totalCostUsd ?? undefined,
287
+ }),
288
+ ]).catch((err) => {
289
+ console.error(`${LOG_PREFIX} Failed to update records on unit ${unit.slotIndex} exit:`, err.message);
290
+ });
291
+ }
292
+ // Dispose adapter
293
+ adapter.dispose();
294
+ // Clean up log streams
295
+ stderrStream.end();
296
+ jsonlStream.end();
297
+ });
298
+ proc.on('error', (error) => {
299
+ if (slotAcquired)
300
+ governor.releaseSlot('factory');
301
+ unit.stdin = null;
302
+ unit.pid = null;
303
+ adapter.updateStdin(null);
304
+ console.error(`${LOG_PREFIX} Unit ${unit.slotIndex} process error:`, error.message);
305
+ // Same re-assignment guard as the close handler
306
+ if (unit.assignedStrategyId !== sessionStrategyId) {
307
+ updateFactorySession(session.id, {
308
+ status: 'failed',
309
+ endedAt: new Date().toISOString(),
310
+ }).catch((err) => {
311
+ console.error(`${LOG_PREFIX} Failed to mark session ${session.id} as failed:`, err.message);
312
+ });
313
+ }
314
+ else {
315
+ unit.status = 'idle';
316
+ unit.assignedStrategyId = null;
317
+ unit.assignedAt = null;
318
+ unit.startedAt = null;
319
+ Promise.all([
320
+ updateExecutionUnit(unit.unitId, {
321
+ status: 'idle',
322
+ assignedStrategyId: null,
323
+ assignedAt: null,
324
+ }),
325
+ updateFactorySession(session.id, {
326
+ status: 'failed',
327
+ endedAt: new Date().toISOString(),
328
+ }),
329
+ ]).catch((err) => {
330
+ console.error(`${LOG_PREFIX} Failed to update unit/session state for unit ${unit.slotIndex}:`, err.message);
331
+ });
332
+ }
333
+ adapter.dispose();
334
+ stderrStream.end();
335
+ jsonlStream.end();
336
+ });
337
+ // Send initial team lead prompt (only if not resuming)
338
+ if (!resumeClaudeSessionId && proc.stdin) {
339
+ const initialPrompt = buildTeamLeadPrompt(state);
340
+ sendMessage(proc.stdin, initialPrompt);
341
+ }
342
+ console.log(`${LOG_PREFIX} Spawned unit ${unit.slotIndex} session ` +
343
+ `(session: ${session.id}, pid: ${pid}, strategy: "${strategy.strategyName}")`);
344
+ return adapter;
345
+ }
346
+ // ============================================================================
347
+ // Environment builder
348
+ // ============================================================================
349
+ /**
350
+ * Build the spawn environment for a unit session.
351
+ */
352
+ function buildUnitEnv(config, state) {
353
+ const env = stripClaudeCodeEnvVars({
354
+ ...process.env,
355
+ CLAUDE_CODE_EXPERIMENTAL_AGENT_TEAMS: '1',
356
+ TELORA_TRACKER_ID: config.trackerId,
357
+ }, { preserve: ['CLAUDE_CODE_EXPERIMENTAL_AGENT_TEAMS'] });
358
+ const otelEnv = buildOtelEnv({
359
+ enabled: config.telemetry.enabled,
360
+ port: config.telemetry.port,
361
+ resourceAttributes: {
362
+ 'telora.org_id': config.organizationId,
363
+ 'telora.instance_id': state.instanceId,
364
+ 'telora.spec_id': state.specId ?? undefined,
365
+ },
366
+ });
367
+ Object.assign(env, otelEnv);
368
+ return env;
369
+ }
370
+ //# sourceMappingURL=unit-session.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"unit-session.js","sourceRoot":"","sources":["../src/unit-session.ts"],"names":[],"mappings":"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"}