@stoneforge/smithy 0.1.0

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 (497) hide show
  1. package/LICENSE +13 -0
  2. package/README.md +114 -0
  3. package/dist/api/index.d.ts +7 -0
  4. package/dist/api/index.d.ts.map +1 -0
  5. package/dist/api/index.js +7 -0
  6. package/dist/api/index.js.map +1 -0
  7. package/dist/api/orchestrator-api.d.ts +153 -0
  8. package/dist/api/orchestrator-api.d.ts.map +1 -0
  9. package/dist/api/orchestrator-api.js +374 -0
  10. package/dist/api/orchestrator-api.js.map +1 -0
  11. package/dist/bin/sf.d.ts +3 -0
  12. package/dist/bin/sf.d.ts.map +1 -0
  13. package/dist/bin/sf.js +10 -0
  14. package/dist/bin/sf.js.map +1 -0
  15. package/dist/cli/commands/agent.d.ts +20 -0
  16. package/dist/cli/commands/agent.d.ts.map +1 -0
  17. package/dist/cli/commands/agent.js +861 -0
  18. package/dist/cli/commands/agent.js.map +1 -0
  19. package/dist/cli/commands/daemon.d.ts +14 -0
  20. package/dist/cli/commands/daemon.d.ts.map +1 -0
  21. package/dist/cli/commands/daemon.js +272 -0
  22. package/dist/cli/commands/daemon.js.map +1 -0
  23. package/dist/cli/commands/dispatch.d.ts +9 -0
  24. package/dist/cli/commands/dispatch.d.ts.map +1 -0
  25. package/dist/cli/commands/dispatch.js +128 -0
  26. package/dist/cli/commands/dispatch.js.map +1 -0
  27. package/dist/cli/commands/merge.d.ts +11 -0
  28. package/dist/cli/commands/merge.d.ts.map +1 -0
  29. package/dist/cli/commands/merge.js +246 -0
  30. package/dist/cli/commands/merge.js.map +1 -0
  31. package/dist/cli/commands/pool.d.ts +21 -0
  32. package/dist/cli/commands/pool.d.ts.map +1 -0
  33. package/dist/cli/commands/pool.js +762 -0
  34. package/dist/cli/commands/pool.js.map +1 -0
  35. package/dist/cli/commands/serve.d.ts +54 -0
  36. package/dist/cli/commands/serve.d.ts.map +1 -0
  37. package/dist/cli/commands/serve.js +57 -0
  38. package/dist/cli/commands/serve.js.map +1 -0
  39. package/dist/cli/commands/task.d.ts +36 -0
  40. package/dist/cli/commands/task.d.ts.map +1 -0
  41. package/dist/cli/commands/task.js +889 -0
  42. package/dist/cli/commands/task.js.map +1 -0
  43. package/dist/cli/commands/test-orchestration.d.ts +32 -0
  44. package/dist/cli/commands/test-orchestration.d.ts.map +1 -0
  45. package/dist/cli/commands/test-orchestration.js +392 -0
  46. package/dist/cli/commands/test-orchestration.js.map +1 -0
  47. package/dist/cli/index.d.ts +13 -0
  48. package/dist/cli/index.d.ts.map +1 -0
  49. package/dist/cli/index.js +15 -0
  50. package/dist/cli/index.js.map +1 -0
  51. package/dist/cli/plugin.d.ts +23 -0
  52. package/dist/cli/plugin.d.ts.map +1 -0
  53. package/dist/cli/plugin.js +36 -0
  54. package/dist/cli/plugin.js.map +1 -0
  55. package/dist/git/index.d.ts +10 -0
  56. package/dist/git/index.d.ts.map +1 -0
  57. package/dist/git/index.js +12 -0
  58. package/dist/git/index.js.map +1 -0
  59. package/dist/git/merge.d.ts +79 -0
  60. package/dist/git/merge.d.ts.map +1 -0
  61. package/dist/git/merge.js +254 -0
  62. package/dist/git/merge.js.map +1 -0
  63. package/dist/git/worktree-manager.d.ts +299 -0
  64. package/dist/git/worktree-manager.d.ts.map +1 -0
  65. package/dist/git/worktree-manager.js +744 -0
  66. package/dist/git/worktree-manager.js.map +1 -0
  67. package/dist/index.d.ts +24 -0
  68. package/dist/index.d.ts.map +1 -0
  69. package/dist/index.js +31 -0
  70. package/dist/index.js.map +1 -0
  71. package/dist/prompts/director.md +272 -0
  72. package/dist/prompts/index.d.ts +100 -0
  73. package/dist/prompts/index.d.ts.map +1 -0
  74. package/dist/prompts/index.js +294 -0
  75. package/dist/prompts/index.js.map +1 -0
  76. package/dist/prompts/message-triage.md +50 -0
  77. package/dist/prompts/persistent-worker.md +240 -0
  78. package/dist/prompts/steward-base.md +64 -0
  79. package/dist/prompts/steward-docs.md +118 -0
  80. package/dist/prompts/steward-health.md +39 -0
  81. package/dist/prompts/steward-merge.md +168 -0
  82. package/dist/prompts/steward-ops.md +28 -0
  83. package/dist/prompts/steward-reminder.md +26 -0
  84. package/dist/prompts/worker.md +282 -0
  85. package/dist/providers/claude/headless.d.ts +18 -0
  86. package/dist/providers/claude/headless.d.ts.map +1 -0
  87. package/dist/providers/claude/headless.js +307 -0
  88. package/dist/providers/claude/headless.js.map +1 -0
  89. package/dist/providers/claude/index.d.ts +24 -0
  90. package/dist/providers/claude/index.d.ts.map +1 -0
  91. package/dist/providers/claude/index.js +80 -0
  92. package/dist/providers/claude/index.js.map +1 -0
  93. package/dist/providers/claude/interactive.d.ts +21 -0
  94. package/dist/providers/claude/interactive.d.ts.map +1 -0
  95. package/dist/providers/claude/interactive.js +142 -0
  96. package/dist/providers/claude/interactive.js.map +1 -0
  97. package/dist/providers/codex/event-mapper.d.ts +91 -0
  98. package/dist/providers/codex/event-mapper.d.ts.map +1 -0
  99. package/dist/providers/codex/event-mapper.js +299 -0
  100. package/dist/providers/codex/event-mapper.js.map +1 -0
  101. package/dist/providers/codex/headless.d.ts +20 -0
  102. package/dist/providers/codex/headless.d.ts.map +1 -0
  103. package/dist/providers/codex/headless.js +174 -0
  104. package/dist/providers/codex/headless.js.map +1 -0
  105. package/dist/providers/codex/index.d.ts +30 -0
  106. package/dist/providers/codex/index.d.ts.map +1 -0
  107. package/dist/providers/codex/index.js +55 -0
  108. package/dist/providers/codex/index.js.map +1 -0
  109. package/dist/providers/codex/interactive.d.ts +21 -0
  110. package/dist/providers/codex/interactive.d.ts.map +1 -0
  111. package/dist/providers/codex/interactive.js +141 -0
  112. package/dist/providers/codex/interactive.js.map +1 -0
  113. package/dist/providers/codex/jsonrpc-client.d.ts +52 -0
  114. package/dist/providers/codex/jsonrpc-client.d.ts.map +1 -0
  115. package/dist/providers/codex/jsonrpc-client.js +141 -0
  116. package/dist/providers/codex/jsonrpc-client.js.map +1 -0
  117. package/dist/providers/codex/server-manager.d.ts +100 -0
  118. package/dist/providers/codex/server-manager.d.ts.map +1 -0
  119. package/dist/providers/codex/server-manager.js +153 -0
  120. package/dist/providers/codex/server-manager.js.map +1 -0
  121. package/dist/providers/index.d.ts +15 -0
  122. package/dist/providers/index.d.ts.map +1 -0
  123. package/dist/providers/index.js +19 -0
  124. package/dist/providers/index.js.map +1 -0
  125. package/dist/providers/opencode/async-queue.d.ts +21 -0
  126. package/dist/providers/opencode/async-queue.d.ts.map +1 -0
  127. package/dist/providers/opencode/async-queue.js +51 -0
  128. package/dist/providers/opencode/async-queue.js.map +1 -0
  129. package/dist/providers/opencode/event-mapper.d.ts +132 -0
  130. package/dist/providers/opencode/event-mapper.d.ts.map +1 -0
  131. package/dist/providers/opencode/event-mapper.js +204 -0
  132. package/dist/providers/opencode/event-mapper.js.map +1 -0
  133. package/dist/providers/opencode/headless.d.ts +25 -0
  134. package/dist/providers/opencode/headless.d.ts.map +1 -0
  135. package/dist/providers/opencode/headless.js +190 -0
  136. package/dist/providers/opencode/headless.js.map +1 -0
  137. package/dist/providers/opencode/index.d.ts +33 -0
  138. package/dist/providers/opencode/index.d.ts.map +1 -0
  139. package/dist/providers/opencode/index.js +42 -0
  140. package/dist/providers/opencode/index.js.map +1 -0
  141. package/dist/providers/opencode/interactive.d.ts +21 -0
  142. package/dist/providers/opencode/interactive.d.ts.map +1 -0
  143. package/dist/providers/opencode/interactive.js +135 -0
  144. package/dist/providers/opencode/interactive.js.map +1 -0
  145. package/dist/providers/opencode/server-manager.d.ts +145 -0
  146. package/dist/providers/opencode/server-manager.d.ts.map +1 -0
  147. package/dist/providers/opencode/server-manager.js +163 -0
  148. package/dist/providers/opencode/server-manager.js.map +1 -0
  149. package/dist/providers/registry.d.ts +38 -0
  150. package/dist/providers/registry.d.ts.map +1 -0
  151. package/dist/providers/registry.js +82 -0
  152. package/dist/providers/registry.js.map +1 -0
  153. package/dist/providers/types.d.ts +144 -0
  154. package/dist/providers/types.d.ts.map +1 -0
  155. package/dist/providers/types.js +25 -0
  156. package/dist/providers/types.js.map +1 -0
  157. package/dist/runtime/event-utils.d.ts +8 -0
  158. package/dist/runtime/event-utils.d.ts.map +1 -0
  159. package/dist/runtime/event-utils.js +23 -0
  160. package/dist/runtime/event-utils.js.map +1 -0
  161. package/dist/runtime/handoff.d.ts +195 -0
  162. package/dist/runtime/handoff.d.ts.map +1 -0
  163. package/dist/runtime/handoff.js +332 -0
  164. package/dist/runtime/handoff.js.map +1 -0
  165. package/dist/runtime/index.d.ts +17 -0
  166. package/dist/runtime/index.d.ts.map +1 -0
  167. package/dist/runtime/index.js +60 -0
  168. package/dist/runtime/index.js.map +1 -0
  169. package/dist/runtime/message-mapper.d.ts +99 -0
  170. package/dist/runtime/message-mapper.d.ts.map +1 -0
  171. package/dist/runtime/message-mapper.js +202 -0
  172. package/dist/runtime/message-mapper.js.map +1 -0
  173. package/dist/runtime/predecessor-query.d.ts +212 -0
  174. package/dist/runtime/predecessor-query.d.ts.map +1 -0
  175. package/dist/runtime/predecessor-query.js +283 -0
  176. package/dist/runtime/predecessor-query.js.map +1 -0
  177. package/dist/runtime/session-manager.d.ts +466 -0
  178. package/dist/runtime/session-manager.d.ts.map +1 -0
  179. package/dist/runtime/session-manager.js +986 -0
  180. package/dist/runtime/session-manager.js.map +1 -0
  181. package/dist/runtime/spawner.d.ts +407 -0
  182. package/dist/runtime/spawner.d.ts.map +1 -0
  183. package/dist/runtime/spawner.js +781 -0
  184. package/dist/runtime/spawner.js.map +1 -0
  185. package/dist/server/config.d.ts +22 -0
  186. package/dist/server/config.d.ts.map +1 -0
  187. package/dist/server/config.js +59 -0
  188. package/dist/server/config.js.map +1 -0
  189. package/dist/server/daemon-state.d.ts +50 -0
  190. package/dist/server/daemon-state.d.ts.map +1 -0
  191. package/dist/server/daemon-state.js +100 -0
  192. package/dist/server/daemon-state.js.map +1 -0
  193. package/dist/server/events-websocket.d.ts +32 -0
  194. package/dist/server/events-websocket.d.ts.map +1 -0
  195. package/dist/server/events-websocket.js +96 -0
  196. package/dist/server/events-websocket.js.map +1 -0
  197. package/dist/server/formatters.d.ts +94 -0
  198. package/dist/server/formatters.d.ts.map +1 -0
  199. package/dist/server/formatters.js +142 -0
  200. package/dist/server/formatters.js.map +1 -0
  201. package/dist/server/index.d.ts +17 -0
  202. package/dist/server/index.d.ts.map +1 -0
  203. package/dist/server/index.js +153 -0
  204. package/dist/server/index.js.map +1 -0
  205. package/dist/server/lsp-websocket.d.ts +33 -0
  206. package/dist/server/lsp-websocket.d.ts.map +1 -0
  207. package/dist/server/lsp-websocket.js +161 -0
  208. package/dist/server/lsp-websocket.js.map +1 -0
  209. package/dist/server/routes/agents.d.ts +9 -0
  210. package/dist/server/routes/agents.d.ts.map +1 -0
  211. package/dist/server/routes/agents.js +369 -0
  212. package/dist/server/routes/agents.js.map +1 -0
  213. package/dist/server/routes/daemon.d.ts +13 -0
  214. package/dist/server/routes/daemon.d.ts.map +1 -0
  215. package/dist/server/routes/daemon.js +187 -0
  216. package/dist/server/routes/daemon.js.map +1 -0
  217. package/dist/server/routes/events.d.ts +23 -0
  218. package/dist/server/routes/events.d.ts.map +1 -0
  219. package/dist/server/routes/events.js +282 -0
  220. package/dist/server/routes/events.js.map +1 -0
  221. package/dist/server/routes/extensions.d.ts +9 -0
  222. package/dist/server/routes/extensions.d.ts.map +1 -0
  223. package/dist/server/routes/extensions.js +202 -0
  224. package/dist/server/routes/extensions.js.map +1 -0
  225. package/dist/server/routes/health.d.ts +7 -0
  226. package/dist/server/routes/health.d.ts.map +1 -0
  227. package/dist/server/routes/health.js +33 -0
  228. package/dist/server/routes/health.js.map +1 -0
  229. package/dist/server/routes/index.d.ts +21 -0
  230. package/dist/server/routes/index.d.ts.map +1 -0
  231. package/dist/server/routes/index.js +21 -0
  232. package/dist/server/routes/index.js.map +1 -0
  233. package/dist/server/routes/lsp.d.ts +9 -0
  234. package/dist/server/routes/lsp.d.ts.map +1 -0
  235. package/dist/server/routes/lsp.js +50 -0
  236. package/dist/server/routes/lsp.js.map +1 -0
  237. package/dist/server/routes/plugins.d.ts +9 -0
  238. package/dist/server/routes/plugins.d.ts.map +1 -0
  239. package/dist/server/routes/plugins.js +109 -0
  240. package/dist/server/routes/plugins.js.map +1 -0
  241. package/dist/server/routes/pools.d.ts +9 -0
  242. package/dist/server/routes/pools.d.ts.map +1 -0
  243. package/dist/server/routes/pools.js +189 -0
  244. package/dist/server/routes/pools.js.map +1 -0
  245. package/dist/server/routes/scheduler.d.ts +9 -0
  246. package/dist/server/routes/scheduler.d.ts.map +1 -0
  247. package/dist/server/routes/scheduler.js +162 -0
  248. package/dist/server/routes/scheduler.js.map +1 -0
  249. package/dist/server/routes/sessions.d.ts +27 -0
  250. package/dist/server/routes/sessions.d.ts.map +1 -0
  251. package/dist/server/routes/sessions.js +773 -0
  252. package/dist/server/routes/sessions.js.map +1 -0
  253. package/dist/server/routes/tasks.d.ts +9 -0
  254. package/dist/server/routes/tasks.d.ts.map +1 -0
  255. package/dist/server/routes/tasks.js +954 -0
  256. package/dist/server/routes/tasks.js.map +1 -0
  257. package/dist/server/routes/upload.d.ts +8 -0
  258. package/dist/server/routes/upload.d.ts.map +1 -0
  259. package/dist/server/routes/upload.js +40 -0
  260. package/dist/server/routes/upload.js.map +1 -0
  261. package/dist/server/routes/workflows.d.ts +9 -0
  262. package/dist/server/routes/workflows.d.ts.map +1 -0
  263. package/dist/server/routes/workflows.js +532 -0
  264. package/dist/server/routes/workflows.js.map +1 -0
  265. package/dist/server/routes/workspace-files.d.ts +12 -0
  266. package/dist/server/routes/workspace-files.d.ts.map +1 -0
  267. package/dist/server/routes/workspace-files.js +520 -0
  268. package/dist/server/routes/workspace-files.js.map +1 -0
  269. package/dist/server/routes/worktrees.d.ts +9 -0
  270. package/dist/server/routes/worktrees.d.ts.map +1 -0
  271. package/dist/server/routes/worktrees.js +94 -0
  272. package/dist/server/routes/worktrees.js.map +1 -0
  273. package/dist/server/server.d.ts +14 -0
  274. package/dist/server/server.d.ts.map +1 -0
  275. package/dist/server/server.js +258 -0
  276. package/dist/server/server.js.map +1 -0
  277. package/dist/server/services/lsp-manager.d.ts +93 -0
  278. package/dist/server/services/lsp-manager.d.ts.map +1 -0
  279. package/dist/server/services/lsp-manager.js +291 -0
  280. package/dist/server/services/lsp-manager.js.map +1 -0
  281. package/dist/server/services/session-messages.d.ts +61 -0
  282. package/dist/server/services/session-messages.d.ts.map +1 -0
  283. package/dist/server/services/session-messages.js +101 -0
  284. package/dist/server/services/session-messages.js.map +1 -0
  285. package/dist/server/services.d.ts +35 -0
  286. package/dist/server/services.d.ts.map +1 -0
  287. package/dist/server/services.js +159 -0
  288. package/dist/server/services.js.map +1 -0
  289. package/dist/server/static.d.ts +18 -0
  290. package/dist/server/static.d.ts.map +1 -0
  291. package/dist/server/static.js +71 -0
  292. package/dist/server/static.js.map +1 -0
  293. package/dist/server/types.d.ts +20 -0
  294. package/dist/server/types.d.ts.map +1 -0
  295. package/dist/server/types.js +7 -0
  296. package/dist/server/types.js.map +1 -0
  297. package/dist/server/websocket.d.ts +16 -0
  298. package/dist/server/websocket.d.ts.map +1 -0
  299. package/dist/server/websocket.js +143 -0
  300. package/dist/server/websocket.js.map +1 -0
  301. package/dist/services/agent-pool-service.d.ts +181 -0
  302. package/dist/services/agent-pool-service.d.ts.map +1 -0
  303. package/dist/services/agent-pool-service.js +590 -0
  304. package/dist/services/agent-pool-service.js.map +1 -0
  305. package/dist/services/agent-registry.d.ts +185 -0
  306. package/dist/services/agent-registry.d.ts.map +1 -0
  307. package/dist/services/agent-registry.js +432 -0
  308. package/dist/services/agent-registry.js.map +1 -0
  309. package/dist/services/dispatch-daemon.d.ts +429 -0
  310. package/dist/services/dispatch-daemon.d.ts.map +1 -0
  311. package/dist/services/dispatch-daemon.js +1833 -0
  312. package/dist/services/dispatch-daemon.js.map +1 -0
  313. package/dist/services/dispatch-service.d.ts +148 -0
  314. package/dist/services/dispatch-service.d.ts.map +1 -0
  315. package/dist/services/dispatch-service.js +170 -0
  316. package/dist/services/dispatch-service.js.map +1 -0
  317. package/dist/services/docs-steward-service.d.ts +199 -0
  318. package/dist/services/docs-steward-service.d.ts.map +1 -0
  319. package/dist/services/docs-steward-service.js +599 -0
  320. package/dist/services/docs-steward-service.js.map +1 -0
  321. package/dist/services/health-steward-service.d.ts +446 -0
  322. package/dist/services/health-steward-service.d.ts.map +1 -0
  323. package/dist/services/health-steward-service.js +866 -0
  324. package/dist/services/health-steward-service.js.map +1 -0
  325. package/dist/services/index.d.ts +26 -0
  326. package/dist/services/index.d.ts.map +1 -0
  327. package/dist/services/index.js +111 -0
  328. package/dist/services/index.js.map +1 -0
  329. package/dist/services/merge-request-provider.d.ts +59 -0
  330. package/dist/services/merge-request-provider.d.ts.map +1 -0
  331. package/dist/services/merge-request-provider.js +89 -0
  332. package/dist/services/merge-request-provider.js.map +1 -0
  333. package/dist/services/merge-steward-service.d.ts +268 -0
  334. package/dist/services/merge-steward-service.d.ts.map +1 -0
  335. package/dist/services/merge-steward-service.js +568 -0
  336. package/dist/services/merge-steward-service.js.map +1 -0
  337. package/dist/services/plugin-executor.d.ts +247 -0
  338. package/dist/services/plugin-executor.d.ts.map +1 -0
  339. package/dist/services/plugin-executor.js +451 -0
  340. package/dist/services/plugin-executor.js.map +1 -0
  341. package/dist/services/role-definition-service.d.ts +117 -0
  342. package/dist/services/role-definition-service.d.ts.map +1 -0
  343. package/dist/services/role-definition-service.js +289 -0
  344. package/dist/services/role-definition-service.js.map +1 -0
  345. package/dist/services/steward-scheduler.d.ts +336 -0
  346. package/dist/services/steward-scheduler.d.ts.map +1 -0
  347. package/dist/services/steward-scheduler.js +732 -0
  348. package/dist/services/steward-scheduler.js.map +1 -0
  349. package/dist/services/task-assignment-service.d.ts +291 -0
  350. package/dist/services/task-assignment-service.d.ts.map +1 -0
  351. package/dist/services/task-assignment-service.js +454 -0
  352. package/dist/services/task-assignment-service.js.map +1 -0
  353. package/dist/services/worker-task-service.d.ts +202 -0
  354. package/dist/services/worker-task-service.d.ts.map +1 -0
  355. package/dist/services/worker-task-service.js +228 -0
  356. package/dist/services/worker-task-service.js.map +1 -0
  357. package/dist/testing/index.d.ts +13 -0
  358. package/dist/testing/index.d.ts.map +1 -0
  359. package/dist/testing/index.js +17 -0
  360. package/dist/testing/index.js.map +1 -0
  361. package/dist/testing/orchestration-tests.d.ts +62 -0
  362. package/dist/testing/orchestration-tests.d.ts.map +1 -0
  363. package/dist/testing/orchestration-tests.js +1115 -0
  364. package/dist/testing/orchestration-tests.js.map +1 -0
  365. package/dist/testing/test-context.d.ts +171 -0
  366. package/dist/testing/test-context.d.ts.map +1 -0
  367. package/dist/testing/test-context.js +665 -0
  368. package/dist/testing/test-context.js.map +1 -0
  369. package/dist/testing/test-prompts.d.ts +46 -0
  370. package/dist/testing/test-prompts.d.ts.map +1 -0
  371. package/dist/testing/test-prompts.js +140 -0
  372. package/dist/testing/test-prompts.js.map +1 -0
  373. package/dist/testing/test-utils.d.ts +200 -0
  374. package/dist/testing/test-utils.d.ts.map +1 -0
  375. package/dist/testing/test-utils.js +378 -0
  376. package/dist/testing/test-utils.js.map +1 -0
  377. package/dist/types/agent-pool.d.ts +215 -0
  378. package/dist/types/agent-pool.d.ts.map +1 -0
  379. package/dist/types/agent-pool.js +143 -0
  380. package/dist/types/agent-pool.js.map +1 -0
  381. package/dist/types/agent.d.ts +265 -0
  382. package/dist/types/agent.d.ts.map +1 -0
  383. package/dist/types/agent.js +127 -0
  384. package/dist/types/agent.js.map +1 -0
  385. package/dist/types/index.d.ts +11 -0
  386. package/dist/types/index.d.ts.map +1 -0
  387. package/dist/types/index.js +40 -0
  388. package/dist/types/index.js.map +1 -0
  389. package/dist/types/message-types.d.ts +294 -0
  390. package/dist/types/message-types.d.ts.map +1 -0
  391. package/dist/types/message-types.js +354 -0
  392. package/dist/types/message-types.js.map +1 -0
  393. package/dist/types/role-definition.d.ts +272 -0
  394. package/dist/types/role-definition.d.ts.map +1 -0
  395. package/dist/types/role-definition.js +144 -0
  396. package/dist/types/role-definition.js.map +1 -0
  397. package/dist/types/task-meta.d.ts +248 -0
  398. package/dist/types/task-meta.d.ts.map +1 -0
  399. package/dist/types/task-meta.js +213 -0
  400. package/dist/types/task-meta.js.map +1 -0
  401. package/package.json +120 -0
  402. package/web/assets/abap-BrgZPUOV.js +6 -0
  403. package/web/assets/apex-DyP6w7ZV.js +6 -0
  404. package/web/assets/azcli-BaLxmfj-.js +6 -0
  405. package/web/assets/bat-CFOPXBzS.js +6 -0
  406. package/web/assets/bicep-BfEKNvv3.js +7 -0
  407. package/web/assets/cameligo-BFG1Mk7z.js +6 -0
  408. package/web/assets/clojure-DTECt2xU.js +6 -0
  409. package/web/assets/codicon-DCmgc-ay.ttf +0 -0
  410. package/web/assets/coffee-CDGzqUPQ.js +6 -0
  411. package/web/assets/cpp-CLLBncYj.js +6 -0
  412. package/web/assets/csharp-dUCx_-0o.js +6 -0
  413. package/web/assets/csp-5Rap-vPy.js +6 -0
  414. package/web/assets/css-D3h14YRZ.js +8 -0
  415. package/web/assets/cssMode-DMo-5YLA.js +9 -0
  416. package/web/assets/cypher-DrQuvNYM.js +6 -0
  417. package/web/assets/dart-CFKIUWau.js +6 -0
  418. package/web/assets/dockerfile-Zznr-cwX.js +6 -0
  419. package/web/assets/ecl-Ce3n6wWz.js +6 -0
  420. package/web/assets/elixir-deUWdS0T.js +6 -0
  421. package/web/assets/flow9-i9-g7ZhI.js +6 -0
  422. package/web/assets/freemarker2-D4qgkQzN.js +8 -0
  423. package/web/assets/fsharp-CzKuDChf.js +6 -0
  424. package/web/assets/go-Cphgjts3.js +6 -0
  425. package/web/assets/graphql-Cg7bfA9N.js +6 -0
  426. package/web/assets/handlebars-CXFvNjQC.js +6 -0
  427. package/web/assets/hcl-0cvrggvQ.js +6 -0
  428. package/web/assets/html-oyuB_D-B.js +6 -0
  429. package/web/assets/htmlMode-iWuZ24-r.js +9 -0
  430. package/web/assets/index-DqP-_E4F.css +32 -0
  431. package/web/assets/index-R1cylSgw.js +1665 -0
  432. package/web/assets/ini-Drc7WvVn.js +6 -0
  433. package/web/assets/java-B_fMsGYe.js +6 -0
  434. package/web/assets/javascript-CRIkN2Pg.js +6 -0
  435. package/web/assets/jsonMode-DVDkDgex.js +15 -0
  436. package/web/assets/julia-Bqgm2twL.js +6 -0
  437. package/web/assets/kotlin-BSkB5QuD.js +6 -0
  438. package/web/assets/less-BsTHnhdd.js +7 -0
  439. package/web/assets/lexon-YWi4-JPR.js +6 -0
  440. package/web/assets/liquid-CSfldbB5.js +6 -0
  441. package/web/assets/lua-nf6ki56Z.js +6 -0
  442. package/web/assets/m3-Cpb6xl2v.js +6 -0
  443. package/web/assets/markdown-DSZPf7rp.js +6 -0
  444. package/web/assets/mdx-Dd58iymR.js +6 -0
  445. package/web/assets/mips-B_c3zf-v.js +6 -0
  446. package/web/assets/monaco-editor-B4lwqA13.js +751 -0
  447. package/web/assets/monaco-editor-CQpyCxOA.css +1 -0
  448. package/web/assets/msdax-rUNN04Wq.js +6 -0
  449. package/web/assets/mysql-DDwshQtU.js +6 -0
  450. package/web/assets/objective-c-B5zXfXm9.js +6 -0
  451. package/web/assets/pascal-CXOwvkN_.js +6 -0
  452. package/web/assets/pascaligo-Bc-ZgV77.js +6 -0
  453. package/web/assets/perl-CwNk8-XU.js +6 -0
  454. package/web/assets/pgsql-tGk8EFnU.js +6 -0
  455. package/web/assets/php-CpIb_Oan.js +6 -0
  456. package/web/assets/pla-B03wrqEc.js +6 -0
  457. package/web/assets/postiats-BKlk5iyT.js +6 -0
  458. package/web/assets/powerquery-Bhzvs7bI.js +6 -0
  459. package/web/assets/powershell-Dd3NCNK9.js +6 -0
  460. package/web/assets/protobuf-COyEY5Pt.js +7 -0
  461. package/web/assets/pug-BaJupSGV.js +6 -0
  462. package/web/assets/python-XWrMqdhO.js +6 -0
  463. package/web/assets/qsharp-DXyYeYxl.js +6 -0
  464. package/web/assets/r-CdQndTaG.js +6 -0
  465. package/web/assets/razor-DPlhCpIs.js +6 -0
  466. package/web/assets/redis-CVwtpugi.js +6 -0
  467. package/web/assets/redshift-25W9uPmb.js +6 -0
  468. package/web/assets/restructuredtext-DfzH4Xui.js +6 -0
  469. package/web/assets/router-vendor-DHlGizSU.js +41 -0
  470. package/web/assets/ruby-Cp1zYvxS.js +6 -0
  471. package/web/assets/rust-D5C2fndG.js +6 -0
  472. package/web/assets/sb-CDntyWJ8.js +6 -0
  473. package/web/assets/scala-BoFRg7Ot.js +6 -0
  474. package/web/assets/scheme-Bio4gycK.js +6 -0
  475. package/web/assets/scss-4Ik7cdeQ.js +8 -0
  476. package/web/assets/shell-CX-rkNHf.js +6 -0
  477. package/web/assets/solidity-Tw7wswEv.js +6 -0
  478. package/web/assets/sophia-C5WLch3f.js +6 -0
  479. package/web/assets/sparql-DHaeiCBh.js +6 -0
  480. package/web/assets/sql-CCSDG5nI.js +6 -0
  481. package/web/assets/st-pnP8ivHi.js +6 -0
  482. package/web/assets/swift-DwJ7jVG9.js +8 -0
  483. package/web/assets/systemverilog-B9Xyijhd.js +6 -0
  484. package/web/assets/tcl-DnHyzjbg.js +6 -0
  485. package/web/assets/tsMode-BbA1Jbf3.js +16 -0
  486. package/web/assets/twig-CPajHgWi.js +6 -0
  487. package/web/assets/typescript-DcLHYzvH.js +6 -0
  488. package/web/assets/typespec-D-MeaMDU.js +6 -0
  489. package/web/assets/ui-vendor-BSco96uv.js +51 -0
  490. package/web/assets/utils-vendor-DaJ2Dubl.js +911 -0
  491. package/web/assets/vb-DgyLZaXg.js +6 -0
  492. package/web/assets/wgsl-DYQUnd45.js +303 -0
  493. package/web/assets/xml-xKYS3dO6.js +6 -0
  494. package/web/assets/yaml-CNmlXqzH.js +6 -0
  495. package/web/favicon.ico +0 -0
  496. package/web/index.html +22 -0
  497. package/web/logo.png +0 -0
