@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,667 @@
1
+ import { describe, it, expect, beforeEach, afterEach } from "vitest";
2
+ import { mkdir, rm, realpath, writeFile, readFile } from "node:fs/promises";
3
+ import { join } from "node:path";
4
+ import { tmpdir } from "node:os";
5
+ import { createJob, updateJob, getJob, listJobs, deleteJob, } from "../job-metadata.js";
6
+ import { StateFileError } from "../errors.js";
7
+ // Helper to create a temp directory
8
+ async function createTempDir() {
9
+ const baseDir = join(tmpdir(), `herdctl-job-test-${Date.now()}-${Math.random().toString(36).slice(2)}`);
10
+ await mkdir(baseDir, { recursive: true });
11
+ // Resolve to real path to handle macOS /var -> /private/var symlink
12
+ return await realpath(baseDir);
13
+ }
14
+ // Helper to create a mock logger
15
+ function createMockLogger() {
16
+ const warnings = [];
17
+ return {
18
+ warnings,
19
+ warn: (message) => warnings.push(message),
20
+ };
21
+ }
22
+ // Helper to create a valid job YAML file
23
+ async function writeJobFile(dir, job) {
24
+ const { stringify } = await import("yaml");
25
+ const filePath = join(dir, `${job.id}.yaml`);
26
+ await writeFile(filePath, stringify(job), "utf-8");
27
+ return filePath;
28
+ }
29
+ describe("createJob", () => {
30
+ let tempDir;
31
+ beforeEach(async () => {
32
+ tempDir = await createTempDir();
33
+ });
34
+ afterEach(async () => {
35
+ await rm(tempDir, { recursive: true, force: true });
36
+ });
37
+ it("creates a job file with correct content", async () => {
38
+ const job = await createJob(tempDir, {
39
+ agent: "test-agent",
40
+ trigger_type: "manual",
41
+ prompt: "Test prompt",
42
+ });
43
+ expect(job.id).toMatch(/^job-\d{4}-\d{2}-\d{2}-[a-z0-9]{6}$/);
44
+ expect(job.agent).toBe("test-agent");
45
+ expect(job.trigger_type).toBe("manual");
46
+ expect(job.status).toBe("pending");
47
+ expect(job.prompt).toBe("Test prompt");
48
+ // Verify file exists
49
+ const filePath = join(tempDir, `${job.id}.yaml`);
50
+ const content = await readFile(filePath, "utf-8");
51
+ expect(content).toContain("agent: test-agent");
52
+ expect(content).toContain("trigger_type: manual");
53
+ });
54
+ it("creates scheduled job with schedule name", async () => {
55
+ const job = await createJob(tempDir, {
56
+ agent: "cron-agent",
57
+ trigger_type: "schedule",
58
+ schedule: "hourly",
59
+ });
60
+ expect(job.schedule).toBe("hourly");
61
+ expect(job.trigger_type).toBe("schedule");
62
+ });
63
+ it("creates forked job with parent reference", async () => {
64
+ // Create parent job first
65
+ const parentJob = await createJob(tempDir, {
66
+ agent: "test-agent",
67
+ trigger_type: "manual",
68
+ });
69
+ const forkedJob = await createJob(tempDir, {
70
+ agent: "test-agent",
71
+ trigger_type: "fork",
72
+ forked_from: parentJob.id,
73
+ });
74
+ expect(forkedJob.trigger_type).toBe("fork");
75
+ expect(forkedJob.forked_from).toBe(parentJob.id);
76
+ });
77
+ it("sets started_at to current time", async () => {
78
+ const before = new Date();
79
+ const job = await createJob(tempDir, {
80
+ agent: "test-agent",
81
+ trigger_type: "manual",
82
+ });
83
+ const after = new Date();
84
+ const startedAt = new Date(job.started_at);
85
+ expect(startedAt.getTime()).toBeGreaterThanOrEqual(before.getTime() - 1000);
86
+ expect(startedAt.getTime()).toBeLessThanOrEqual(after.getTime() + 1000);
87
+ });
88
+ it("throws StateFileError when directory does not exist", async () => {
89
+ const nonExistentDir = join(tempDir, "does-not-exist");
90
+ await expect(createJob(nonExistentDir, {
91
+ agent: "test-agent",
92
+ trigger_type: "manual",
93
+ })).rejects.toThrow(StateFileError);
94
+ });
95
+ it("generates unique job IDs", async () => {
96
+ const jobs = await Promise.all([
97
+ createJob(tempDir, { agent: "agent-1", trigger_type: "manual" }),
98
+ createJob(tempDir, { agent: "agent-2", trigger_type: "manual" }),
99
+ createJob(tempDir, { agent: "agent-3", trigger_type: "manual" }),
100
+ ]);
101
+ const ids = jobs.map((j) => j.id);
102
+ const uniqueIds = new Set(ids);
103
+ expect(uniqueIds.size).toBe(3);
104
+ });
105
+ });
106
+ describe("updateJob", () => {
107
+ let tempDir;
108
+ beforeEach(async () => {
109
+ tempDir = await createTempDir();
110
+ });
111
+ afterEach(async () => {
112
+ await rm(tempDir, { recursive: true, force: true });
113
+ });
114
+ it("updates job status", async () => {
115
+ const job = await createJob(tempDir, {
116
+ agent: "test-agent",
117
+ trigger_type: "manual",
118
+ });
119
+ const updated = await updateJob(tempDir, job.id, {
120
+ status: "running",
121
+ session_id: "session-123",
122
+ });
123
+ expect(updated.status).toBe("running");
124
+ expect(updated.session_id).toBe("session-123");
125
+ expect(updated.agent).toBe("test-agent"); // Preserved
126
+ });
127
+ it("auto-calculates duration when finished_at is set", async () => {
128
+ const job = await createJob(tempDir, {
129
+ agent: "test-agent",
130
+ trigger_type: "manual",
131
+ });
132
+ // Wait a bit to have a measurable duration
133
+ const startTime = new Date(job.started_at);
134
+ const finishTime = new Date(startTime.getTime() + 5000); // 5 seconds later
135
+ const updated = await updateJob(tempDir, job.id, {
136
+ status: "completed",
137
+ exit_reason: "success",
138
+ finished_at: finishTime.toISOString(),
139
+ });
140
+ expect(updated.duration_seconds).toBe(5);
141
+ });
142
+ it("preserves explicit duration_seconds over auto-calculation", async () => {
143
+ const job = await createJob(tempDir, {
144
+ agent: "test-agent",
145
+ trigger_type: "manual",
146
+ });
147
+ const updated = await updateJob(tempDir, job.id, {
148
+ status: "completed",
149
+ finished_at: new Date().toISOString(),
150
+ duration_seconds: 999, // Explicit value
151
+ });
152
+ expect(updated.duration_seconds).toBe(999);
153
+ });
154
+ it("updates summary and output_file", async () => {
155
+ const job = await createJob(tempDir, {
156
+ agent: "test-agent",
157
+ trigger_type: "manual",
158
+ });
159
+ const updated = await updateJob(tempDir, job.id, {
160
+ summary: "All tests passed",
161
+ output_file: "/path/to/output.log",
162
+ });
163
+ expect(updated.summary).toBe("All tests passed");
164
+ expect(updated.output_file).toBe("/path/to/output.log");
165
+ });
166
+ it("throws StateFileError for non-existent job", async () => {
167
+ await expect(updateJob(tempDir, "job-2024-01-15-noexis", { status: "running" })).rejects.toThrow(StateFileError);
168
+ });
169
+ it("throws StateFileError for corrupted job file", async () => {
170
+ const corruptedPath = join(tempDir, "job-2024-01-15-corupt.yaml");
171
+ await writeFile(corruptedPath, "invalid: [yaml", "utf-8");
172
+ await expect(updateJob(tempDir, "job-2024-01-15-corupt", { status: "running" })).rejects.toThrow(StateFileError);
173
+ });
174
+ it("persists updates to file", async () => {
175
+ const job = await createJob(tempDir, {
176
+ agent: "test-agent",
177
+ trigger_type: "manual",
178
+ });
179
+ await updateJob(tempDir, job.id, {
180
+ status: "completed",
181
+ summary: "Done!",
182
+ });
183
+ // Read file directly
184
+ const content = await readFile(join(tempDir, `${job.id}.yaml`), "utf-8");
185
+ expect(content).toContain("status: completed");
186
+ expect(content).toContain("summary: Done!");
187
+ });
188
+ it("handles multiple sequential updates", async () => {
189
+ const job = await createJob(tempDir, {
190
+ agent: "test-agent",
191
+ trigger_type: "manual",
192
+ });
193
+ await updateJob(tempDir, job.id, { status: "running" });
194
+ await updateJob(tempDir, job.id, { session_id: "sess-1" });
195
+ const final = await updateJob(tempDir, job.id, {
196
+ status: "completed",
197
+ exit_reason: "success",
198
+ });
199
+ expect(final.status).toBe("completed");
200
+ expect(final.session_id).toBe("sess-1");
201
+ expect(final.exit_reason).toBe("success");
202
+ });
203
+ });
204
+ describe("getJob", () => {
205
+ let tempDir;
206
+ beforeEach(async () => {
207
+ tempDir = await createTempDir();
208
+ });
209
+ afterEach(async () => {
210
+ await rm(tempDir, { recursive: true, force: true });
211
+ });
212
+ it("returns job when it exists", async () => {
213
+ const created = await createJob(tempDir, {
214
+ agent: "test-agent",
215
+ trigger_type: "manual",
216
+ prompt: "Test prompt",
217
+ });
218
+ const retrieved = await getJob(tempDir, created.id);
219
+ expect(retrieved).not.toBeNull();
220
+ expect(retrieved.id).toBe(created.id);
221
+ expect(retrieved.agent).toBe("test-agent");
222
+ expect(retrieved.prompt).toBe("Test prompt");
223
+ });
224
+ it("returns null for non-existent job", async () => {
225
+ const result = await getJob(tempDir, "job-2024-01-15-noexis");
226
+ expect(result).toBeNull();
227
+ });
228
+ it("returns null and logs warning for corrupted job file", async () => {
229
+ const logger = createMockLogger();
230
+ const corruptedPath = join(tempDir, "job-2024-01-15-corpt1.yaml");
231
+ // Use actually parseable YAML but with invalid schema
232
+ await writeFile(corruptedPath, "agent: ''\nstatus: invalid\n", "utf-8");
233
+ const result = await getJob(tempDir, "job-2024-01-15-corpt1", { logger });
234
+ expect(result).toBeNull();
235
+ expect(logger.warnings.length).toBeGreaterThan(0);
236
+ });
237
+ it("returns null for job with invalid schema", async () => {
238
+ const logger = createMockLogger();
239
+ const invalidJob = {
240
+ id: "job-2024-01-15-invali",
241
+ agent: "", // Invalid: empty
242
+ trigger_type: "manual",
243
+ status: "running",
244
+ started_at: "2024-01-15T10:00:00Z",
245
+ };
246
+ await writeJobFile(tempDir, invalidJob);
247
+ const result = await getJob(tempDir, "job-2024-01-15-invali", { logger });
248
+ expect(result).toBeNull();
249
+ expect(logger.warnings.length).toBeGreaterThan(0);
250
+ });
251
+ it("throws for permission errors", async () => {
252
+ // This is hard to test portably - skip or use mock
253
+ });
254
+ });
255
+ describe("listJobs", () => {
256
+ let tempDir;
257
+ beforeEach(async () => {
258
+ tempDir = await createTempDir();
259
+ });
260
+ afterEach(async () => {
261
+ await rm(tempDir, { recursive: true, force: true });
262
+ });
263
+ it("returns empty list when directory is empty", async () => {
264
+ const result = await listJobs(tempDir);
265
+ expect(result.jobs).toEqual([]);
266
+ expect(result.errors).toBe(0);
267
+ });
268
+ it("returns empty list when directory does not exist", async () => {
269
+ const nonExistent = join(tempDir, "does-not-exist");
270
+ const result = await listJobs(nonExistent);
271
+ expect(result.jobs).toEqual([]);
272
+ expect(result.errors).toBe(0);
273
+ });
274
+ it("lists all jobs in directory", async () => {
275
+ await createJob(tempDir, { agent: "agent-1", trigger_type: "manual" });
276
+ await createJob(tempDir, { agent: "agent-2", trigger_type: "schedule" });
277
+ await createJob(tempDir, { agent: "agent-3", trigger_type: "webhook" });
278
+ const result = await listJobs(tempDir);
279
+ expect(result.jobs).toHaveLength(3);
280
+ expect(result.errors).toBe(0);
281
+ });
282
+ it("sorts jobs by started_at descending (most recent first)", async () => {
283
+ // Create jobs with known timestamps
284
+ const job1 = {
285
+ id: "job-2024-01-15-first1",
286
+ agent: "agent",
287
+ trigger_type: "manual",
288
+ status: "completed",
289
+ started_at: "2024-01-15T10:00:00Z",
290
+ schedule: null,
291
+ exit_reason: null,
292
+ session_id: null,
293
+ forked_from: null,
294
+ finished_at: null,
295
+ duration_seconds: null,
296
+ prompt: null,
297
+ summary: null,
298
+ output_file: null,
299
+ };
300
+ const job2 = {
301
+ ...job1,
302
+ id: "job-2024-01-15-middl2",
303
+ started_at: "2024-01-15T12:00:00Z",
304
+ };
305
+ const job3 = {
306
+ ...job1,
307
+ id: "job-2024-01-15-last03",
308
+ started_at: "2024-01-15T14:00:00Z",
309
+ };
310
+ await writeJobFile(tempDir, job1);
311
+ await writeJobFile(tempDir, job2);
312
+ await writeJobFile(tempDir, job3);
313
+ const result = await listJobs(tempDir);
314
+ expect(result.jobs[0].id).toBe("job-2024-01-15-last03"); // Most recent
315
+ expect(result.jobs[1].id).toBe("job-2024-01-15-middl2");
316
+ expect(result.jobs[2].id).toBe("job-2024-01-15-first1"); // Oldest
317
+ });
318
+ describe("filtering by agent", () => {
319
+ it("returns only jobs for specified agent", async () => {
320
+ await createJob(tempDir, { agent: "agent-a", trigger_type: "manual" });
321
+ await createJob(tempDir, { agent: "agent-b", trigger_type: "manual" });
322
+ await createJob(tempDir, { agent: "agent-a", trigger_type: "schedule" });
323
+ const result = await listJobs(tempDir, { agent: "agent-a" });
324
+ expect(result.jobs).toHaveLength(2);
325
+ expect(result.jobs.every((j) => j.agent === "agent-a")).toBe(true);
326
+ });
327
+ });
328
+ describe("filtering by status", () => {
329
+ it("returns only jobs with specified status", async () => {
330
+ const job1 = await createJob(tempDir, {
331
+ agent: "agent",
332
+ trigger_type: "manual",
333
+ });
334
+ const job2 = await createJob(tempDir, {
335
+ agent: "agent",
336
+ trigger_type: "manual",
337
+ });
338
+ await createJob(tempDir, { agent: "agent", trigger_type: "manual" });
339
+ await updateJob(tempDir, job1.id, { status: "completed" });
340
+ await updateJob(tempDir, job2.id, { status: "failed" });
341
+ const completedJobs = await listJobs(tempDir, { status: "completed" });
342
+ expect(completedJobs.jobs).toHaveLength(1);
343
+ expect(completedJobs.jobs[0].id).toBe(job1.id);
344
+ const failedJobs = await listJobs(tempDir, { status: "failed" });
345
+ expect(failedJobs.jobs).toHaveLength(1);
346
+ expect(failedJobs.jobs[0].id).toBe(job2.id);
347
+ const pendingJobs = await listJobs(tempDir, { status: "pending" });
348
+ expect(pendingJobs.jobs).toHaveLength(1);
349
+ });
350
+ });
351
+ describe("filtering by date range", () => {
352
+ it("filters jobs started after a date", async () => {
353
+ const oldJob = {
354
+ id: "job-2024-01-10-old001",
355
+ agent: "agent",
356
+ trigger_type: "manual",
357
+ status: "completed",
358
+ started_at: "2024-01-10T10:00:00Z",
359
+ schedule: null,
360
+ exit_reason: null,
361
+ session_id: null,
362
+ forked_from: null,
363
+ finished_at: null,
364
+ duration_seconds: null,
365
+ prompt: null,
366
+ summary: null,
367
+ output_file: null,
368
+ };
369
+ const newJob = {
370
+ ...oldJob,
371
+ id: "job-2024-01-20-new001",
372
+ started_at: "2024-01-20T10:00:00Z",
373
+ };
374
+ await writeJobFile(tempDir, oldJob);
375
+ await writeJobFile(tempDir, newJob);
376
+ const result = await listJobs(tempDir, {
377
+ startedAfter: "2024-01-15T00:00:00Z",
378
+ });
379
+ expect(result.jobs).toHaveLength(1);
380
+ expect(result.jobs[0].id).toBe("job-2024-01-20-new001");
381
+ });
382
+ it("filters jobs started before a date", async () => {
383
+ const oldJob = {
384
+ id: "job-2024-01-10-old002",
385
+ agent: "agent",
386
+ trigger_type: "manual",
387
+ status: "completed",
388
+ started_at: "2024-01-10T10:00:00Z",
389
+ schedule: null,
390
+ exit_reason: null,
391
+ session_id: null,
392
+ forked_from: null,
393
+ finished_at: null,
394
+ duration_seconds: null,
395
+ prompt: null,
396
+ summary: null,
397
+ output_file: null,
398
+ };
399
+ const newJob = {
400
+ ...oldJob,
401
+ id: "job-2024-01-20-new002",
402
+ started_at: "2024-01-20T10:00:00Z",
403
+ };
404
+ await writeJobFile(tempDir, oldJob);
405
+ await writeJobFile(tempDir, newJob);
406
+ const result = await listJobs(tempDir, {
407
+ startedBefore: "2024-01-15T00:00:00Z",
408
+ });
409
+ expect(result.jobs).toHaveLength(1);
410
+ expect(result.jobs[0].id).toBe("job-2024-01-10-old002");
411
+ });
412
+ it("filters jobs within a date range", async () => {
413
+ const veryOldJob = {
414
+ id: "job-2024-01-01-very01",
415
+ agent: "agent",
416
+ trigger_type: "manual",
417
+ status: "completed",
418
+ started_at: "2024-01-01T10:00:00Z",
419
+ schedule: null,
420
+ exit_reason: null,
421
+ session_id: null,
422
+ forked_from: null,
423
+ finished_at: null,
424
+ duration_seconds: null,
425
+ prompt: null,
426
+ summary: null,
427
+ output_file: null,
428
+ };
429
+ const middleJob = {
430
+ ...veryOldJob,
431
+ id: "job-2024-01-15-midd01",
432
+ started_at: "2024-01-15T10:00:00Z",
433
+ };
434
+ const veryNewJob = {
435
+ ...veryOldJob,
436
+ id: "job-2024-01-30-vnew01",
437
+ started_at: "2024-01-30T10:00:00Z",
438
+ };
439
+ await writeJobFile(tempDir, veryOldJob);
440
+ await writeJobFile(tempDir, middleJob);
441
+ await writeJobFile(tempDir, veryNewJob);
442
+ const result = await listJobs(tempDir, {
443
+ startedAfter: "2024-01-10T00:00:00Z",
444
+ startedBefore: "2024-01-20T00:00:00Z",
445
+ });
446
+ expect(result.jobs).toHaveLength(1);
447
+ expect(result.jobs[0].id).toBe("job-2024-01-15-midd01");
448
+ });
449
+ it("accepts Date objects for date filters", async () => {
450
+ const job = {
451
+ id: "job-2024-01-15-date01",
452
+ agent: "agent",
453
+ trigger_type: "manual",
454
+ status: "completed",
455
+ started_at: "2024-01-15T10:00:00Z",
456
+ schedule: null,
457
+ exit_reason: null,
458
+ session_id: null,
459
+ forked_from: null,
460
+ finished_at: null,
461
+ duration_seconds: null,
462
+ prompt: null,
463
+ summary: null,
464
+ output_file: null,
465
+ };
466
+ await writeJobFile(tempDir, job);
467
+ const result = await listJobs(tempDir, {
468
+ startedAfter: new Date("2024-01-10T00:00:00Z"),
469
+ startedBefore: new Date("2024-01-20T00:00:00Z"),
470
+ });
471
+ expect(result.jobs).toHaveLength(1);
472
+ });
473
+ });
474
+ describe("combining filters", () => {
475
+ it("applies multiple filters together", async () => {
476
+ const job1 = {
477
+ id: "job-2024-01-15-comb01",
478
+ agent: "agent-a",
479
+ trigger_type: "manual",
480
+ status: "completed",
481
+ started_at: "2024-01-15T10:00:00Z",
482
+ schedule: null,
483
+ exit_reason: null,
484
+ session_id: null,
485
+ forked_from: null,
486
+ finished_at: null,
487
+ duration_seconds: null,
488
+ prompt: null,
489
+ summary: null,
490
+ output_file: null,
491
+ };
492
+ const job2 = {
493
+ ...job1,
494
+ id: "job-2024-01-15-comb02",
495
+ agent: "agent-b",
496
+ status: "completed",
497
+ };
498
+ const job3 = {
499
+ ...job1,
500
+ id: "job-2024-01-15-comb03",
501
+ agent: "agent-a",
502
+ status: "failed",
503
+ };
504
+ const job4 = {
505
+ ...job1,
506
+ id: "job-2024-01-10-comb04",
507
+ started_at: "2024-01-10T10:00:00Z",
508
+ status: "completed",
509
+ };
510
+ await writeJobFile(tempDir, job1);
511
+ await writeJobFile(tempDir, job2);
512
+ await writeJobFile(tempDir, job3);
513
+ await writeJobFile(tempDir, job4);
514
+ const result = await listJobs(tempDir, {
515
+ agent: "agent-a",
516
+ status: "completed",
517
+ startedAfter: "2024-01-14T00:00:00Z",
518
+ });
519
+ expect(result.jobs).toHaveLength(1);
520
+ expect(result.jobs[0].id).toBe("job-2024-01-15-comb01");
521
+ });
522
+ });
523
+ describe("error handling", () => {
524
+ it("counts and reports parse errors", async () => {
525
+ const logger = createMockLogger();
526
+ await createJob(tempDir, { agent: "agent", trigger_type: "manual" });
527
+ // Create corrupted job file
528
+ await writeFile(join(tempDir, "job-2024-01-15-corupt.yaml"), "invalid: [yaml", "utf-8");
529
+ const result = await listJobs(tempDir, {}, { logger });
530
+ expect(result.jobs).toHaveLength(1);
531
+ expect(result.errors).toBe(1);
532
+ expect(logger.warnings.length).toBeGreaterThan(0);
533
+ });
534
+ it("ignores non-job files", async () => {
535
+ await createJob(tempDir, { agent: "agent", trigger_type: "manual" });
536
+ // Create non-job files
537
+ await writeFile(join(tempDir, "other.yaml"), "foo: bar", "utf-8");
538
+ await writeFile(join(tempDir, "job-.txt"), "not yaml", "utf-8");
539
+ const result = await listJobs(tempDir);
540
+ expect(result.jobs).toHaveLength(1);
541
+ expect(result.errors).toBe(0);
542
+ });
543
+ });
544
+ });
545
+ describe("deleteJob", () => {
546
+ let tempDir;
547
+ beforeEach(async () => {
548
+ tempDir = await createTempDir();
549
+ });
550
+ afterEach(async () => {
551
+ await rm(tempDir, { recursive: true, force: true });
552
+ });
553
+ it("deletes existing job and returns true", async () => {
554
+ const job = await createJob(tempDir, {
555
+ agent: "test-agent",
556
+ trigger_type: "manual",
557
+ });
558
+ const deleted = await deleteJob(tempDir, job.id);
559
+ expect(deleted).toBe(true);
560
+ // Verify file is gone
561
+ const retrieved = await getJob(tempDir, job.id);
562
+ expect(retrieved).toBeNull();
563
+ });
564
+ it("returns false for non-existent job", async () => {
565
+ const deleted = await deleteJob(tempDir, "job-2024-01-15-noexis");
566
+ expect(deleted).toBe(false);
567
+ });
568
+ it("does not affect other jobs", async () => {
569
+ const job1 = await createJob(tempDir, {
570
+ agent: "agent-1",
571
+ trigger_type: "manual",
572
+ });
573
+ const job2 = await createJob(tempDir, {
574
+ agent: "agent-2",
575
+ trigger_type: "manual",
576
+ });
577
+ await deleteJob(tempDir, job1.id);
578
+ const remaining = await listJobs(tempDir);
579
+ expect(remaining.jobs).toHaveLength(1);
580
+ expect(remaining.jobs[0].id).toBe(job2.id);
581
+ });
582
+ });
583
+ describe("atomic write behavior", () => {
584
+ let tempDir;
585
+ beforeEach(async () => {
586
+ tempDir = await createTempDir();
587
+ });
588
+ afterEach(async () => {
589
+ await rm(tempDir, { recursive: true, force: true });
590
+ });
591
+ it("does not leave temp files on successful write", async () => {
592
+ await createJob(tempDir, {
593
+ agent: "test-agent",
594
+ trigger_type: "manual",
595
+ });
596
+ const { readdir } = await import("node:fs/promises");
597
+ const files = await readdir(tempDir);
598
+ const tempFiles = files.filter((f) => f.includes(".tmp."));
599
+ expect(tempFiles).toHaveLength(0);
600
+ });
601
+ it("preserves original file on update validation failure", async () => {
602
+ const job = await createJob(tempDir, {
603
+ agent: "test-agent",
604
+ trigger_type: "manual",
605
+ });
606
+ // Try to update with invalid data (would fail validation if we didn't catch it)
607
+ // The current implementation validates before write, so invalid updates fail early
608
+ const retrieved = await getJob(tempDir, job.id);
609
+ expect(retrieved).not.toBeNull();
610
+ expect(retrieved.agent).toBe("test-agent");
611
+ });
612
+ });
613
+ describe("concurrent operations", () => {
614
+ let tempDir;
615
+ beforeEach(async () => {
616
+ tempDir = await createTempDir();
617
+ });
618
+ afterEach(async () => {
619
+ await rm(tempDir, { recursive: true, force: true });
620
+ });
621
+ it("handles multiple concurrent creates", async () => {
622
+ const creates = [];
623
+ for (let i = 0; i < 20; i++) {
624
+ creates.push(createJob(tempDir, {
625
+ agent: `agent-${i}`,
626
+ trigger_type: "manual",
627
+ }));
628
+ }
629
+ const jobs = await Promise.all(creates);
630
+ // All jobs should have unique IDs
631
+ const ids = new Set(jobs.map((j) => j.id));
632
+ expect(ids.size).toBe(20);
633
+ // All jobs should be retrievable
634
+ const result = await listJobs(tempDir);
635
+ expect(result.jobs).toHaveLength(20);
636
+ });
637
+ it("handles multiple concurrent reads", async () => {
638
+ const job = await createJob(tempDir, {
639
+ agent: "test-agent",
640
+ trigger_type: "manual",
641
+ });
642
+ const reads = [];
643
+ for (let i = 0; i < 50; i++) {
644
+ reads.push(getJob(tempDir, job.id));
645
+ }
646
+ const results = await Promise.all(reads);
647
+ for (const result of results) {
648
+ expect(result).not.toBeNull();
649
+ expect(result.id).toBe(job.id);
650
+ }
651
+ });
652
+ it("handles sequential updates correctly", async () => {
653
+ const job = await createJob(tempDir, {
654
+ agent: "test-agent",
655
+ trigger_type: "manual",
656
+ });
657
+ // Sequential updates (not concurrent to avoid race conditions)
658
+ for (let i = 0; i < 10; i++) {
659
+ await updateJob(tempDir, job.id, {
660
+ summary: `Update ${i}`,
661
+ });
662
+ }
663
+ const final = await getJob(tempDir, job.id);
664
+ expect(final.summary).toBe("Update 9");
665
+ });
666
+ });
667
+ //# sourceMappingURL=job-metadata.test.js.map