@herdctl/core 0.0.1

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 (520) hide show
  1. package/.turbo/turbo-build.log +4 -0
  2. package/.turbo/turbo-test.log +219 -0
  3. package/.turbo/turbo-typecheck.log +4 -0
  4. package/coverage/base.css +224 -0
  5. package/coverage/block-navigation.js +87 -0
  6. package/coverage/coverage-final.json +51 -0
  7. package/coverage/favicon.png +0 -0
  8. package/coverage/index.html +251 -0
  9. package/coverage/prettify.css +1 -0
  10. package/coverage/prettify.js +2 -0
  11. package/coverage/sort-arrow-sprite.png +0 -0
  12. package/coverage/sorter.js +210 -0
  13. package/coverage/src/config/index.html +191 -0
  14. package/coverage/src/config/index.ts.html +442 -0
  15. package/coverage/src/config/interpolate.ts.html +652 -0
  16. package/coverage/src/config/loader.ts.html +1501 -0
  17. package/coverage/src/config/merge.ts.html +823 -0
  18. package/coverage/src/config/parser.ts.html +1213 -0
  19. package/coverage/src/config/schema.ts.html +1123 -0
  20. package/coverage/src/fleet-manager/errors.ts.html +2326 -0
  21. package/coverage/src/fleet-manager/event-types.ts.html +1219 -0
  22. package/coverage/src/fleet-manager/fleet-manager.ts.html +7030 -0
  23. package/coverage/src/fleet-manager/index.html +206 -0
  24. package/coverage/src/fleet-manager/index.ts.html +469 -0
  25. package/coverage/src/fleet-manager/job-manager.ts.html +2074 -0
  26. package/coverage/src/fleet-manager/job-queue.ts.html +2479 -0
  27. package/coverage/src/fleet-manager/types.ts.html +2602 -0
  28. package/coverage/src/index.html +116 -0
  29. package/coverage/src/index.ts.html +181 -0
  30. package/coverage/src/runner/errors.ts.html +1006 -0
  31. package/coverage/src/runner/index.html +191 -0
  32. package/coverage/src/runner/index.ts.html +256 -0
  33. package/coverage/src/runner/job-executor.ts.html +1429 -0
  34. package/coverage/src/runner/message-processor.ts.html +1150 -0
  35. package/coverage/src/runner/sdk-adapter.ts.html +658 -0
  36. package/coverage/src/runner/types.ts.html +559 -0
  37. package/coverage/src/scheduler/errors.ts.html +388 -0
  38. package/coverage/src/scheduler/index.html +206 -0
  39. package/coverage/src/scheduler/index.ts.html +244 -0
  40. package/coverage/src/scheduler/interval.ts.html +652 -0
  41. package/coverage/src/scheduler/schedule-runner.ts.html +1411 -0
  42. package/coverage/src/scheduler/schedule-state.ts.html +718 -0
  43. package/coverage/src/scheduler/scheduler.ts.html +1795 -0
  44. package/coverage/src/scheduler/types.ts.html +733 -0
  45. package/coverage/src/state/directory.ts.html +736 -0
  46. package/coverage/src/state/errors.ts.html +376 -0
  47. package/coverage/src/state/fleet-state.ts.html +937 -0
  48. package/coverage/src/state/index.html +221 -0
  49. package/coverage/src/state/index.ts.html +322 -0
  50. package/coverage/src/state/job-metadata.ts.html +1420 -0
  51. package/coverage/src/state/job-output.ts.html +1033 -0
  52. package/coverage/src/state/schemas/fleet-state.ts.html +445 -0
  53. package/coverage/src/state/schemas/index.html +176 -0
  54. package/coverage/src/state/schemas/index.ts.html +286 -0
  55. package/coverage/src/state/schemas/job-metadata.ts.html +628 -0
  56. package/coverage/src/state/schemas/job-output.ts.html +616 -0
  57. package/coverage/src/state/schemas/session-info.ts.html +361 -0
  58. package/coverage/src/state/session.ts.html +844 -0
  59. package/coverage/src/state/types.ts.html +262 -0
  60. package/coverage/src/state/utils/atomic.ts.html +748 -0
  61. package/coverage/src/state/utils/index.html +146 -0
  62. package/coverage/src/state/utils/index.ts.html +103 -0
  63. package/coverage/src/state/utils/reads.ts.html +1621 -0
  64. package/coverage/src/work-sources/adapters/github.ts.html +3583 -0
  65. package/coverage/src/work-sources/adapters/index.html +131 -0
  66. package/coverage/src/work-sources/adapters/index.ts.html +277 -0
  67. package/coverage/src/work-sources/errors.ts.html +298 -0
  68. package/coverage/src/work-sources/index.html +176 -0
  69. package/coverage/src/work-sources/index.ts.html +529 -0
  70. package/coverage/src/work-sources/manager.ts.html +1324 -0
  71. package/coverage/src/work-sources/registry.ts.html +619 -0
  72. package/coverage/src/work-sources/types.ts.html +568 -0
  73. package/dist/config/__tests__/agent.test.d.ts +2 -0
  74. package/dist/config/__tests__/agent.test.d.ts.map +1 -0
  75. package/dist/config/__tests__/agent.test.js +752 -0
  76. package/dist/config/__tests__/agent.test.js.map +1 -0
  77. package/dist/config/__tests__/interpolate.test.d.ts +2 -0
  78. package/dist/config/__tests__/interpolate.test.d.ts.map +1 -0
  79. package/dist/config/__tests__/interpolate.test.js +509 -0
  80. package/dist/config/__tests__/interpolate.test.js.map +1 -0
  81. package/dist/config/__tests__/loader.test.d.ts +2 -0
  82. package/dist/config/__tests__/loader.test.d.ts.map +1 -0
  83. package/dist/config/__tests__/loader.test.js +631 -0
  84. package/dist/config/__tests__/loader.test.js.map +1 -0
  85. package/dist/config/__tests__/merge.test.d.ts +2 -0
  86. package/dist/config/__tests__/merge.test.d.ts.map +1 -0
  87. package/dist/config/__tests__/merge.test.js +672 -0
  88. package/dist/config/__tests__/merge.test.js.map +1 -0
  89. package/dist/config/__tests__/parser.test.d.ts +2 -0
  90. package/dist/config/__tests__/parser.test.d.ts.map +1 -0
  91. package/dist/config/__tests__/parser.test.js +476 -0
  92. package/dist/config/__tests__/parser.test.js.map +1 -0
  93. package/dist/config/__tests__/schema.test.d.ts +2 -0
  94. package/dist/config/__tests__/schema.test.d.ts.map +1 -0
  95. package/dist/config/__tests__/schema.test.js +776 -0
  96. package/dist/config/__tests__/schema.test.js.map +1 -0
  97. package/dist/config/index.d.ts +11 -0
  98. package/dist/config/index.d.ts.map +1 -0
  99. package/dist/config/index.js +26 -0
  100. package/dist/config/index.js.map +1 -0
  101. package/dist/config/interpolate.d.ts +76 -0
  102. package/dist/config/interpolate.d.ts.map +1 -0
  103. package/dist/config/interpolate.js +143 -0
  104. package/dist/config/interpolate.js.map +1 -0
  105. package/dist/config/loader.d.ts +147 -0
  106. package/dist/config/loader.d.ts.map +1 -0
  107. package/dist/config/loader.js +336 -0
  108. package/dist/config/loader.js.map +1 -0
  109. package/dist/config/merge.d.ts +84 -0
  110. package/dist/config/merge.d.ts.map +1 -0
  111. package/dist/config/merge.js +138 -0
  112. package/dist/config/merge.js.map +1 -0
  113. package/dist/config/parser.d.ts +143 -0
  114. package/dist/config/parser.d.ts.map +1 -0
  115. package/dist/config/parser.js +316 -0
  116. package/dist/config/parser.js.map +1 -0
  117. package/dist/config/schema.d.ts +1906 -0
  118. package/dist/config/schema.d.ts.map +1 -0
  119. package/dist/config/schema.js +268 -0
  120. package/dist/config/schema.js.map +1 -0
  121. package/dist/fleet-manager/__tests__/coverage.test.d.ts +13 -0
  122. package/dist/fleet-manager/__tests__/coverage.test.d.ts.map +1 -0
  123. package/dist/fleet-manager/__tests__/coverage.test.js +2282 -0
  124. package/dist/fleet-manager/__tests__/coverage.test.js.map +1 -0
  125. package/dist/fleet-manager/__tests__/errors.test.d.ts +7 -0
  126. package/dist/fleet-manager/__tests__/errors.test.d.ts.map +1 -0
  127. package/dist/fleet-manager/__tests__/errors.test.js +557 -0
  128. package/dist/fleet-manager/__tests__/errors.test.js.map +1 -0
  129. package/dist/fleet-manager/__tests__/event-helpers.test.d.ts +7 -0
  130. package/dist/fleet-manager/__tests__/event-helpers.test.d.ts.map +1 -0
  131. package/dist/fleet-manager/__tests__/event-helpers.test.js +368 -0
  132. package/dist/fleet-manager/__tests__/event-helpers.test.js.map +1 -0
  133. package/dist/fleet-manager/__tests__/integration.test.d.ts +11 -0
  134. package/dist/fleet-manager/__tests__/integration.test.d.ts.map +1 -0
  135. package/dist/fleet-manager/__tests__/integration.test.js +949 -0
  136. package/dist/fleet-manager/__tests__/integration.test.js.map +1 -0
  137. package/dist/fleet-manager/__tests__/job-control.test.d.ts +7 -0
  138. package/dist/fleet-manager/__tests__/job-control.test.d.ts.map +1 -0
  139. package/dist/fleet-manager/__tests__/job-control.test.js +215 -0
  140. package/dist/fleet-manager/__tests__/job-control.test.js.map +1 -0
  141. package/dist/fleet-manager/__tests__/job-manager.test.d.ts +7 -0
  142. package/dist/fleet-manager/__tests__/job-manager.test.d.ts.map +1 -0
  143. package/dist/fleet-manager/__tests__/job-manager.test.js +659 -0
  144. package/dist/fleet-manager/__tests__/job-manager.test.js.map +1 -0
  145. package/dist/fleet-manager/__tests__/job-queue.test.d.ts +5 -0
  146. package/dist/fleet-manager/__tests__/job-queue.test.d.ts.map +1 -0
  147. package/dist/fleet-manager/__tests__/job-queue.test.js +315 -0
  148. package/dist/fleet-manager/__tests__/job-queue.test.js.map +1 -0
  149. package/dist/fleet-manager/__tests__/reload.test.d.ts +7 -0
  150. package/dist/fleet-manager/__tests__/reload.test.d.ts.map +1 -0
  151. package/dist/fleet-manager/__tests__/reload.test.js +609 -0
  152. package/dist/fleet-manager/__tests__/reload.test.js.map +1 -0
  153. package/dist/fleet-manager/__tests__/status-queries.test.d.ts +7 -0
  154. package/dist/fleet-manager/__tests__/status-queries.test.d.ts.map +1 -0
  155. package/dist/fleet-manager/__tests__/status-queries.test.js +488 -0
  156. package/dist/fleet-manager/__tests__/status-queries.test.js.map +1 -0
  157. package/dist/fleet-manager/__tests__/trigger.test.d.ts +7 -0
  158. package/dist/fleet-manager/__tests__/trigger.test.d.ts.map +1 -0
  159. package/dist/fleet-manager/__tests__/trigger.test.js +471 -0
  160. package/dist/fleet-manager/__tests__/trigger.test.js.map +1 -0
  161. package/dist/fleet-manager/errors.d.ts +407 -0
  162. package/dist/fleet-manager/errors.d.ts.map +1 -0
  163. package/dist/fleet-manager/errors.js +569 -0
  164. package/dist/fleet-manager/errors.js.map +1 -0
  165. package/dist/fleet-manager/event-types.d.ts +302 -0
  166. package/dist/fleet-manager/event-types.d.ts.map +1 -0
  167. package/dist/fleet-manager/event-types.js +9 -0
  168. package/dist/fleet-manager/event-types.js.map +1 -0
  169. package/dist/fleet-manager/fleet-manager.d.ts +699 -0
  170. package/dist/fleet-manager/fleet-manager.d.ts.map +1 -0
  171. package/dist/fleet-manager/fleet-manager.js +1906 -0
  172. package/dist/fleet-manager/fleet-manager.js.map +1 -0
  173. package/dist/fleet-manager/index.d.ts +17 -0
  174. package/dist/fleet-manager/index.d.ts.map +1 -0
  175. package/dist/fleet-manager/index.js +29 -0
  176. package/dist/fleet-manager/index.js.map +1 -0
  177. package/dist/fleet-manager/job-manager.d.ts +271 -0
  178. package/dist/fleet-manager/job-manager.d.ts.map +1 -0
  179. package/dist/fleet-manager/job-manager.js +443 -0
  180. package/dist/fleet-manager/job-manager.js.map +1 -0
  181. package/dist/fleet-manager/job-queue.d.ts +422 -0
  182. package/dist/fleet-manager/job-queue.d.ts.map +1 -0
  183. package/dist/fleet-manager/job-queue.js +448 -0
  184. package/dist/fleet-manager/job-queue.js.map +1 -0
  185. package/dist/fleet-manager/types.d.ts +680 -0
  186. package/dist/fleet-manager/types.d.ts.map +1 -0
  187. package/dist/fleet-manager/types.js +8 -0
  188. package/dist/fleet-manager/types.js.map +1 -0
  189. package/dist/index.d.ts +20 -0
  190. package/dist/index.d.ts.map +1 -0
  191. package/dist/index.js +26 -0
  192. package/dist/index.js.map +1 -0
  193. package/dist/runner/__tests__/errors.test.d.ts +2 -0
  194. package/dist/runner/__tests__/errors.test.d.ts.map +1 -0
  195. package/dist/runner/__tests__/errors.test.js +264 -0
  196. package/dist/runner/__tests__/errors.test.js.map +1 -0
  197. package/dist/runner/__tests__/job-executor.test.d.ts +2 -0
  198. package/dist/runner/__tests__/job-executor.test.d.ts.map +1 -0
  199. package/dist/runner/__tests__/job-executor.test.js +1345 -0
  200. package/dist/runner/__tests__/job-executor.test.js.map +1 -0
  201. package/dist/runner/__tests__/message-processor.test.d.ts +2 -0
  202. package/dist/runner/__tests__/message-processor.test.d.ts.map +1 -0
  203. package/dist/runner/__tests__/message-processor.test.js +768 -0
  204. package/dist/runner/__tests__/message-processor.test.js.map +1 -0
  205. package/dist/runner/__tests__/sdk-adapter.test.d.ts +2 -0
  206. package/dist/runner/__tests__/sdk-adapter.test.d.ts.map +1 -0
  207. package/dist/runner/__tests__/sdk-adapter.test.js +554 -0
  208. package/dist/runner/__tests__/sdk-adapter.test.js.map +1 -0
  209. package/dist/runner/errors.d.ts +121 -0
  210. package/dist/runner/errors.d.ts.map +1 -0
  211. package/dist/runner/errors.js +212 -0
  212. package/dist/runner/errors.js.map +1 -0
  213. package/dist/runner/index.d.ts +12 -0
  214. package/dist/runner/index.d.ts.map +1 -0
  215. package/dist/runner/index.js +15 -0
  216. package/dist/runner/index.js.map +1 -0
  217. package/dist/runner/job-executor.d.ts +98 -0
  218. package/dist/runner/job-executor.d.ts.map +1 -0
  219. package/dist/runner/job-executor.js +333 -0
  220. package/dist/runner/job-executor.js.map +1 -0
  221. package/dist/runner/message-processor.d.ts +45 -0
  222. package/dist/runner/message-processor.d.ts.map +1 -0
  223. package/dist/runner/message-processor.js +294 -0
  224. package/dist/runner/message-processor.js.map +1 -0
  225. package/dist/runner/sdk-adapter.d.ts +60 -0
  226. package/dist/runner/sdk-adapter.d.ts.map +1 -0
  227. package/dist/runner/sdk-adapter.js +138 -0
  228. package/dist/runner/sdk-adapter.js.map +1 -0
  229. package/dist/runner/types.d.ts +135 -0
  230. package/dist/runner/types.d.ts.map +1 -0
  231. package/dist/runner/types.js +7 -0
  232. package/dist/runner/types.js.map +1 -0
  233. package/dist/scheduler/__tests__/errors.test.d.ts +2 -0
  234. package/dist/scheduler/__tests__/errors.test.d.ts.map +1 -0
  235. package/dist/scheduler/__tests__/errors.test.js +101 -0
  236. package/dist/scheduler/__tests__/errors.test.js.map +1 -0
  237. package/dist/scheduler/__tests__/interval.test.d.ts +2 -0
  238. package/dist/scheduler/__tests__/interval.test.d.ts.map +1 -0
  239. package/dist/scheduler/__tests__/interval.test.js +419 -0
  240. package/dist/scheduler/__tests__/interval.test.js.map +1 -0
  241. package/dist/scheduler/__tests__/schedule-runner.test.d.ts +2 -0
  242. package/dist/scheduler/__tests__/schedule-runner.test.d.ts.map +1 -0
  243. package/dist/scheduler/__tests__/schedule-runner.test.js +634 -0
  244. package/dist/scheduler/__tests__/schedule-runner.test.js.map +1 -0
  245. package/dist/scheduler/__tests__/schedule-state.test.d.ts +2 -0
  246. package/dist/scheduler/__tests__/schedule-state.test.d.ts.map +1 -0
  247. package/dist/scheduler/__tests__/schedule-state.test.js +572 -0
  248. package/dist/scheduler/__tests__/schedule-state.test.js.map +1 -0
  249. package/dist/scheduler/__tests__/scheduler.test.d.ts +2 -0
  250. package/dist/scheduler/__tests__/scheduler.test.d.ts.map +1 -0
  251. package/dist/scheduler/__tests__/scheduler.test.js +987 -0
  252. package/dist/scheduler/__tests__/scheduler.test.js.map +1 -0
  253. package/dist/scheduler/errors.d.ts +61 -0
  254. package/dist/scheduler/errors.d.ts.map +1 -0
  255. package/dist/scheduler/errors.js +81 -0
  256. package/dist/scheduler/errors.js.map +1 -0
  257. package/dist/scheduler/index.d.ts +13 -0
  258. package/dist/scheduler/index.d.ts.map +1 -0
  259. package/dist/scheduler/index.js +17 -0
  260. package/dist/scheduler/index.js.map +1 -0
  261. package/dist/scheduler/interval.d.ts +64 -0
  262. package/dist/scheduler/interval.d.ts.map +1 -0
  263. package/dist/scheduler/interval.js +139 -0
  264. package/dist/scheduler/interval.js.map +1 -0
  265. package/dist/scheduler/schedule-runner.d.ts +149 -0
  266. package/dist/scheduler/schedule-runner.d.ts.map +1 -0
  267. package/dist/scheduler/schedule-runner.js +277 -0
  268. package/dist/scheduler/schedule-runner.js.map +1 -0
  269. package/dist/scheduler/schedule-state.d.ts +105 -0
  270. package/dist/scheduler/schedule-state.d.ts.map +1 -0
  271. package/dist/scheduler/schedule-state.js +151 -0
  272. package/dist/scheduler/schedule-state.js.map +1 -0
  273. package/dist/scheduler/scheduler.d.ts +138 -0
  274. package/dist/scheduler/scheduler.d.ts.map +1 -0
  275. package/dist/scheduler/scheduler.js +423 -0
  276. package/dist/scheduler/scheduler.js.map +1 -0
  277. package/dist/scheduler/types.d.ts +160 -0
  278. package/dist/scheduler/types.d.ts.map +1 -0
  279. package/dist/scheduler/types.js +8 -0
  280. package/dist/scheduler/types.js.map +1 -0
  281. package/dist/state/__tests__/directory.test.d.ts +2 -0
  282. package/dist/state/__tests__/directory.test.d.ts.map +1 -0
  283. package/dist/state/__tests__/directory.test.js +414 -0
  284. package/dist/state/__tests__/directory.test.js.map +1 -0
  285. package/dist/state/__tests__/fleet-state.test.d.ts +2 -0
  286. package/dist/state/__tests__/fleet-state.test.d.ts.map +1 -0
  287. package/dist/state/__tests__/fleet-state.test.js +696 -0
  288. package/dist/state/__tests__/fleet-state.test.js.map +1 -0
  289. package/dist/state/__tests__/job-metadata-schema.test.d.ts +2 -0
  290. package/dist/state/__tests__/job-metadata-schema.test.d.ts.map +1 -0
  291. package/dist/state/__tests__/job-metadata-schema.test.js +329 -0
  292. package/dist/state/__tests__/job-metadata-schema.test.js.map +1 -0
  293. package/dist/state/__tests__/job-metadata.test.d.ts +2 -0
  294. package/dist/state/__tests__/job-metadata.test.d.ts.map +1 -0
  295. package/dist/state/__tests__/job-metadata.test.js +667 -0
  296. package/dist/state/__tests__/job-metadata.test.js.map +1 -0
  297. package/dist/state/__tests__/job-output.test.d.ts +2 -0
  298. package/dist/state/__tests__/job-output.test.d.ts.map +1 -0
  299. package/dist/state/__tests__/job-output.test.js +672 -0
  300. package/dist/state/__tests__/job-output.test.js.map +1 -0
  301. package/dist/state/__tests__/session-schema.test.d.ts +2 -0
  302. package/dist/state/__tests__/session-schema.test.d.ts.map +1 -0
  303. package/dist/state/__tests__/session-schema.test.js +323 -0
  304. package/dist/state/__tests__/session-schema.test.js.map +1 -0
  305. package/dist/state/__tests__/session.test.d.ts +2 -0
  306. package/dist/state/__tests__/session.test.d.ts.map +1 -0
  307. package/dist/state/__tests__/session.test.js +468 -0
  308. package/dist/state/__tests__/session.test.js.map +1 -0
  309. package/dist/state/directory.d.ts +42 -0
  310. package/dist/state/directory.d.ts.map +1 -0
  311. package/dist/state/directory.js +170 -0
  312. package/dist/state/directory.js.map +1 -0
  313. package/dist/state/errors.d.ts +44 -0
  314. package/dist/state/errors.d.ts.map +1 -0
  315. package/dist/state/errors.js +82 -0
  316. package/dist/state/errors.js.map +1 -0
  317. package/dist/state/fleet-state.d.ts +126 -0
  318. package/dist/state/fleet-state.d.ts.map +1 -0
  319. package/dist/state/fleet-state.js +196 -0
  320. package/dist/state/fleet-state.js.map +1 -0
  321. package/dist/state/index.d.ts +21 -0
  322. package/dist/state/index.d.ts.map +1 -0
  323. package/dist/state/index.js +30 -0
  324. package/dist/state/index.js.map +1 -0
  325. package/dist/state/job-metadata.d.ts +151 -0
  326. package/dist/state/job-metadata.d.ts.map +1 -0
  327. package/dist/state/job-metadata.js +287 -0
  328. package/dist/state/job-metadata.js.map +1 -0
  329. package/dist/state/job-output.d.ts +116 -0
  330. package/dist/state/job-output.d.ts.map +1 -0
  331. package/dist/state/job-output.js +218 -0
  332. package/dist/state/job-output.js.map +1 -0
  333. package/dist/state/schemas/__tests__/job-output.test.d.ts +2 -0
  334. package/dist/state/schemas/__tests__/job-output.test.d.ts.map +1 -0
  335. package/dist/state/schemas/__tests__/job-output.test.js +279 -0
  336. package/dist/state/schemas/__tests__/job-output.test.js.map +1 -0
  337. package/dist/state/schemas/fleet-state.d.ts +249 -0
  338. package/dist/state/schemas/fleet-state.d.ts.map +1 -0
  339. package/dist/state/schemas/fleet-state.js +97 -0
  340. package/dist/state/schemas/fleet-state.js.map +1 -0
  341. package/dist/state/schemas/index.d.ts +10 -0
  342. package/dist/state/schemas/index.d.ts.map +1 -0
  343. package/dist/state/schemas/index.js +10 -0
  344. package/dist/state/schemas/index.js.map +1 -0
  345. package/dist/state/schemas/job-metadata.d.ts +118 -0
  346. package/dist/state/schemas/job-metadata.d.ts.map +1 -0
  347. package/dist/state/schemas/job-metadata.js +123 -0
  348. package/dist/state/schemas/job-metadata.js.map +1 -0
  349. package/dist/state/schemas/job-output.d.ts +291 -0
  350. package/dist/state/schemas/job-output.d.ts.map +1 -0
  351. package/dist/state/schemas/job-output.js +132 -0
  352. package/dist/state/schemas/job-output.js.map +1 -0
  353. package/dist/state/schemas/session-info.d.ts +65 -0
  354. package/dist/state/schemas/session-info.d.ts.map +1 -0
  355. package/dist/state/schemas/session-info.js +58 -0
  356. package/dist/state/schemas/session-info.js.map +1 -0
  357. package/dist/state/session.d.ts +92 -0
  358. package/dist/state/session.d.ts.map +1 -0
  359. package/dist/state/session.js +173 -0
  360. package/dist/state/session.js.map +1 -0
  361. package/dist/state/types.d.ts +54 -0
  362. package/dist/state/types.d.ts.map +1 -0
  363. package/dist/state/types.js +18 -0
  364. package/dist/state/types.js.map +1 -0
  365. package/dist/state/utils/__tests__/atomic.test.d.ts +2 -0
  366. package/dist/state/utils/__tests__/atomic.test.d.ts.map +1 -0
  367. package/dist/state/utils/__tests__/atomic.test.js +537 -0
  368. package/dist/state/utils/__tests__/atomic.test.js.map +1 -0
  369. package/dist/state/utils/__tests__/reads.test.d.ts +2 -0
  370. package/dist/state/utils/__tests__/reads.test.d.ts.map +1 -0
  371. package/dist/state/utils/__tests__/reads.test.js +792 -0
  372. package/dist/state/utils/__tests__/reads.test.js.map +1 -0
  373. package/dist/state/utils/atomic.d.ts +89 -0
  374. package/dist/state/utils/atomic.d.ts.map +1 -0
  375. package/dist/state/utils/atomic.js +157 -0
  376. package/dist/state/utils/atomic.js.map +1 -0
  377. package/dist/state/utils/index.d.ts +6 -0
  378. package/dist/state/utils/index.d.ts.map +1 -0
  379. package/dist/state/utils/index.js +6 -0
  380. package/dist/state/utils/index.js.map +1 -0
  381. package/dist/state/utils/reads.d.ts +196 -0
  382. package/dist/state/utils/reads.d.ts.map +1 -0
  383. package/dist/state/utils/reads.js +346 -0
  384. package/dist/state/utils/reads.js.map +1 -0
  385. package/dist/work-sources/__tests__/github.test.d.ts +2 -0
  386. package/dist/work-sources/__tests__/github.test.d.ts.map +1 -0
  387. package/dist/work-sources/__tests__/github.test.js +1334 -0
  388. package/dist/work-sources/__tests__/github.test.js.map +1 -0
  389. package/dist/work-sources/__tests__/manager.test.d.ts +2 -0
  390. package/dist/work-sources/__tests__/manager.test.d.ts.map +1 -0
  391. package/dist/work-sources/__tests__/manager.test.js +424 -0
  392. package/dist/work-sources/__tests__/manager.test.js.map +1 -0
  393. package/dist/work-sources/__tests__/registry.test.d.ts +2 -0
  394. package/dist/work-sources/__tests__/registry.test.d.ts.map +1 -0
  395. package/dist/work-sources/__tests__/registry.test.js +381 -0
  396. package/dist/work-sources/__tests__/registry.test.js.map +1 -0
  397. package/dist/work-sources/__tests__/types.test.d.ts +2 -0
  398. package/dist/work-sources/__tests__/types.test.d.ts.map +1 -0
  399. package/dist/work-sources/__tests__/types.test.js +406 -0
  400. package/dist/work-sources/__tests__/types.test.js.map +1 -0
  401. package/dist/work-sources/adapters/github.d.ts +290 -0
  402. package/dist/work-sources/adapters/github.d.ts.map +1 -0
  403. package/dist/work-sources/adapters/github.js +803 -0
  404. package/dist/work-sources/adapters/github.js.map +1 -0
  405. package/dist/work-sources/adapters/index.d.ts +10 -0
  406. package/dist/work-sources/adapters/index.d.ts.map +1 -0
  407. package/dist/work-sources/adapters/index.js +31 -0
  408. package/dist/work-sources/adapters/index.js.map +1 -0
  409. package/dist/work-sources/errors.d.ts +40 -0
  410. package/dist/work-sources/errors.d.ts.map +1 -0
  411. package/dist/work-sources/errors.js +54 -0
  412. package/dist/work-sources/errors.js.map +1 -0
  413. package/dist/work-sources/index.d.ts +105 -0
  414. package/dist/work-sources/index.d.ts.map +1 -0
  415. package/dist/work-sources/index.js +24 -0
  416. package/dist/work-sources/index.js.map +1 -0
  417. package/dist/work-sources/manager.d.ts +370 -0
  418. package/dist/work-sources/manager.d.ts.map +1 -0
  419. package/dist/work-sources/manager.js +61 -0
  420. package/dist/work-sources/manager.js.map +1 -0
  421. package/dist/work-sources/registry.d.ts +128 -0
  422. package/dist/work-sources/registry.d.ts.map +1 -0
  423. package/dist/work-sources/registry.js +132 -0
  424. package/dist/work-sources/registry.js.map +1 -0
  425. package/dist/work-sources/types.d.ts +127 -0
  426. package/dist/work-sources/types.d.ts.map +1 -0
  427. package/dist/work-sources/types.js +8 -0
  428. package/dist/work-sources/types.js.map +1 -0
  429. package/package.json +23 -0
  430. package/src/config/__tests__/agent.test.ts +864 -0
  431. package/src/config/__tests__/interpolate.test.ts +644 -0
  432. package/src/config/__tests__/loader.test.ts +784 -0
  433. package/src/config/__tests__/merge.test.ts +751 -0
  434. package/src/config/__tests__/parser.test.ts +533 -0
  435. package/src/config/__tests__/schema.test.ts +873 -0
  436. package/src/config/index.ts +119 -0
  437. package/src/config/interpolate.ts +189 -0
  438. package/src/config/loader.ts +472 -0
  439. package/src/config/merge.ts +246 -0
  440. package/src/config/parser.ts +376 -0
  441. package/src/config/schema.ts +346 -0
  442. package/src/fleet-manager/__tests__/coverage.test.ts +2869 -0
  443. package/src/fleet-manager/__tests__/errors.test.ts +660 -0
  444. package/src/fleet-manager/__tests__/event-helpers.test.ts +448 -0
  445. package/src/fleet-manager/__tests__/integration.test.ts +1209 -0
  446. package/src/fleet-manager/__tests__/job-control.test.ts +283 -0
  447. package/src/fleet-manager/__tests__/job-manager.test.ts +869 -0
  448. package/src/fleet-manager/__tests__/job-queue.test.ts +401 -0
  449. package/src/fleet-manager/__tests__/reload.test.ts +751 -0
  450. package/src/fleet-manager/__tests__/status-queries.test.ts +595 -0
  451. package/src/fleet-manager/__tests__/trigger.test.ts +601 -0
  452. package/src/fleet-manager/errors.ts +747 -0
  453. package/src/fleet-manager/event-types.ts +378 -0
  454. package/src/fleet-manager/fleet-manager.ts +2315 -0
  455. package/src/fleet-manager/index.ts +128 -0
  456. package/src/fleet-manager/job-manager.ts +663 -0
  457. package/src/fleet-manager/job-queue.ts +798 -0
  458. package/src/fleet-manager/types.ts +839 -0
  459. package/src/index.ts +32 -0
  460. package/src/runner/__tests__/errors.test.ts +382 -0
  461. package/src/runner/__tests__/job-executor.test.ts +1708 -0
  462. package/src/runner/__tests__/message-processor.test.ts +960 -0
  463. package/src/runner/__tests__/sdk-adapter.test.ts +626 -0
  464. package/src/runner/errors.ts +307 -0
  465. package/src/runner/index.ts +57 -0
  466. package/src/runner/job-executor.ts +448 -0
  467. package/src/runner/message-processor.ts +355 -0
  468. package/src/runner/sdk-adapter.ts +191 -0
  469. package/src/runner/types.ts +158 -0
  470. package/src/scheduler/__tests__/errors.test.ts +159 -0
  471. package/src/scheduler/__tests__/interval.test.ts +515 -0
  472. package/src/scheduler/__tests__/schedule-runner.test.ts +798 -0
  473. package/src/scheduler/__tests__/schedule-state.test.ts +671 -0
  474. package/src/scheduler/__tests__/scheduler.test.ts +1280 -0
  475. package/src/scheduler/errors.ts +101 -0
  476. package/src/scheduler/index.ts +53 -0
  477. package/src/scheduler/interval.ts +189 -0
  478. package/src/scheduler/schedule-runner.ts +442 -0
  479. package/src/scheduler/schedule-state.ts +211 -0
  480. package/src/scheduler/scheduler.ts +570 -0
  481. package/src/scheduler/types.ts +216 -0
  482. package/src/state/__tests__/directory.test.ts +595 -0
  483. package/src/state/__tests__/fleet-state.test.ts +868 -0
  484. package/src/state/__tests__/job-metadata-schema.test.ts +414 -0
  485. package/src/state/__tests__/job-metadata.test.ts +831 -0
  486. package/src/state/__tests__/job-output.test.ts +856 -0
  487. package/src/state/__tests__/session-schema.test.ts +378 -0
  488. package/src/state/__tests__/session.test.ts +604 -0
  489. package/src/state/directory.ts +217 -0
  490. package/src/state/errors.ts +97 -0
  491. package/src/state/fleet-state.ts +284 -0
  492. package/src/state/index.ts +79 -0
  493. package/src/state/job-metadata.ts +445 -0
  494. package/src/state/job-output.ts +316 -0
  495. package/src/state/schemas/__tests__/job-output.test.ts +338 -0
  496. package/src/state/schemas/fleet-state.ts +120 -0
  497. package/src/state/schemas/index.ts +67 -0
  498. package/src/state/schemas/job-metadata.ts +181 -0
  499. package/src/state/schemas/job-output.ts +177 -0
  500. package/src/state/schemas/session-info.ts +92 -0
  501. package/src/state/session.ts +253 -0
  502. package/src/state/types.ts +59 -0
  503. package/src/state/utils/__tests__/atomic.test.ts +723 -0
  504. package/src/state/utils/__tests__/reads.test.ts +1071 -0
  505. package/src/state/utils/atomic.ts +221 -0
  506. package/src/state/utils/index.ts +6 -0
  507. package/src/state/utils/reads.ts +512 -0
  508. package/src/work-sources/__tests__/github.test.ts +1800 -0
  509. package/src/work-sources/__tests__/manager.test.ts +529 -0
  510. package/src/work-sources/__tests__/registry.test.ts +477 -0
  511. package/src/work-sources/__tests__/types.test.ts +479 -0
  512. package/src/work-sources/adapters/github.ts +1166 -0
  513. package/src/work-sources/adapters/index.ts +64 -0
  514. package/src/work-sources/errors.ts +71 -0
  515. package/src/work-sources/index.ts +148 -0
  516. package/src/work-sources/manager.ts +413 -0
  517. package/src/work-sources/registry.ts +178 -0
  518. package/src/work-sources/types.ts +161 -0
  519. package/tsconfig.json +9 -0
  520. package/vitest.config.ts +19 -0