@@ -0,0 +1,732 @@
1
+ /**
2
+ * Steward Scheduler Service
3
+ *
4
+ * This service executes stewards on schedule (cron) or in response to events.
5
+ * It manages the lifecycle of scheduled steward executions and tracks execution history.
6
+ *
7
+ * Key features:
8
+ * - Cron-based scheduling using node-cron
9
+ * - Event-driven triggers with condition evaluation
10
+ * - Execution history tracking
11
+ * - Graceful shutdown support
12
+ *
13
+ * TB-O23: Steward Scheduler Service
14
+ *
15
+ * @module
16
+ */
17
+ import { EventEmitter } from 'node:events';
18
+ import { createTimestamp } from '@stoneforge/core';
19
+ import { isCronTrigger, isEventTrigger, } from '../types/index.js';
20
+ import { getAgentMetadata } from './agent-registry.js';
21
+ // ============================================================================
22
+ // Cron Schedule Utilities
23
+ // ============================================================================
24
+ /**
25
+ * Validates a cron expression.
26
+ * This is a basic validation - we check the format but not all edge cases.
27
+ */
28
+ export function isValidCronExpression(schedule) {
29
+ // Standard cron format: * * * * * (minute hour day month weekday)
30
+ // Extended format with seconds: * * * * * * (second minute hour day month weekday)
31
+ const parts = schedule.trim().split(/\s+/);
32
+ if (parts.length < 5 || parts.length > 6) {
33
+ return false;
34
+ }
35
+ // Basic validation: each part should be a valid cron field
36
+ const cronFieldPattern = /^(\*|\d+(-\d+)?(,\d+(-\d+)?)*)(\/\d+)?$/;
37
+ return parts.every(part => cronFieldPattern.test(part) || part === '*');
38
+ }
39
+ /**
40
+ * Calculates the next run time for a cron expression.
41
+ * This is a simplified implementation - for production use node-cron handles this.
42
+ */
43
+ export function getNextCronRunTime(_schedule) {
44
+ // This is a placeholder - node-cron provides this via the scheduled task
45
+ // For now we return undefined; actual implementation uses node-cron internals
46
+ return undefined;
47
+ }
48
+ // ============================================================================
49
+ // Condition Evaluation
50
+ // ============================================================================
51
+ /**
52
+ * Validates that a condition string contains only safe expression tokens.
53
+ * Allows: property access, comparisons, string/number literals, booleans,
54
+ * logical operators, parentheses.
55
+ * Rejects: function calls, assignments, semicolons, template literals,
56
+ * dangerous globals.
57
+ */
58
+ function isSafeCondition(condition) {
59
+ // Strip string literals so their contents don't trigger false positives
60
+ const withoutStrings = condition
61
+ .replace(/'[^']*'/g, '""')
62
+ .replace(/"[^"]*"/g, '""');
63
+ // Reject dangerous patterns
64
+ const dangerousPatterns = [
65
+ /[;{}]/, // statements, blocks
66
+ /\b(import|require|eval|Function|constructor|__proto__|prototype)\b/,
67
+ /\b(process|global|globalThis|window|document)\b/,
68
+ /\b(setTimeout|setInterval|fetch|XMLHttpRequest)\b/,
69
+ /=>|\.\.\.|\+\+|--/, // arrow functions, spread, increment/decrement
70
+ /\[.*\]/, // bracket notation (property access escape vector)
71
+ /`/, // template literals
72
+ /\$\{/, // template expressions
73
+ /\bthis\b/, // this reference
74
+ /\bnew\b/, // constructor calls
75
+ /\bdelete\b/, // delete operator
76
+ /\bvoid\b/, // void operator
77
+ /\btypeof\b/, // typeof operator
78
+ /\bin\b/, // in operator
79
+ /\binstanceof\b/, // instanceof operator
80
+ /[^=!<>]=[^=]/, // assignment (but not ==, !=, <=, >=)
81
+ ];
82
+ for (const pattern of dangerousPatterns) {
83
+ if (pattern.test(withoutStrings)) {
84
+ return false;
85
+ }
86
+ }
87
+ // Only allow safe characters after string removal
88
+ const safeTokenPattern = /^[\w\s.$?!&|><=()'",-]+$/;
89
+ if (!safeTokenPattern.test(withoutStrings)) {
90
+ return false;
91
+ }
92
+ // Reject function calls: identifier followed by (
93
+ if (/\w\s*\(/.test(withoutStrings)) {
94
+ return false;
95
+ }
96
+ return true;
97
+ }
98
+ /**
99
+ * Evaluates a simple condition expression against event data.
100
+ * Supports basic JavaScript-like expressions with property access.
101
+ *
102
+ * Examples:
103
+ * - "task.status === 'closed'"
104
+ * - "task.assignedAgent?.role === 'worker'"
105
+ * - "branch.tests === 'passing'"
106
+ */
107
+ export function evaluateCondition(condition, context) {
108
+ try {
109
+ // Validate condition contains only safe expression tokens
110
+ if (!isSafeCondition(condition)) {
111
+ return false;
112
+ }
113
+ const contextKeys = Object.keys(context);
114
+ const contextValues = Object.values(context);
115
+ const fn = new Function(...contextKeys, `"use strict"; try { return Boolean(${condition}); } catch { return false; }`);
116
+ return fn(...contextValues);
117
+ }
118
+ catch {
119
+ return false;
120
+ }
121
+ }
122
+ // ============================================================================
123
+ // Steward Scheduler Implementation
124
+ // ============================================================================
125
+ /**
126
+ * Default configuration values
127
+ */
128
+ const DEFAULT_CONFIG = {
129
+ maxHistoryPerSteward: 100,
130
+ defaultTimeoutMs: 5 * 60 * 1000, // 5 minutes
131
+ startImmediately: false,
132
+ };
133
+ /**
134
+ * Implementation of the Steward Scheduler Service.
135
+ */
136
+ export class StewardSchedulerImpl {
137
+ agentRegistry;
138
+ config;
139
+ executor;
140
+ emitter;
141
+ running = false;
142
+ cronJobs = new Map(); // key: stewardId-triggerIndex
143
+ eventSubscriptions = new Map(); // key: eventName
144
+ executionHistory = [];
145
+ runningExecutions = new Set();
146
+ executionCounter = 0;
147
+ constructor(agentRegistry, executor, config = {}) {
148
+ this.agentRegistry = agentRegistry;
149
+ this.executor = executor;
150
+ this.config = { ...DEFAULT_CONFIG, ...config };
151
+ this.emitter = new EventEmitter();
152
+ }
153
+ // ----------------------------------------
154
+ // Lifecycle
155
+ // ----------------------------------------
156
+ async start() {
157
+ if (this.running) {
158
+ return;
159
+ }
160
+ this.running = true;
161
+ // Start all registered cron jobs
162
+ for (const job of this.cronJobs.values()) {
163
+ this.startCronJob(job);
164
+ }
165
+ // Activate all event subscriptions
166
+ for (const subs of this.eventSubscriptions.values()) {
167
+ for (const sub of subs) {
168
+ sub.isActive = true;
169
+ }
170
+ }
171
+ // Register all stewards if configured to do so
172
+ if (this.config.startImmediately) {
173
+ await this.registerAllStewards();
174
+ }
175
+ }
176
+ async stop() {
177
+ if (!this.running) {
178
+ return;
179
+ }
180
+ this.running = false;
181
+ // Stop all cron jobs
182
+ for (const job of this.cronJobs.values()) {
183
+ this.stopCronJob(job);
184
+ }
185
+ // Deactivate event subscriptions
186
+ for (const subs of this.eventSubscriptions.values()) {
187
+ for (const sub of subs) {
188
+ sub.isActive = false;
189
+ }
190
+ }
191
+ }
192
+ isRunning() {
193
+ return this.running;
194
+ }
195
+ // ----------------------------------------
196
+ // Steward Management
197
+ // ----------------------------------------
198
+ async registerSteward(stewardId) {
199
+ const agent = await this.agentRegistry.getAgent(stewardId);
200
+ if (!agent) {
201
+ return false;
202
+ }
203
+ const metadata = getAgentMetadata(agent);
204
+ if (!metadata || metadata.agentRole !== 'steward') {
205
+ return false;
206
+ }
207
+ const stewardMeta = metadata;
208
+ const triggers = stewardMeta.triggers ?? [];
209
+ // Remove existing registrations for this steward
210
+ await this.unregisterSteward(stewardId);
211
+ // Register each trigger
212
+ for (let i = 0; i < triggers.length; i++) {
213
+ const trigger = triggers[i];
214
+ if (isCronTrigger(trigger)) {
215
+ const jobKey = `${stewardId}-${i}`;
216
+ const jobState = {
217
+ stewardId,
218
+ stewardName: agent.name,
219
+ trigger,
220
+ isRunning: false,
221
+ };
222
+ this.cronJobs.set(jobKey, jobState);
223
+ // Start job if scheduler is running
224
+ if (this.running) {
225
+ this.startCronJob(jobState);
226
+ }
227
+ }
228
+ else if (isEventTrigger(trigger)) {
229
+ const eventName = trigger.event;
230
+ if (!this.eventSubscriptions.has(eventName)) {
231
+ this.eventSubscriptions.set(eventName, []);
232
+ }
233
+ this.eventSubscriptions.get(eventName).push({
234
+ stewardId,
235
+ stewardName: agent.name,
236
+ trigger,
237
+ isActive: this.running,
238
+ });
239
+ }
240
+ }
241
+ this.emitter.emit('steward:registered', stewardId);
242
+ return true;
243
+ }
244
+ async unregisterSteward(stewardId) {
245
+ let unregistered = false;
246
+ // Remove cron jobs
247
+ for (const [key, job] of this.cronJobs.entries()) {
248
+ if (job.stewardId === stewardId) {
249
+ this.stopCronJob(job);
250
+ this.cronJobs.delete(key);
251
+ unregistered = true;
252
+ }
253
+ }
254
+ // Remove event subscriptions
255
+ for (const [eventName, subs] of this.eventSubscriptions.entries()) {
256
+ const remaining = subs.filter(s => s.stewardId !== stewardId);
257
+ if (remaining.length !== subs.length) {
258
+ unregistered = true;
259
+ }
260
+ if (remaining.length === 0) {
261
+ this.eventSubscriptions.delete(eventName);
262
+ }
263
+ else {
264
+ this.eventSubscriptions.set(eventName, remaining);
265
+ }
266
+ }
267
+ if (unregistered) {
268
+ this.emitter.emit('steward:unregistered', stewardId);
269
+ }
270
+ return unregistered;
271
+ }
272
+ async refreshSteward(stewardId) {
273
+ await this.unregisterSteward(stewardId);
274
+ await this.registerSteward(stewardId);
275
+ }
276
+ async registerAllStewards() {
277
+ const stewards = await this.agentRegistry.getStewards();
278
+ let registered = 0;
279
+ for (const steward of stewards) {
280
+ const success = await this.registerSteward(steward.id);
281
+ if (success) {
282
+ registered++;
283
+ }
284
+ }
285
+ return registered;
286
+ }
287
+ // ----------------------------------------
288
+ // Manual Execution
289
+ // ----------------------------------------
290
+ async executeSteward(stewardId, context) {
291
+ const agent = await this.agentRegistry.getAgent(stewardId);
292
+ if (!agent) {
293
+ return {
294
+ success: false,
295
+ error: `Steward not found: ${stewardId}`,
296
+ durationMs: 0,
297
+ };
298
+ }
299
+ const metadata = getAgentMetadata(agent);
300
+ if (!metadata || metadata.agentRole !== 'steward') {
301
+ return {
302
+ success: false,
303
+ error: `Entity is not a steward: ${stewardId}`,
304
+ durationMs: 0,
305
+ };
306
+ }
307
+ // Create a manual trigger
308
+ const manualTrigger = {
309
+ type: 'event',
310
+ event: 'manual',
311
+ };
312
+ return this.runExecution(agent, manualTrigger, true, context);
313
+ }
314
+ // ----------------------------------------
315
+ // Event Publishing
316
+ // ----------------------------------------
317
+ async publishEvent(eventName, eventData) {
318
+ if (!this.running) {
319
+ return 0;
320
+ }
321
+ const subscriptions = this.eventSubscriptions.get(eventName) ?? [];
322
+ let triggered = 0;
323
+ for (const sub of subscriptions) {
324
+ if (!sub.isActive) {
325
+ continue;
326
+ }
327
+ // Check condition if present
328
+ if (sub.trigger.condition) {
329
+ const matches = evaluateCondition(sub.trigger.condition, eventData);
330
+ if (!matches) {
331
+ continue;
332
+ }
333
+ }
334
+ // Execute the steward
335
+ const agent = await this.agentRegistry.getAgent(sub.stewardId);
336
+ if (agent) {
337
+ // Run execution asynchronously
338
+ this.runExecution(agent, sub.trigger, false, eventData).catch(() => {
339
+ // Errors are handled in runExecution
340
+ });
341
+ triggered++;
342
+ }
343
+ }
344
+ return triggered;
345
+ }
346
+ // ----------------------------------------
347
+ // Status & Queries
348
+ // ----------------------------------------
349
+ getScheduledJobs(stewardId) {
350
+ const jobs = [];
351
+ for (const job of this.cronJobs.values()) {
352
+ if (stewardId && job.stewardId !== stewardId) {
353
+ continue;
354
+ }
355
+ jobs.push({
356
+ stewardId: job.stewardId,
357
+ stewardName: job.stewardName,
358
+ trigger: job.trigger,
359
+ isRunning: job.isRunning,
360
+ nextRunAt: job.nextRunAt,
361
+ lastRunAt: job.lastRunAt,
362
+ });
363
+ }
364
+ return jobs;
365
+ }
366
+ getEventSubscriptions(stewardId) {
367
+ const subscriptions = [];
368
+ for (const subs of this.eventSubscriptions.values()) {
369
+ for (const sub of subs) {
370
+ if (stewardId && sub.stewardId !== stewardId) {
371
+ continue;
372
+ }
373
+ subscriptions.push({
374
+ stewardId: sub.stewardId,
375
+ stewardName: sub.stewardName,
376
+ trigger: sub.trigger,
377
+ isActive: sub.isActive,
378
+ });
379
+ }
380
+ }
381
+ return subscriptions;
382
+ }
383
+ getExecutionHistory(filter) {
384
+ let entries = [...this.executionHistory];
385
+ if (filter) {
386
+ if (filter.stewardId) {
387
+ entries = entries.filter(e => e.stewardId === filter.stewardId);
388
+ }
389
+ if (filter.triggerType) {
390
+ entries = entries.filter(e => e.trigger.type === filter.triggerType);
391
+ }
392
+ if (filter.success !== undefined) {
393
+ entries = entries.filter(e => e.result?.success === filter.success);
394
+ }
395
+ if (filter.startedAfter) {
396
+ entries = entries.filter(e => e.startedAt >= filter.startedAfter);
397
+ }
398
+ if (filter.startedBefore) {
399
+ entries = entries.filter(e => e.startedAt <= filter.startedBefore);
400
+ }
401
+ }
402
+ // Sort by startedAt descending
403
+ entries.sort((a, b) => (b.startedAt > a.startedAt ? 1 : -1));
404
+ if (filter?.limit) {
405
+ entries = entries.slice(0, filter.limit);
406
+ }
407
+ return entries;
408
+ }
409
+ getLastExecution(stewardId) {
410
+ const entries = this.getExecutionHistory({ stewardId, limit: 1 });
411
+ return entries[0];
412
+ }
413
+ getStats() {
414
+ const registeredStewards = new Set();
415
+ for (const job of this.cronJobs.values()) {
416
+ registeredStewards.add(job.stewardId);
417
+ }
418
+ for (const subs of this.eventSubscriptions.values()) {
419
+ for (const sub of subs) {
420
+ registeredStewards.add(sub.stewardId);
421
+ }
422
+ }
423
+ const successfulExecutions = this.executionHistory.filter(e => e.result?.success === true).length;
424
+ const failedExecutions = this.executionHistory.filter(e => e.result?.success === false).length;
425
+ return {
426
+ registeredStewards: registeredStewards.size,
427
+ activeCronJobs: this.cronJobs.size,
428
+ activeEventSubscriptions: [...this.eventSubscriptions.values()].flat().length,
429
+ totalExecutions: this.executionHistory.length,
430
+ successfulExecutions,
431
+ failedExecutions,
432
+ runningExecutions: this.runningExecutions.size,
433
+ };
434
+ }
435
+ on(event, listener) {
436
+ this.emitter.on(event, listener);
437
+ }
438
+ off(event, listener) {
439
+ this.emitter.off(event, listener);
440
+ }
441
+ // ----------------------------------------
442
+ // Private Helpers
443
+ // ----------------------------------------
444
+ startCronJob(job) {
445
+ if (job.intervalId) {
446
+ return; // Already running
447
+ }
448
+ this.scheduleNextRun(job);
449
+ }
450
+ scheduleNextRun(job) {
451
+ const nextTime = this.getNextCronTime(job.trigger.schedule);
452
+ if (!nextTime)
453
+ return;
454
+ job.nextRunAt = nextTime;
455
+ const delayMs = Math.max(0, nextTime.getTime() - Date.now());
456
+ job.intervalId = setTimeout(async () => {
457
+ if (!this.running)
458
+ return;
459
+ if (job.isRunning) {
460
+ // Skip this run but schedule the next one
461
+ job.intervalId = undefined;
462
+ this.scheduleNextRun(job);
463
+ return;
464
+ }
465
+ const agent = await this.agentRegistry.getAgent(job.stewardId);
466
+ if (agent && this.running) {
467
+ await this.runExecution(agent, job.trigger, false);
468
+ job.lastRunAt = createTimestamp();
469
+ }
470
+ if (this.running) {
471
+ job.intervalId = undefined;
472
+ this.scheduleNextRun(job);
473
+ }
474
+ }, delayMs);
475
+ }
476
+ stopCronJob(job) {
477
+ if (job.intervalId) {
478
+ clearTimeout(job.intervalId);
479
+ job.intervalId = undefined;
480
+ }
481
+ }
482
+ /**
483
+ * Calculates the next fire time for a cron expression after the given date.
484
+ * Supports 5-field cron (minute hour dom month dow) with optional 6th seconds field (ignored).
485
+ * Supports: *, specific values, step (* /N), range (N-M), and lists (N,M).
486
+ * Returns null for invalid expressions.
487
+ */
488
+ getNextCronTime(schedule, after) {
489
+ const parts = schedule.trim().split(/\s+/);
490
+ if (parts.length < 5 || parts.length > 6) {
491
+ return null;
492
+ }
493
+ // If 6 fields, ignore the first (seconds) field
494
+ const fields = parts.length === 6 ? parts.slice(1) : parts;
495
+ const [minuteField, hourField, domField, monthField, dowField] = fields;
496
+ // Parse each field into a set of allowed values
497
+ const minutes = this.parseCronField(minuteField, 0, 59);
498
+ const hours = this.parseCronField(hourField, 0, 23);
499
+ const doms = this.parseCronField(domField, 1, 31);
500
+ const months = this.parseCronField(monthField, 1, 12);
501
+ const dows = this.parseCronField(dowField, 0, 6); // 0=Sunday
502
+ if (!minutes || !hours || !doms || !months || !dows) {
503
+ return null;
504
+ }
505
+ // Start from the next minute after 'after'
506
+ const start = after ? new Date(after) : new Date();
507
+ start.setSeconds(0, 0);
508
+ start.setMinutes(start.getMinutes() + 1);
509
+ // Iterate forward up to 366 days to find the next matching time
510
+ const maxIterations = 366 * 24 * 60; // worst case: check every minute for a year
511
+ const candidate = new Date(start);
512
+ for (let i = 0; i < maxIterations; i++) {
513
+ const month = candidate.getMonth() + 1; // 1-12
514
+ const dom = candidate.getDate();
515
+ const dow = candidate.getDay(); // 0=Sunday
516
+ const hour = candidate.getHours();
517
+ const minute = candidate.getMinutes();
518
+ if (months.has(month) &&
519
+ doms.has(dom) &&
520
+ dows.has(dow) &&
521
+ hours.has(hour) &&
522
+ minutes.has(minute)) {
523
+ return candidate;
524
+ }
525
+ // Advance by 1 minute
526
+ candidate.setMinutes(candidate.getMinutes() + 1);
527
+ }
528
+ return null; // No match found within 366 days
529
+ }
530
+ /**
531
+ * Parses a single cron field into a set of valid values.
532
+ * Supports: *, N, N-M, N,M, * /N, N-M/S
533
+ */
534
+ parseCronField(field, min, max) {
535
+ const result = new Set();
536
+ // Handle comma-separated list
537
+ const segments = field.split(',');
538
+ for (const segment of segments) {
539
+ // Handle step: */N or N-M/S
540
+ const stepMatch = segment.match(/^(.+)\/(\d+)$/);
541
+ if (stepMatch) {
542
+ const step = parseInt(stepMatch[2], 10);
543
+ if (step <= 0)
544
+ return null;
545
+ let rangeStart = min;
546
+ let rangeEnd = max;
547
+ if (stepMatch[1] !== '*') {
548
+ const rangeMatch = stepMatch[1].match(/^(\d+)-(\d+)$/);
549
+ if (rangeMatch) {
550
+ rangeStart = parseInt(rangeMatch[1], 10);
551
+ rangeEnd = parseInt(rangeMatch[2], 10);
552
+ }
553
+ else {
554
+ rangeStart = parseInt(stepMatch[1], 10);
555
+ rangeEnd = max;
556
+ }
557
+ }
558
+ for (let v = rangeStart; v <= rangeEnd; v += step) {
559
+ if (v >= min && v <= max)
560
+ result.add(v);
561
+ }
562
+ continue;
563
+ }
564
+ // Handle wildcard
565
+ if (segment === '*') {
566
+ for (let v = min; v <= max; v++)
567
+ result.add(v);
568
+ continue;
569
+ }
570
+ // Handle range: N-M
571
+ const rangeMatch = segment.match(/^(\d+)-(\d+)$/);
572
+ if (rangeMatch) {
573
+ const start = parseInt(rangeMatch[1], 10);
574
+ const end = parseInt(rangeMatch[2], 10);
575
+ for (let v = start; v <= end; v++) {
576
+ if (v >= min && v <= max)
577
+ result.add(v);
578
+ }
579
+ continue;
580
+ }
581
+ // Handle specific value
582
+ const value = parseInt(segment, 10);
583
+ if (isNaN(value) || value < min || value > max)
584
+ return null;
585
+ result.add(value);
586
+ }
587
+ return result.size > 0 ? result : null;
588
+ }
589
+ async runExecution(agent, trigger, manual, eventContext) {
590
+ const executionId = `exec-${++this.executionCounter}-${Date.now()}`;
591
+ const stewardId = agent.id;
592
+ const startedAt = createTimestamp();
593
+ const entry = {
594
+ executionId,
595
+ stewardId,
596
+ stewardName: agent.name,
597
+ trigger,
598
+ manual,
599
+ startedAt,
600
+ eventContext,
601
+ };
602
+ this.addHistoryEntry(entry);
603
+ this.runningExecutions.add(executionId);
604
+ this.emitter.emit('execution:started', entry);
605
+ // Update job state if this is a cron job
606
+ for (const job of this.cronJobs.values()) {
607
+ if (job.stewardId === stewardId && isCronTrigger(trigger)) {
608
+ job.isRunning = true;
609
+ }
610
+ }
611
+ const startTime = Date.now();
612
+ try {
613
+ // Execute the steward
614
+ const result = await this.executor(agent, { trigger, eventContext });
615
+ // Complete the entry
616
+ const completedEntry = {
617
+ ...entry,
618
+ completedAt: createTimestamp(),
619
+ result,
620
+ };
621
+ this.updateHistoryEntry(executionId, completedEntry);
622
+ this.runningExecutions.delete(executionId);
623
+ if (result.success) {
624
+ this.emitter.emit('execution:completed', completedEntry);
625
+ }
626
+ else {
627
+ this.emitter.emit('execution:failed', completedEntry);
628
+ }
629
+ // Update job state
630
+ for (const job of this.cronJobs.values()) {
631
+ if (job.stewardId === stewardId) {
632
+ job.isRunning = false;
633
+ job.lastRunAt = completedEntry.completedAt;
634
+ }
635
+ }
636
+ // Update steward metadata with last execution time
637
+ await this.agentRegistry.updateAgentMetadata(stewardId, {
638
+ lastExecutedAt: completedEntry.completedAt,
639
+ });
640
+ return result;
641
+ }
642
+ catch (error) {
643
+ const errorMessage = error instanceof Error ? error.message : String(error);
644
+ const result = {
645
+ success: false,
646
+ error: errorMessage,
647
+ durationMs: Date.now() - startTime,
648
+ };
649
+ const failedEntry = {
650
+ ...entry,
651
+ completedAt: createTimestamp(),
652
+ result,
653
+ };
654
+ this.updateHistoryEntry(executionId, failedEntry);
655
+ this.runningExecutions.delete(executionId);
656
+ this.emitter.emit('execution:failed', failedEntry);
657
+ // Update job state
658
+ for (const job of this.cronJobs.values()) {
659
+ if (job.stewardId === stewardId) {
660
+ job.isRunning = false;
661
+ }
662
+ }
663
+ return result;
664
+ }
665
+ }
666
+ addHistoryEntry(entry) {
667
+ this.executionHistory.push(entry);
668
+ this.pruneHistory();
669
+ }
670
+ updateHistoryEntry(executionId, entry) {
671
+ const index = this.executionHistory.findIndex(e => e.executionId === executionId);
672
+ if (index !== -1) {
673
+ this.executionHistory[index] = entry;
674
+ }
675
+ }
676
+ pruneHistory() {
677
+ // Group by steward and keep only maxHistoryPerSteward entries per steward
678
+ const bysteward = new Map();
679
+ for (const entry of this.executionHistory) {
680
+ if (!bysteward.has(entry.stewardId)) {
681
+ bysteward.set(entry.stewardId, []);
682
+ }
683
+ bysteward.get(entry.stewardId).push(entry);
684
+ }
685
+ const prunedHistory = [];
686
+ for (const entries of bysteward.values()) {
687
+ // Sort by startedAt descending and keep only the first maxHistoryPerSteward
688
+ entries.sort((a, b) => (b.startedAt > a.startedAt ? 1 : -1));
689
+ prunedHistory.push(...entries.slice(0, this.config.maxHistoryPerSteward));
690
+ }
691
+ this.executionHistory = prunedHistory;
692
+ }
693
+ }
694
+ // ============================================================================
695
+ // Factory Function
696
+ // ============================================================================
697
+ /**
698
+ * Creates a StewardScheduler instance
699
+ *
700
+ * @param agentRegistry - The agent registry for looking up stewards
701
+ * @param executor - Function to execute steward logic
702
+ * @param config - Optional configuration
703
+ */
704
+ export function createStewardScheduler(agentRegistry, executor, config) {
705
+ return new StewardSchedulerImpl(agentRegistry, executor, config);
706
+ }
707
+ // ============================================================================
708
+ // Default Executor (placeholder)
709
+ // ============================================================================
710
+ /**
711
+ * Creates a default steward executor that delegates to the appropriate
712
+ * service based on the steward's focus.
713
+ *
714
+ * This is a placeholder - the actual executor would integrate with:
715
+ * - MergeStewardService for 'merge' focus
716
+ * - HealthStewardService for 'health' focus (TB-O24)
717
+ * - etc.
718
+ */
719
+ export function createDefaultStewardExecutor() {
720
+ return async (steward, _context) => {
721
+ const metadata = getAgentMetadata(steward);
722
+ const focus = metadata?.stewardFocus;
723
+ // Placeholder - returns success with info about what would be done
724
+ return {
725
+ success: true,
726
+ output: `Steward ${steward.name} (${focus}) executed successfully`,
727
+ durationMs: 0,
728
+ itemsProcessed: 0,
729
+ };
730
+ };
731
+ }
732
+ //# sourceMappingURL=steward-scheduler.js.map