@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,322 @@
1
+ /**
2
+ * Resource limit checking for factory instances.
3
+ *
4
+ * Enforces blueprint resource limits (token budget, wall-clock time,
5
+ * per-unit iterations, work unit count) and returns a structured result
6
+ * indicating whether any limit has been exceeded.
7
+ *
8
+ * Checks are designed to run after each session completion and gate
9
+ * evaluation. All checks are based on the blueprint configuration --
10
+ * null limits are treated as unlimited.
11
+ */
12
+ import { getInstanceWorkUnits } from './queries/work-units.js';
13
+ import { getActiveSessionsForInstance } from './queries/sessions.js';
14
+ // ============================================================================
15
+ // Main entry point
16
+ // ============================================================================
17
+ /**
18
+ * Check all resource limits for a factory instance.
19
+ *
20
+ * Evaluates four resource limits defined in the blueprint:
21
+ * 1. Token budget: aggregate tokens across all factory sessions
22
+ * 2. Wall-clock time: elapsed time since instance started
23
+ * 3. Iteration count: per-work-unit iteration limit
24
+ * 4. Work unit count: total work units vs max_work_units
25
+ *
26
+ * Returns immediately on the first exceeded limit found. All limits
27
+ * configured as null in the blueprint are treated as unlimited.
28
+ *
29
+ * @param instanceState - The in-memory state of the factory instance.
30
+ * @returns A result indicating whether any limit has been exceeded.
31
+ */
32
+ export async function checkResourceLimits(instanceState) {
33
+ const blueprint = instanceState.blueprint;
34
+ const exceeded = [];
35
+ // Check 1: Token budget
36
+ const tokenResult = await checkTokenBudget(instanceState, blueprint);
37
+ if (tokenResult) {
38
+ exceeded.push(tokenResult);
39
+ }
40
+ // Check 1b: Cost budget
41
+ const costResult = checkCostBudget(instanceState, blueprint);
42
+ if (costResult) {
43
+ exceeded.push(costResult);
44
+ }
45
+ // Check 2: Wall-clock time
46
+ const wallClockResult = checkWallClockTime(instanceState, blueprint);
47
+ if (wallClockResult) {
48
+ exceeded.push(wallClockResult);
49
+ }
50
+ // Check 3: Per-work-unit iteration count
51
+ const iterationResults = await checkIterationLimits(instanceState, blueprint);
52
+ exceeded.push(...iterationResults);
53
+ // Check 4: Total work unit count
54
+ const workUnitCountResult = await checkWorkUnitCount(instanceState, blueprint);
55
+ if (workUnitCountResult) {
56
+ exceeded.push(workUnitCountResult);
57
+ }
58
+ // Check 5: Instance iteration limit (completion gate cycles)
59
+ const instanceIterResult = checkInstanceIterations(instanceState, blueprint);
60
+ if (instanceIterResult) {
61
+ exceeded.push(instanceIterResult);
62
+ }
63
+ if (exceeded.length === 0) {
64
+ return { exceeded: false, reason: '', details: [] };
65
+ }
66
+ // Build a combined reason string from all exceeded limits
67
+ const reasons = exceeded.map((d) => d.description);
68
+ return {
69
+ exceeded: true,
70
+ reason: reasons.join('; '),
71
+ details: exceeded,
72
+ };
73
+ }
74
+ // ============================================================================
75
+ // Individual limit checks
76
+ // ============================================================================
77
+ /**
78
+ * Check whether the aggregate token usage across all sessions exceeds
79
+ * the blueprint's max_token_budget.
80
+ *
81
+ * Fetches active sessions for the instance and sums their token_count
82
+ * values. Sessions with null token_count are treated as 0.
83
+ */
84
+ async function checkTokenBudget(instanceState, blueprint) {
85
+ if (blueprint.maxTokenBudget === null) {
86
+ return null;
87
+ }
88
+ const sessions = await getActiveSessionsForInstance(instanceState.instanceId);
89
+ const totalTokens = sumSessionTokens(sessions);
90
+ if (totalTokens > blueprint.maxTokenBudget) {
91
+ return {
92
+ limitType: 'token_budget',
93
+ currentValue: totalTokens,
94
+ maxValue: blueprint.maxTokenBudget,
95
+ description: `Token budget exceeded: ${totalTokens} tokens used ` +
96
+ `(limit: ${blueprint.maxTokenBudget})`,
97
+ };
98
+ }
99
+ return null;
100
+ }
101
+ /**
102
+ * Check whether the cumulative cost across all sessions exceeds
103
+ * the blueprint's max_cost_budget (denominated in dollars).
104
+ *
105
+ * Uses the in-memory costUsed counter which is updated after each
106
+ * session completes.
107
+ */
108
+ function checkCostBudget(instanceState, blueprint) {
109
+ if (blueprint.maxCostBudget === null) {
110
+ return null;
111
+ }
112
+ const currentCost = instanceState.costUsed;
113
+ if (currentCost > blueprint.maxCostBudget) {
114
+ return {
115
+ limitType: 'cost_budget',
116
+ currentValue: Math.round(currentCost * 100) / 100,
117
+ maxValue: blueprint.maxCostBudget,
118
+ description: `Cost budget exceeded: $${currentCost.toFixed(2)} spent ` +
119
+ `(limit: $${blueprint.maxCostBudget.toFixed(2)})`,
120
+ };
121
+ }
122
+ return null;
123
+ }
124
+ /**
125
+ * Check whether the wall-clock elapsed time exceeds the blueprint's
126
+ * max_wall_clock_hours.
127
+ *
128
+ * Uses the in-memory startedAt timestamp for the instance. This avoids
129
+ * an extra API call since the lifecycle manager always sets startedAt
130
+ * when the instance is picked up.
131
+ */
132
+ function checkWallClockTime(instanceState, blueprint) {
133
+ if (blueprint.maxWallClockHours === null) {
134
+ return null;
135
+ }
136
+ const elapsedMs = Date.now() - instanceState.startedAt.getTime();
137
+ const elapsedHours = elapsedMs / (1000 * 60 * 60);
138
+ const maxHours = blueprint.maxWallClockHours;
139
+ if (elapsedHours > maxHours) {
140
+ return {
141
+ limitType: 'wall_clock',
142
+ currentValue: Math.round(elapsedHours * 100) / 100,
143
+ maxValue: maxHours,
144
+ description: `Wall-clock time exceeded: ${(elapsedHours).toFixed(2)} hours elapsed ` +
145
+ `(limit: ${maxHours} hours)`,
146
+ };
147
+ }
148
+ return null;
149
+ }
150
+ /**
151
+ * Check whether any work unit has exceeded the per-unit iteration limit
152
+ * defined in the blueprint's max_iterations_per_work_unit.
153
+ *
154
+ * Returns a detail entry for each work unit that has exceeded the limit.
155
+ */
156
+ async function checkIterationLimits(instanceState, blueprint) {
157
+ if (blueprint.maxIterationsPerWorkUnit === null) {
158
+ return [];
159
+ }
160
+ const maxIterations = blueprint.maxIterationsPerWorkUnit;
161
+ const workUnits = await getInstanceWorkUnits(instanceState.instanceId);
162
+ const exceeded = [];
163
+ for (const unit of workUnits) {
164
+ if (unit.iterationCount >= maxIterations) {
165
+ exceeded.push({
166
+ limitType: 'iteration_count',
167
+ currentValue: unit.iterationCount,
168
+ maxValue: maxIterations,
169
+ description: `Work unit "${unit.title}" (${unit.id}) exceeded iteration limit: ` +
170
+ `${unit.iterationCount} iterations (limit: ${maxIterations})`,
171
+ });
172
+ }
173
+ }
174
+ return exceeded;
175
+ }
176
+ /**
177
+ * Check whether the total number of work units exceeds the blueprint's
178
+ * max_work_units limit.
179
+ */
180
+ async function checkWorkUnitCount(instanceState, blueprint) {
181
+ if (blueprint.maxWorkUnits === null) {
182
+ return null;
183
+ }
184
+ const workUnits = await getInstanceWorkUnits(instanceState.instanceId);
185
+ const count = workUnits.length;
186
+ if (count > blueprint.maxWorkUnits) {
187
+ return {
188
+ limitType: 'work_unit_count',
189
+ currentValue: count,
190
+ maxValue: blueprint.maxWorkUnits,
191
+ description: `Work unit count exceeded: ${count} work units ` +
192
+ `(limit: ${blueprint.maxWorkUnits})`,
193
+ };
194
+ }
195
+ return null;
196
+ }
197
+ /**
198
+ * Check whether the instance has exceeded its completion gate iteration limit.
199
+ *
200
+ * Uses blueprint.maxInstanceIterations. Null means no limit (skip check).
201
+ * This ensures the instance escalates when iteration limits are hit, giving
202
+ * the human a chance to extend the limit or review progress.
203
+ */
204
+ function checkInstanceIterations(instanceState, blueprint) {
205
+ const maxIterations = blueprint.maxInstanceIterations;
206
+ if (maxIterations === null)
207
+ return null;
208
+ if (instanceState.completionGateIterations >= maxIterations) {
209
+ return {
210
+ limitType: 'instance_iterations',
211
+ currentValue: instanceState.completionGateIterations,
212
+ maxValue: maxIterations,
213
+ description: `Instance iteration limit reached: ${instanceState.completionGateIterations} cycles ` +
214
+ `(limit: ${maxIterations})`,
215
+ };
216
+ }
217
+ return null;
218
+ }
219
+ // ============================================================================
220
+ // Pure helpers
221
+ // ============================================================================
222
+ /**
223
+ * Sum token counts across a list of factory sessions.
224
+ * Sessions with null token_count are treated as 0.
225
+ */
226
+ export function sumSessionTokens(sessions) {
227
+ return sessions.reduce((sum, s) => sum + (s.tokenCount ?? 0), 0);
228
+ }
229
+ /**
230
+ * Check resource limits using pre-fetched data (no API calls).
231
+ *
232
+ * This is useful when the caller has already fetched work units and
233
+ * sessions and wants to avoid redundant API calls. Performs the same
234
+ * checks as checkResourceLimits but operates on provided data.
235
+ */
236
+ export function checkResourceLimitsSync(instanceState, sessions, workUnits) {
237
+ const blueprint = instanceState.blueprint;
238
+ const exceeded = [];
239
+ // Check 1: Token budget
240
+ if (blueprint.maxTokenBudget !== null) {
241
+ const totalTokens = sumSessionTokens(sessions);
242
+ if (totalTokens > blueprint.maxTokenBudget) {
243
+ exceeded.push({
244
+ limitType: 'token_budget',
245
+ currentValue: totalTokens,
246
+ maxValue: blueprint.maxTokenBudget,
247
+ description: `Token budget exceeded: ${totalTokens} tokens used ` +
248
+ `(limit: ${blueprint.maxTokenBudget})`,
249
+ });
250
+ }
251
+ }
252
+ // Check 1b: Cost budget
253
+ if (blueprint.maxCostBudget !== null) {
254
+ const currentCost = instanceState.costUsed;
255
+ if (currentCost > blueprint.maxCostBudget) {
256
+ exceeded.push({
257
+ limitType: 'cost_budget',
258
+ currentValue: Math.round(currentCost * 100) / 100,
259
+ maxValue: blueprint.maxCostBudget,
260
+ description: `Cost budget exceeded: $${currentCost.toFixed(2)} spent ` +
261
+ `(limit: $${blueprint.maxCostBudget.toFixed(2)})`,
262
+ });
263
+ }
264
+ }
265
+ // Check 2: Wall-clock time
266
+ if (blueprint.maxWallClockHours !== null) {
267
+ const elapsedMs = Date.now() - instanceState.startedAt.getTime();
268
+ const elapsedHours = elapsedMs / (1000 * 60 * 60);
269
+ if (elapsedHours > blueprint.maxWallClockHours) {
270
+ exceeded.push({
271
+ limitType: 'wall_clock',
272
+ currentValue: Math.round(elapsedHours * 100) / 100,
273
+ maxValue: blueprint.maxWallClockHours,
274
+ description: `Wall-clock time exceeded: ${elapsedHours.toFixed(2)} hours elapsed ` +
275
+ `(limit: ${blueprint.maxWallClockHours} hours)`,
276
+ });
277
+ }
278
+ }
279
+ // Check 3: Per-work-unit iteration count
280
+ if (blueprint.maxIterationsPerWorkUnit !== null) {
281
+ const maxIterations = blueprint.maxIterationsPerWorkUnit;
282
+ for (const unit of workUnits) {
283
+ if (unit.iterationCount >= maxIterations) {
284
+ exceeded.push({
285
+ limitType: 'iteration_count',
286
+ currentValue: unit.iterationCount,
287
+ maxValue: maxIterations,
288
+ description: `Work unit "${unit.title}" (${unit.id}) exceeded iteration limit: ` +
289
+ `${unit.iterationCount} iterations (limit: ${maxIterations})`,
290
+ });
291
+ }
292
+ }
293
+ }
294
+ // Check 4: Total work unit count
295
+ if (blueprint.maxWorkUnits !== null) {
296
+ const count = workUnits.length;
297
+ if (count > blueprint.maxWorkUnits) {
298
+ exceeded.push({
299
+ limitType: 'work_unit_count',
300
+ currentValue: count,
301
+ maxValue: blueprint.maxWorkUnits,
302
+ description: `Work unit count exceeded: ${count} work units ` +
303
+ `(limit: ${blueprint.maxWorkUnits})`,
304
+ });
305
+ }
306
+ }
307
+ // Check 5: Instance iteration limit (completion gate cycles)
308
+ const instanceIterResult = checkInstanceIterations(instanceState, blueprint);
309
+ if (instanceIterResult) {
310
+ exceeded.push(instanceIterResult);
311
+ }
312
+ if (exceeded.length === 0) {
313
+ return { exceeded: false, reason: '', details: [] };
314
+ }
315
+ const reasons = exceeded.map((d) => d.description);
316
+ return {
317
+ exceeded: true,
318
+ reason: reasons.join('; '),
319
+ details: exceeded,
320
+ };
321
+ }
322
+ //# sourceMappingURL=resource-limits.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"resource-limits.js","sourceRoot":"","sources":["../src/resource-limits.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,98 @@
1
+ /**
2
+ * DAG-aware execution unit scheduler.
3
+ *
4
+ * Each poll cycle, the scheduler examines the strategy DAG to determine
5
+ * which strategies have all upstream dependencies completed. For each
6
+ * ready strategy, it assigns an available (idle) execution unit.
7
+ *
8
+ * The core algorithm is a pure function (computeAssignments) for testability.
9
+ * The IO wrapper (runSchedulerCycle) handles DB queries and atomic updates.
10
+ */
11
+ import type { ExecutionUnitStatus } from './types.js';
12
+ import type { PersistedStrategy, StrategyExecutionStatus } from './strategy-design.js';
13
+ /** Minimal strategy info needed by the scheduler. */
14
+ export interface SchedulerStrategy {
15
+ id: string;
16
+ name: string;
17
+ executionStatus: StrategyExecutionStatus | null;
18
+ dependsOn: string[];
19
+ priorityRank: number;
20
+ }
21
+ /** Minimal execution unit info needed by the scheduler. */
22
+ export interface SchedulerUnit {
23
+ id: string;
24
+ slotIndex: number;
25
+ status: ExecutionUnitStatus;
26
+ assignedStrategyId: string | null;
27
+ }
28
+ /** A single assignment produced by the scheduler. */
29
+ export interface SchedulerAssignment {
30
+ unitId: string;
31
+ strategyId: string;
32
+ }
33
+ /**
34
+ * Compute strategy-to-unit assignments.
35
+ *
36
+ * Pure function -- no DB calls, no side effects. Takes the current state
37
+ * of strategies and execution units and returns the list of new assignments.
38
+ *
39
+ * Eligible strategies: executionStatus is 'pending' AND all dependsOn
40
+ * strategies have executionStatus 'completed'.
41
+ *
42
+ * Idle units: status is 'idle'.
43
+ *
44
+ * Matching: assign eligible strategies to idle units in priorityRank order
45
+ * (lower rank = higher priority). If more eligible strategies than idle units,
46
+ * only assign what fits.
47
+ */
48
+ export declare function computeAssignments(strategies: SchedulerStrategy[], units: SchedulerUnit[]): SchedulerAssignment[];
49
+ /** Dependencies injected into runSchedulerCycle for testability. */
50
+ export interface SchedulerDeps {
51
+ getStrategies: (instanceId: string) => Promise<PersistedStrategy[]>;
52
+ getUnits: (instanceId: string) => Promise<SchedulerUnit[]>;
53
+ assignUnit: (unitId: string, strategyId: string) => Promise<{
54
+ id: string;
55
+ } | null>;
56
+ updateStrategyStatus: (strategyId: string, status: StrategyExecutionStatus) => Promise<void>;
57
+ }
58
+ /** Result of a single scheduler cycle. */
59
+ export interface SchedulerCycleResult {
60
+ /** Assignments that were successfully applied. */
61
+ assignments: SchedulerAssignment[];
62
+ /** Number of eligible strategies that couldn't be assigned (no idle units). */
63
+ waitingStrategies: number;
64
+ }
65
+ /**
66
+ * Run one scheduler cycle for a factory instance.
67
+ *
68
+ * Fetches strategies and execution units from DB, computes assignments,
69
+ * then applies each assignment using an atomic conditional update.
70
+ *
71
+ * If the conditional update returns null (unit was claimed by another cycle),
72
+ * the assignment is skipped and logged.
73
+ */
74
+ export declare function runSchedulerCycle(instanceId: string, deps: SchedulerDeps): Promise<SchedulerCycleResult>;
75
+ /**
76
+ * Release the execution unit assigned to a strategy back to idle.
77
+ *
78
+ * Called when a strategy reaches a terminal state (completed via gates,
79
+ * or failed). Clears assignedStrategyId, sets status to 'idle' in both
80
+ * DB and in-memory state. Preserves claudeSessionId for potential resume.
81
+ *
82
+ * @returns true if a unit was found and released, false otherwise.
83
+ */
84
+ export declare function releaseUnitForStrategy(state: {
85
+ executionUnits: Map<string, {
86
+ unitId: string;
87
+ assignedStrategyId: string | null;
88
+ assignedAt: Date | null;
89
+ status: ExecutionUnitStatus;
90
+ claudeSessionId: string | null;
91
+ }>;
92
+ }, strategyId: string): Promise<boolean>;
93
+ /**
94
+ * Create the default SchedulerDeps using real query functions.
95
+ * Used by the instance lifecycle to wire the scheduler.
96
+ */
97
+ export declare function createSchedulerDeps(): SchedulerDeps;
98
+ //# sourceMappingURL=scheduler.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"scheduler.d.ts","sourceRoot":"","sources":["../src/scheduler.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AAEH,OAAO,KAAK,EAAE,mBAAmB,EAAE,MAAM,YAAY,CAAC;AACtD,OAAO,KAAK,EAAE,iBAAiB,EAAE,uBAAuB,EAAE,MAAM,sBAAsB,CAAC;AAQvF,qDAAqD;AACrD,MAAM,WAAW,iBAAiB;IAChC,EAAE,EAAE,MAAM,CAAC;IACX,IAAI,EAAE,MAAM,CAAC;IACb,eAAe,EAAE,uBAAuB,GAAG,IAAI,CAAC;IAChD,SAAS,EAAE,MAAM,EAAE,CAAC;IACpB,YAAY,EAAE,MAAM,CAAC;CACtB;AAED,2DAA2D;AAC3D,MAAM,WAAW,aAAa;IAC5B,EAAE,EAAE,MAAM,CAAC;IACX,SAAS,EAAE,MAAM,CAAC;IAClB,MAAM,EAAE,mBAAmB,CAAC;IAC5B,kBAAkB,EAAE,MAAM,GAAG,IAAI,CAAC;CACnC;AAED,qDAAqD;AACrD,MAAM,WAAW,mBAAmB;IAClC,MAAM,EAAE,MAAM,CAAC;IACf,UAAU,EAAE,MAAM,CAAC;CACpB;AAMD;;;;;;;;;;;;;;GAcG;AACH,wBAAgB,kBAAkB,CAChC,UAAU,EAAE,iBAAiB,EAAE,EAC/B,KAAK,EAAE,aAAa,EAAE,GACrB,mBAAmB,EAAE,CAgCvB;AAMD,oEAAoE;AACpE,MAAM,WAAW,aAAa;IAC5B,aAAa,EAAE,CAAC,UAAU,EAAE,MAAM,KAAK,OAAO,CAAC,iBAAiB,EAAE,CAAC,CAAC;IACpE,QAAQ,EAAE,CAAC,UAAU,EAAE,MAAM,KAAK,OAAO,CAAC,aAAa,EAAE,CAAC,CAAC;IAC3D,UAAU,EAAE,CAAC,MAAM,EAAE,MAAM,EAAE,UAAU,EAAE,MAAM,KAAK,OAAO,CAAC;QAAE,EAAE,EAAE,MAAM,CAAA;KAAE,GAAG,IAAI,CAAC,CAAC;IACnF,oBAAoB,EAAE,CAAC,UAAU,EAAE,MAAM,EAAE,MAAM,EAAE,uBAAuB,KAAK,OAAO,CAAC,IAAI,CAAC,CAAC;CAC9F;AAED,0CAA0C;AAC1C,MAAM,WAAW,oBAAoB;IACnC,kDAAkD;IAClD,WAAW,EAAE,mBAAmB,EAAE,CAAC;IACnC,+EAA+E;IAC/E,iBAAiB,EAAE,MAAM,CAAC;CAC3B;AAED;;;;;;;;GAQG;AACH,wBAAsB,iBAAiB,CACrC,UAAU,EAAE,MAAM,EAClB,IAAI,EAAE,aAAa,GAClB,OAAO,CAAC,oBAAoB,CAAC,CAqF/B;AAMD;;;;;;;;GAQG;AACH,wBAAsB,sBAAsB,CAC1C,KAAK,EAAE;IAAE,cAAc,EAAE,GAAG,CAAC,MAAM,EAAE;QAAE,MAAM,EAAE,MAAM,CAAC;QAAC,kBAAkB,EAAE,MAAM,GAAG,IAAI,CAAC;QAAC,UAAU,EAAE,IAAI,GAAG,IAAI,CAAC;QAAC,MAAM,EAAE,mBAAmB,CAAC;QAAC,eAAe,EAAE,MAAM,GAAG,IAAI,CAAA;KAAE,CAAC,CAAA;CAAE,EACnL,UAAU,EAAE,MAAM,GACjB,OAAO,CAAC,OAAO,CAAC,CAgClB;AAMD;;;GAGG;AACH,wBAAgB,mBAAmB,IAAI,aAAa,CAoBnD"}
@@ -0,0 +1,203 @@
1
+ /**
2
+ * DAG-aware execution unit scheduler.
3
+ *
4
+ * Each poll cycle, the scheduler examines the strategy DAG to determine
5
+ * which strategies have all upstream dependencies completed. For each
6
+ * ready strategy, it assigns an available (idle) execution unit.
7
+ *
8
+ * The core algorithm is a pure function (computeAssignments) for testability.
9
+ * The IO wrapper (runSchedulerCycle) handles DB queries and atomic updates.
10
+ */
11
+ const LOG_PREFIX = '[scheduler]';
12
+ // ============================================================================
13
+ // Pure scheduling algorithm
14
+ // ============================================================================
15
+ /**
16
+ * Compute strategy-to-unit assignments.
17
+ *
18
+ * Pure function -- no DB calls, no side effects. Takes the current state
19
+ * of strategies and execution units and returns the list of new assignments.
20
+ *
21
+ * Eligible strategies: executionStatus is 'pending' AND all dependsOn
22
+ * strategies have executionStatus 'completed'.
23
+ *
24
+ * Idle units: status is 'idle'.
25
+ *
26
+ * Matching: assign eligible strategies to idle units in priorityRank order
27
+ * (lower rank = higher priority). If more eligible strategies than idle units,
28
+ * only assign what fits.
29
+ */
30
+ export function computeAssignments(strategies, units) {
31
+ // Build a status lookup for fast dependency checking
32
+ const statusById = new Map();
33
+ for (const s of strategies) {
34
+ statusById.set(s.id, s.executionStatus);
35
+ }
36
+ // Find eligible strategies: pending + all deps completed
37
+ const eligible = strategies
38
+ .filter((s) => {
39
+ if (s.executionStatus !== 'pending')
40
+ return false;
41
+ return s.dependsOn.every((depId) => statusById.get(depId) === 'completed');
42
+ })
43
+ .sort((a, b) => a.priorityRank - b.priorityRank);
44
+ // Find idle units, sorted by slot_index for deterministic assignment
45
+ const idle = units
46
+ .filter((u) => u.status === 'idle')
47
+ .sort((a, b) => a.slotIndex - b.slotIndex);
48
+ // Match eligible strategies to idle units
49
+ const assignments = [];
50
+ const assignCount = Math.min(eligible.length, idle.length);
51
+ for (let i = 0; i < assignCount; i++) {
52
+ assignments.push({
53
+ unitId: idle[i].id,
54
+ strategyId: eligible[i].id,
55
+ });
56
+ }
57
+ return assignments;
58
+ }
59
+ /**
60
+ * Run one scheduler cycle for a factory instance.
61
+ *
62
+ * Fetches strategies and execution units from DB, computes assignments,
63
+ * then applies each assignment using an atomic conditional update.
64
+ *
65
+ * If the conditional update returns null (unit was claimed by another cycle),
66
+ * the assignment is skipped and logged.
67
+ */
68
+ export async function runSchedulerCycle(instanceId, deps) {
69
+ // Fetch current state
70
+ const strategies = await deps.getStrategies(instanceId);
71
+ const units = await deps.getUnits(instanceId);
72
+ // Map to scheduler types
73
+ const schedulerStrategies = strategies.map((s) => ({
74
+ id: s.id,
75
+ name: s.name,
76
+ executionStatus: s.executionStatus,
77
+ dependsOn: s.dependsOn,
78
+ priorityRank: s.priorityRank,
79
+ }));
80
+ const schedulerUnits = units.map((u) => ({
81
+ id: u.id,
82
+ slotIndex: u.slotIndex,
83
+ status: u.status,
84
+ assignedStrategyId: u.assignedStrategyId,
85
+ }));
86
+ // Compute assignments
87
+ const planned = computeAssignments(schedulerStrategies, schedulerUnits);
88
+ if (planned.length === 0) {
89
+ // Count how many strategies are eligible but can't be assigned
90
+ const eligibleCount = schedulerStrategies.filter((s) => {
91
+ if (s.executionStatus !== 'pending')
92
+ return false;
93
+ const statusById = new Map(schedulerStrategies.map((st) => [st.id, st.executionStatus]));
94
+ return s.dependsOn.every((depId) => statusById.get(depId) === 'completed');
95
+ }).length;
96
+ const idleCount = schedulerUnits.filter((u) => u.status === 'idle').length;
97
+ const waitingStrategies = Math.max(0, eligibleCount - idleCount);
98
+ return { assignments: [], waitingStrategies };
99
+ }
100
+ // Apply assignments atomically
101
+ const successfulAssignments = [];
102
+ const strategyNameById = new Map(strategies.map((s) => [s.id, s.name]));
103
+ for (const assignment of planned) {
104
+ const result = await deps.assignUnit(assignment.unitId, assignment.strategyId);
105
+ if (!result) {
106
+ // Unit was claimed by another cycle -- skip
107
+ console.log(`${LOG_PREFIX} Unit ${assignment.unitId} was already claimed -- skipping assignment ` +
108
+ `for strategy "${strategyNameById.get(assignment.strategyId) ?? assignment.strategyId}"`);
109
+ continue;
110
+ }
111
+ // Update strategy execution_status to in_progress
112
+ try {
113
+ await deps.updateStrategyStatus(assignment.strategyId, 'in_progress');
114
+ }
115
+ catch (err) {
116
+ console.error(`${LOG_PREFIX} Failed to update strategy ${assignment.strategyId} to in_progress: ` +
117
+ `${err.message}`);
118
+ // Assignment succeeded in DB but status update failed -- still count it
119
+ }
120
+ successfulAssignments.push(assignment);
121
+ console.log(`${LOG_PREFIX} Assigned strategy "${strategyNameById.get(assignment.strategyId) ?? assignment.strategyId}" ` +
122
+ `to unit ${assignment.unitId}`);
123
+ }
124
+ // Count waiting strategies
125
+ const assignedStrategyIds = new Set(successfulAssignments.map((a) => a.strategyId));
126
+ const eligibleAfter = schedulerStrategies.filter((s) => {
127
+ if (s.executionStatus !== 'pending')
128
+ return false;
129
+ if (assignedStrategyIds.has(s.id))
130
+ return false;
131
+ const statusById = new Map(schedulerStrategies.map((st) => [st.id, st.executionStatus]));
132
+ return s.dependsOn.every((depId) => statusById.get(depId) === 'completed');
133
+ }).length;
134
+ return {
135
+ assignments: successfulAssignments,
136
+ waitingStrategies: eligibleAfter,
137
+ };
138
+ }
139
+ // ============================================================================
140
+ // Unit release
141
+ // ============================================================================
142
+ /**
143
+ * Release the execution unit assigned to a strategy back to idle.
144
+ *
145
+ * Called when a strategy reaches a terminal state (completed via gates,
146
+ * or failed). Clears assignedStrategyId, sets status to 'idle' in both
147
+ * DB and in-memory state. Preserves claudeSessionId for potential resume.
148
+ *
149
+ * @returns true if a unit was found and released, false otherwise.
150
+ */
151
+ export async function releaseUnitForStrategy(state, strategyId) {
152
+ // Find the unit assigned to this strategy
153
+ let targetUnit = null;
154
+ for (const unit of state.executionUnits.values()) {
155
+ if (unit.assignedStrategyId === strategyId) {
156
+ targetUnit = unit;
157
+ break;
158
+ }
159
+ }
160
+ if (!targetUnit) {
161
+ console.log(`${LOG_PREFIX} No execution unit found for strategy ${strategyId} -- skipping release`);
162
+ return false;
163
+ }
164
+ // Release in DB
165
+ const { releaseExecutionUnit } = await import('./queries/execution-units.js');
166
+ await releaseExecutionUnit(targetUnit.unitId);
167
+ // Update in-memory state
168
+ targetUnit.assignedStrategyId = null;
169
+ targetUnit.assignedAt = null;
170
+ targetUnit.status = 'idle';
171
+ console.log(`${LOG_PREFIX} Released unit ${targetUnit.unitId} (strategy ${strategyId} -> idle)` +
172
+ (targetUnit.claudeSessionId ? ` [session preserved for resume]` : ''));
173
+ return true;
174
+ }
175
+ // ============================================================================
176
+ // Default dependencies
177
+ // ============================================================================
178
+ /**
179
+ * Create the default SchedulerDeps using real query functions.
180
+ * Used by the instance lifecycle to wire the scheduler.
181
+ */
182
+ export function createSchedulerDeps() {
183
+ // Lazy imports to avoid circular dependencies
184
+ return {
185
+ getStrategies: async (instanceId) => {
186
+ const { getStrategiesByFactoryInstance } = await import('./strategy-design.js');
187
+ return getStrategiesByFactoryInstance(instanceId);
188
+ },
189
+ getUnits: async (instanceId) => {
190
+ const { getExecutionUnitsByInstance } = await import('./queries/execution-units.js');
191
+ return getExecutionUnitsByInstance(instanceId);
192
+ },
193
+ assignUnit: async (unitId, strategyId) => {
194
+ const { assignExecutionUnit } = await import('./queries/execution-units.js');
195
+ return assignExecutionUnit(unitId, strategyId);
196
+ },
197
+ updateStrategyStatus: async (strategyId, status) => {
198
+ const { updateStrategyExecutionStatus } = await import('./queries/strategies.js');
199
+ await updateStrategyExecutionStatus(strategyId, status);
200
+ },
201
+ };
202
+ }
203
+ //# sourceMappingURL=scheduler.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"scheduler.js","sourceRoot":"","sources":["../src/scheduler.ts"],"names":[],"mappings":"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"}