@@ -0,0 +1,442 @@
1
+ /**
2
+ * Schedule Runner for executing triggered schedules
3
+ *
4
+ * Handles the actual execution of scheduled work by:
5
+ * 1. Fetching work items from work sources (if configured)
6
+ * 2. Building prompts from schedule config and work items
7
+ * 3. Invoking the JobExecutor to run the agent
8
+ * 4. Updating schedule state and reporting outcomes
9
+ */
10
+
11
+ import type { ResolvedAgent, Schedule } from "../config/index.js";
12
+ import type { ScheduleState } from "../state/schemas/fleet-state.js";
13
+ import type { RunnerResult, SDKQueryFunction } from "../runner/index.js";
14
+ import type {
15
+ WorkSourceManager,
16
+ WorkItem,
17
+ WorkResult,
18
+ WorkOutcome,
19
+ } from "../work-sources/index.js";
20
+ import { JobExecutor, type JobExecutorOptions } from "../runner/index.js";
21
+ import {
22
+ updateScheduleState,
23
+ type ScheduleStateLogger,
24
+ } from "./schedule-state.js";
25
+ import { calculateNextTrigger } from "./interval.js";
26
+
27
+ // =============================================================================
28
+ // Types
29
+ // =============================================================================
30
+
31
+ /**
32
+ * Logger interface for schedule runner
33
+ */
34
+ export interface ScheduleRunnerLogger {
35
+ debug: (message: string) => void;
36
+ info: (message: string) => void;
37
+ warn: (message: string) => void;
38
+ error: (message: string) => void;
39
+ }
40
+
41
+ /**
42
+ * Trigger metadata passed to the JobExecutor
43
+ */
44
+ export interface TriggerMetadata {
45
+ /** The type of trigger */
46
+ triggerType: "interval";
47
+ /** The name of the schedule that triggered */
48
+ schedule: string;
49
+ /** Work item ID if this run is processing a work item */
50
+ workItemId?: string;
51
+ /** Work item title for reference */
52
+ workItemTitle?: string;
53
+ }
54
+
55
+ /**
56
+ * Options for running a schedule
57
+ */
58
+ export interface RunScheduleOptions {
59
+ /** The agent to run */
60
+ agent: ResolvedAgent;
61
+ /** The name of the schedule */
62
+ scheduleName: string;
63
+ /** The schedule configuration */
64
+ schedule: Schedule;
65
+ /** Current schedule state */
66
+ scheduleState: ScheduleState;
67
+ /** Path to the state directory (e.g., .herdctl) */
68
+ stateDir: string;
69
+ /** The SDK query function for agent execution */
70
+ sdkQuery: SDKQueryFunction;
71
+ /** Optional work source manager for fetching work items */
72
+ workSourceManager?: WorkSourceManager;
73
+ /** Optional logger */
74
+ logger?: ScheduleRunnerLogger;
75
+ /** Optional job executor options */
76
+ executorOptions?: JobExecutorOptions;
77
+ }
78
+
79
+ /**
80
+ * Result of running a schedule, extending RunnerResult with schedule-specific info
81
+ */
82
+ export interface ScheduleRunResult extends RunnerResult {
83
+ /** The work item that was processed (if any) */
84
+ workItem?: WorkItem;
85
+ /** Whether a work item was fetched and processed */
86
+ processedWorkItem: boolean;
87
+ }
88
+
89
+ // =============================================================================
90
+ // Default Logger
91
+ // =============================================================================
92
+
93
+ const defaultLogger: ScheduleRunnerLogger = {
94
+ debug: (message: string) => console.debug(`[schedule-runner] ${message}`),
95
+ info: (message: string) => console.info(`[schedule-runner] ${message}`),
96
+ warn: (message: string) => console.warn(`[schedule-runner] ${message}`),
97
+ error: (message: string) => console.error(`[schedule-runner] ${message}`),
98
+ };
99
+
100
+ // =============================================================================
101
+ // Build Schedule Prompt
102
+ // =============================================================================
103
+
104
+ /**
105
+ * Build the prompt for a scheduled run
106
+ *
107
+ * Constructs the prompt by combining:
108
+ * 1. The schedule's configured prompt (if any)
109
+ * 2. Work item details (if a work item was fetched)
110
+ *
111
+ * @param schedule - The schedule configuration
112
+ * @param workItem - Optional work item fetched from work source
113
+ * @returns The constructed prompt string
114
+ *
115
+ * @example Without work item
116
+ * ```typescript
117
+ * const prompt = buildSchedulePrompt(
118
+ * { type: 'interval', interval: '1h', prompt: 'Check for updates' }
119
+ * );
120
+ * // => "Check for updates"
121
+ * ```
122
+ *
123
+ * @example With work item
124
+ * ```typescript
125
+ * const prompt = buildSchedulePrompt(
126
+ * { type: 'interval', interval: '1h', prompt: 'Process this issue:' },
127
+ * { title: 'Fix bug', description: 'There is a bug in auth.ts', ... }
128
+ * );
129
+ * // => "Process this issue:\n\n## Work Item: Fix bug\n\nThere is a bug in auth.ts\n\n..."
130
+ * ```
131
+ */
132
+ export function buildSchedulePrompt(
133
+ schedule: Schedule,
134
+ workItem?: WorkItem
135
+ ): string {
136
+ const parts: string[] = [];
137
+
138
+ // Add schedule prompt if configured
139
+ if (schedule.prompt) {
140
+ parts.push(schedule.prompt);
141
+ }
142
+
143
+ // Add work item details if provided
144
+ if (workItem) {
145
+ const workItemSection = formatWorkItem(workItem);
146
+ parts.push(workItemSection);
147
+ }
148
+
149
+ // If no prompt and no work item, provide a default
150
+ if (parts.length === 0) {
151
+ return "Execute scheduled task.";
152
+ }
153
+
154
+ return parts.join("\n\n");
155
+ }
156
+
157
+ /**
158
+ * Format a work item for inclusion in a prompt
159
+ */
160
+ function formatWorkItem(workItem: WorkItem): string {
161
+ const lines: string[] = [];
162
+
163
+ lines.push(`## Work Item: ${workItem.title}`);
164
+ lines.push("");
165
+
166
+ if (workItem.description) {
167
+ lines.push(workItem.description);
168
+ lines.push("");
169
+ }
170
+
171
+ // Add metadata
172
+ const metadata: string[] = [];
173
+ metadata.push(`- **Source:** ${workItem.source}`);
174
+ metadata.push(`- **ID:** ${workItem.externalId}`);
175
+ metadata.push(`- **Priority:** ${workItem.priority}`);
176
+
177
+ if (workItem.labels.length > 0) {
178
+ metadata.push(`- **Labels:** ${workItem.labels.join(", ")}`);
179
+ }
180
+
181
+ if (workItem.url) {
182
+ metadata.push(`- **URL:** ${workItem.url}`);
183
+ }
184
+
185
+ lines.push(metadata.join("\n"));
186
+
187
+ return lines.join("\n");
188
+ }
189
+
190
+ // =============================================================================
191
+ // Run Schedule
192
+ // =============================================================================
193
+
194
+ /**
195
+ * Execute a triggered schedule
196
+ *
197
+ * This function handles the complete lifecycle of a scheduled execution:
198
+ * 1. Updates schedule state to 'running'
199
+ * 2. Fetches work item from work source (if configured)
200
+ * 3. Builds the prompt from schedule config and work item
201
+ * 4. Invokes the JobExecutor to run the agent
202
+ * 5. Reports outcome to work source (if applicable)
203
+ * 6. Updates schedule state with last_run_at and next_run_at
204
+ *
205
+ * @param options - Options for running the schedule
206
+ * @returns Result of the schedule execution
207
+ *
208
+ * @example Basic usage
209
+ * ```typescript
210
+ * const result = await runSchedule({
211
+ * agent: resolvedAgent,
212
+ * scheduleName: 'hourly',
213
+ * schedule: { type: 'interval', interval: '1h', prompt: 'Check status' },
214
+ * scheduleState: { status: 'idle', last_run_at: null },
215
+ * stateDir: '.herdctl',
216
+ * sdkQuery: query,
217
+ * });
218
+ *
219
+ * console.log(`Job ${result.jobId} completed: ${result.success}`);
220
+ * ```
221
+ *
222
+ * @example With work source
223
+ * ```typescript
224
+ * const result = await runSchedule({
225
+ * agent: resolvedAgent,
226
+ * scheduleName: 'issue-processor',
227
+ * schedule: {
228
+ * type: 'interval',
229
+ * interval: '5m',
230
+ * prompt: 'Process this GitHub issue:',
231
+ * work_source: { type: 'github', owner: 'org', repo: 'repo' }
232
+ * },
233
+ * scheduleState: { status: 'idle', last_run_at: null },
234
+ * stateDir: '.herdctl',
235
+ * sdkQuery: query,
236
+ * workSourceManager: manager,
237
+ * });
238
+ *
239
+ * if (result.workItem) {
240
+ * console.log(`Processed work item: ${result.workItem.title}`);
241
+ * }
242
+ * ```
243
+ */
244
+ export async function runSchedule(
245
+ options: RunScheduleOptions
246
+ ): Promise<ScheduleRunResult> {
247
+ const {
248
+ agent,
249
+ scheduleName,
250
+ schedule,
251
+ stateDir,
252
+ sdkQuery,
253
+ workSourceManager,
254
+ logger = defaultLogger,
255
+ executorOptions,
256
+ } = options;
257
+
258
+ const stateLogger: ScheduleStateLogger = { warn: logger.warn };
259
+
260
+ logger.info(`Running schedule ${agent.name}/${scheduleName}`);
261
+
262
+ // Step 1: Update schedule state to 'running'
263
+ await updateScheduleState(
264
+ stateDir,
265
+ agent.name,
266
+ scheduleName,
267
+ {
268
+ status: "running",
269
+ last_run_at: new Date().toISOString(),
270
+ },
271
+ { logger: stateLogger }
272
+ );
273
+
274
+ let workItem: WorkItem | undefined;
275
+ let processedWorkItem = false;
276
+
277
+ try {
278
+ // Step 2: Fetch work item if schedule has work_source configured
279
+ if (schedule.work_source && workSourceManager) {
280
+ logger.debug(
281
+ `Fetching work item for ${agent.name}/${scheduleName} from ${schedule.work_source.type}`
282
+ );
283
+
284
+ const workResult = await workSourceManager.getNextWorkItem(agent, {
285
+ autoClaim: true,
286
+ });
287
+
288
+ if (workResult.item && workResult.claimed) {
289
+ workItem = workResult.item;
290
+ processedWorkItem = true;
291
+ logger.info(
292
+ `Claimed work item ${workItem.id}: ${workItem.title}`
293
+ );
294
+ } else if (workResult.item && !workResult.claimed) {
295
+ // Work item found but claim failed (race condition)
296
+ logger.warn(
297
+ `Work item ${workResult.item.id} found but claim failed: ${workResult.claimResult?.reason}`
298
+ );
299
+ } else {
300
+ // No work available
301
+ logger.debug(
302
+ `No work items available for ${agent.name}/${scheduleName}`
303
+ );
304
+ }
305
+ }
306
+
307
+ // Step 3: Build the prompt
308
+ const prompt = buildSchedulePrompt(schedule, workItem);
309
+
310
+ // Step 4: Build trigger metadata
311
+ const triggerMetadata: TriggerMetadata = {
312
+ triggerType: "interval",
313
+ schedule: scheduleName,
314
+ };
315
+
316
+ if (workItem) {
317
+ triggerMetadata.workItemId = workItem.id;
318
+ triggerMetadata.workItemTitle = workItem.title;
319
+ }
320
+
321
+ // Step 5: Execute the agent via JobExecutor
322
+ const executor = new JobExecutor(sdkQuery, executorOptions);
323
+
324
+ const runnerResult = await executor.execute({
325
+ agent,
326
+ prompt,
327
+ stateDir,
328
+ triggerType: "schedule",
329
+ schedule: scheduleName,
330
+ });
331
+
332
+ // Step 6: Report outcome to work source if we processed a work item
333
+ if (workItem && workSourceManager) {
334
+ const workResult = buildWorkResult(runnerResult);
335
+
336
+ try {
337
+ await workSourceManager.reportOutcome(workItem.id, workResult, {
338
+ agent,
339
+ });
340
+ logger.info(
341
+ `Reported outcome for work item ${workItem.id}: ${workResult.outcome}`
342
+ );
343
+ } catch (reportError) {
344
+ logger.error(
345
+ `Failed to report outcome for work item ${workItem.id}: ${(reportError as Error).message}`
346
+ );
347
+ // Don't fail the overall run if reporting fails
348
+ }
349
+ }
350
+
351
+ // Step 7: Calculate next trigger time
352
+ const nextTrigger = schedule.interval
353
+ ? calculateNextTrigger(new Date(), schedule.interval)
354
+ : null;
355
+
356
+ // Step 8: Update schedule state with success
357
+ await updateScheduleState(
358
+ stateDir,
359
+ agent.name,
360
+ scheduleName,
361
+ {
362
+ status: "idle",
363
+ next_run_at: nextTrigger?.toISOString() ?? null,
364
+ last_error: runnerResult.success ? null : runnerResult.error?.message,
365
+ },
366
+ { logger: stateLogger }
367
+ );
368
+
369
+ logger.info(
370
+ `Completed schedule ${agent.name}/${scheduleName}: ${runnerResult.success ? "success" : "failed"}`
371
+ );
372
+
373
+ return {
374
+ ...runnerResult,
375
+ workItem,
376
+ processedWorkItem,
377
+ };
378
+ } catch (error) {
379
+ const errorMessage =
380
+ error instanceof Error ? error.message : String(error);
381
+
382
+ logger.error(
383
+ `Error running schedule ${agent.name}/${scheduleName}: ${errorMessage}`
384
+ );
385
+
386
+ // Release work item if we claimed one and execution failed unexpectedly
387
+ if (workItem && workSourceManager) {
388
+ try {
389
+ await workSourceManager.releaseWorkItem(workItem.id, {
390
+ agent,
391
+ reason: `Unexpected error: ${errorMessage}`,
392
+ addComment: true,
393
+ });
394
+ logger.info(`Released work item ${workItem.id} due to error`);
395
+ } catch (releaseError) {
396
+ logger.error(
397
+ `Failed to release work item ${workItem.id}: ${(releaseError as Error).message}`
398
+ );
399
+ }
400
+ }
401
+
402
+ // Calculate next trigger time even on error
403
+ const nextTrigger = schedule.interval
404
+ ? calculateNextTrigger(new Date(), schedule.interval)
405
+ : null;
406
+
407
+ // Update schedule state with error
408
+ await updateScheduleState(
409
+ stateDir,
410
+ agent.name,
411
+ scheduleName,
412
+ {
413
+ status: "idle",
414
+ next_run_at: nextTrigger?.toISOString() ?? null,
415
+ last_error: errorMessage,
416
+ },
417
+ { logger: stateLogger }
418
+ );
419
+
420
+ // Re-throw to let caller handle
421
+ throw error;
422
+ }
423
+ }
424
+
425
+ // =============================================================================
426
+ // Helper Functions
427
+ // =============================================================================
428
+
429
+ /**
430
+ * Build a WorkResult from a RunnerResult for reporting to work sources
431
+ */
432
+ function buildWorkResult(runnerResult: RunnerResult): WorkResult {
433
+ const outcome: WorkOutcome = runnerResult.success ? "success" : "failure";
434
+
435
+ return {
436
+ outcome,
437
+ summary:
438
+ runnerResult.summary ?? (runnerResult.success ? "Task completed successfully" : "Task failed"),
439
+ error: runnerResult.error?.message,
440
+ artifacts: runnerResult.jobId ? [`job:${runnerResult.jobId}`] : undefined,
441
+ };
442
+ }
@@ -0,0 +1,211 @@
1
+ /**
2
+ * Schedule state management
3
+ *
4
+ * Provides functions for reading and updating schedule state within fleet state.
5
+ * Schedule state is stored per-agent in the `schedules` map within AgentState.
6
+ */
7
+
8
+ import { join } from "node:path";
9
+ import {
10
+ type ScheduleState,
11
+ type FleetState,
12
+ createDefaultScheduleState,
13
+ } from "../state/schemas/fleet-state.js";
14
+ import { readFleetState, writeFleetState } from "../state/fleet-state.js";
15
+ import { STATE_FILE_NAME } from "../state/types.js";
16
+
17
+ /**
18
+ * Logger interface for warning messages
19
+ */
20
+ export interface ScheduleStateLogger {
21
+ warn: (message: string) => void;
22
+ }
23
+
24
+ /**
25
+ * Default console logger
26
+ */
27
+ const defaultLogger: ScheduleStateLogger = {
28
+ warn: (message: string) => console.warn(`[herdctl] ${message}`),
29
+ };
30
+
31
+ /**
32
+ * Options for schedule state operations
33
+ */
34
+ export interface ScheduleStateOptions {
35
+ /**
36
+ * Logger for warning messages
37
+ * Default: console.warn
38
+ */
39
+ logger?: ScheduleStateLogger;
40
+ }
41
+
42
+ /**
43
+ * Partial updates for schedule state
44
+ */
45
+ export type ScheduleStateUpdates = Partial<ScheduleState>;
46
+
47
+ /**
48
+ * Get the state file path from a state directory
49
+ */
50
+ function getStateFilePath(stateDir: string): string {
51
+ return join(stateDir, STATE_FILE_NAME);
52
+ }
53
+
54
+ /**
55
+ * Get the schedule state for a specific agent and schedule
56
+ *
57
+ * Returns default state if the agent or schedule doesn't exist.
58
+ *
59
+ * @param stateDir - Path to the state directory (e.g., .herdctl)
60
+ * @param agentName - Name of the agent
61
+ * @param scheduleName - Name of the schedule
62
+ * @param options - Options including logger
63
+ * @returns The schedule state, or default state if not found
64
+ *
65
+ * @example
66
+ * ```typescript
67
+ * const state = await getScheduleState('.herdctl', 'my-agent', 'hourly');
68
+ * console.log(state.last_run_at);
69
+ * console.log(state.next_run_at);
70
+ * console.log(state.status);
71
+ * ```
72
+ */
73
+ export async function getScheduleState(
74
+ stateDir: string,
75
+ agentName: string,
76
+ scheduleName: string,
77
+ options: ScheduleStateOptions = {}
78
+ ): Promise<ScheduleState> {
79
+ const stateFilePath = getStateFilePath(stateDir);
80
+ const fleetState = await readFleetState(stateFilePath, options);
81
+
82
+ const agentState = fleetState.agents[agentName];
83
+ if (!agentState || !agentState.schedules) {
84
+ return createDefaultScheduleState();
85
+ }
86
+
87
+ const scheduleState = agentState.schedules[scheduleName];
88
+ if (!scheduleState) {
89
+ return createDefaultScheduleState();
90
+ }
91
+
92
+ return scheduleState;
93
+ }
94
+
95
+ /**
96
+ * Update the schedule state for a specific agent and schedule
97
+ *
98
+ * This function:
99
+ * 1. Reads current fleet state
100
+ * 2. Applies partial updates to the specified schedule
101
+ * 3. Writes the updated state back atomically
102
+ *
103
+ * If the agent or schedule doesn't exist, it will be created.
104
+ *
105
+ * @param stateDir - Path to the state directory (e.g., .herdctl)
106
+ * @param agentName - Name of the agent
107
+ * @param scheduleName - Name of the schedule
108
+ * @param updates - Partial ScheduleState updates to apply
109
+ * @param options - Options including logger
110
+ * @returns The updated ScheduleState
111
+ *
112
+ * @example
113
+ * ```typescript
114
+ * // Mark schedule as running
115
+ * await updateScheduleState('.herdctl', 'my-agent', 'hourly', {
116
+ * status: 'running',
117
+ * last_run_at: new Date().toISOString(),
118
+ * });
119
+ *
120
+ * // Record error
121
+ * await updateScheduleState('.herdctl', 'my-agent', 'hourly', {
122
+ * status: 'idle',
123
+ * last_error: 'Container exited with code 1',
124
+ * });
125
+ *
126
+ * // Clear error
127
+ * await updateScheduleState('.herdctl', 'my-agent', 'hourly', {
128
+ * last_error: null,
129
+ * });
130
+ * ```
131
+ */
132
+ export async function updateScheduleState(
133
+ stateDir: string,
134
+ agentName: string,
135
+ scheduleName: string,
136
+ updates: ScheduleStateUpdates,
137
+ options: ScheduleStateOptions = {}
138
+ ): Promise<ScheduleState> {
139
+ const stateFilePath = getStateFilePath(stateDir);
140
+ const fleetState = await readFleetState(stateFilePath, options);
141
+
142
+ // Get or create agent state
143
+ const currentAgentState = fleetState.agents[agentName] ?? { status: "idle" };
144
+
145
+ // Get current schedules map or create empty one
146
+ const currentSchedules = currentAgentState.schedules ?? {};
147
+
148
+ // Get current schedule state or create default
149
+ const currentScheduleState =
150
+ currentSchedules[scheduleName] ?? createDefaultScheduleState();
151
+
152
+ // Merge updates
153
+ const updatedScheduleState: ScheduleState = {
154
+ ...currentScheduleState,
155
+ ...updates,
156
+ };
157
+
158
+ // Update the fleet state
159
+ const updatedFleetState: FleetState = {
160
+ ...fleetState,
161
+ agents: {
162
+ ...fleetState.agents,
163
+ [agentName]: {
164
+ ...currentAgentState,
165
+ schedules: {
166
+ ...currentSchedules,
167
+ [scheduleName]: updatedScheduleState,
168
+ },
169
+ },
170
+ },
171
+ };
172
+
173
+ // Write back
174
+ await writeFleetState(stateFilePath, updatedFleetState);
175
+
176
+ return updatedScheduleState;
177
+ }
178
+
179
+ /**
180
+ * Get all schedule states for a specific agent
181
+ *
182
+ * Returns an empty object if the agent doesn't exist or has no schedules.
183
+ *
184
+ * @param stateDir - Path to the state directory (e.g., .herdctl)
185
+ * @param agentName - Name of the agent
186
+ * @param options - Options including logger
187
+ * @returns Map of schedule names to their state
188
+ *
189
+ * @example
190
+ * ```typescript
191
+ * const schedules = await getAgentScheduleStates('.herdctl', 'my-agent');
192
+ * for (const [name, state] of Object.entries(schedules)) {
193
+ * console.log(`${name}: ${state.status}, last run: ${state.last_run_at}`);
194
+ * }
195
+ * ```
196
+ */
197
+ export async function getAgentScheduleStates(
198
+ stateDir: string,
199
+ agentName: string,
200
+ options: ScheduleStateOptions = {}
201
+ ): Promise<Record<string, ScheduleState>> {
202
+ const stateFilePath = getStateFilePath(stateDir);
203
+ const fleetState = await readFleetState(stateFilePath, options);
204
+
205
+ const agentState = fleetState.agents[agentName];
206
+ if (!agentState || !agentState.schedules) {
207
+ return {};
208
+ }
209
+
210
+ return agentState.schedules;
211
+ }