@namzu/cli 29.0.1 → 29.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (384) hide show
  1. package/CHANGELOG.md +115 -0
  2. package/README.md +20 -0
  3. package/dist/browser/commands.d.ts +29 -0
  4. package/dist/browser/commands.d.ts.map +1 -0
  5. package/dist/browser/commands.js +361 -0
  6. package/dist/browser/commands.js.map +1 -0
  7. package/dist/browser/control.d.ts +79 -0
  8. package/dist/browser/control.d.ts.map +1 -0
  9. package/dist/browser/control.js +140 -0
  10. package/dist/browser/control.js.map +1 -0
  11. package/dist/browser/describe.d.ts +12 -0
  12. package/dist/browser/describe.d.ts.map +1 -0
  13. package/dist/browser/describe.js +27 -0
  14. package/dist/browser/describe.js.map +1 -0
  15. package/dist/cli.d.ts.map +1 -1
  16. package/dist/cli.js +29 -2
  17. package/dist/cli.js.map +1 -1
  18. package/dist/commands/acp.d.ts.map +1 -1
  19. package/dist/commands/acp.js +1 -0
  20. package/dist/commands/acp.js.map +1 -1
  21. package/dist/commands/browser.d.ts +7 -0
  22. package/dist/commands/browser.d.ts.map +1 -0
  23. package/dist/commands/browser.js +16 -0
  24. package/dist/commands/browser.js.map +1 -0
  25. package/dist/commands/drain.d.ts +2 -1
  26. package/dist/commands/drain.d.ts.map +1 -1
  27. package/dist/commands/drain.js +6 -3
  28. package/dist/commands/drain.js.map +1 -1
  29. package/dist/commands/exec-flags.d.ts +2 -1
  30. package/dist/commands/exec-flags.d.ts.map +1 -1
  31. package/dist/commands/exec-flags.js +6 -3
  32. package/dist/commands/exec-flags.js.map +1 -1
  33. package/dist/commands/exec-json.d.ts.map +1 -1
  34. package/dist/commands/exec-json.js +2 -1
  35. package/dist/commands/exec-json.js.map +1 -1
  36. package/dist/commands/exec.d.ts.map +1 -1
  37. package/dist/commands/exec.js +2 -1
  38. package/dist/commands/exec.js.map +1 -1
  39. package/dist/commands/host-queries.d.ts.map +1 -1
  40. package/dist/commands/host-queries.js +10 -3
  41. package/dist/commands/host-queries.js.map +1 -1
  42. package/dist/commands/schedule.d.ts +9 -0
  43. package/dist/commands/schedule.d.ts.map +1 -0
  44. package/dist/commands/schedule.js +126 -0
  45. package/dist/commands/schedule.js.map +1 -0
  46. package/dist/commands/serve.d.ts +3 -1
  47. package/dist/commands/serve.d.ts.map +1 -1
  48. package/dist/commands/serve.js +5 -3
  49. package/dist/commands/serve.js.map +1 -1
  50. package/dist/commands/skills.d.ts +10 -0
  51. package/dist/commands/skills.d.ts.map +1 -1
  52. package/dist/commands/skills.js +23 -7
  53. package/dist/commands/skills.js.map +1 -1
  54. package/dist/commands/upgrade.d.ts +5 -0
  55. package/dist/commands/upgrade.d.ts.map +1 -1
  56. package/dist/commands/upgrade.js +11 -0
  57. package/dist/commands/upgrade.js.map +1 -1
  58. package/dist/config/load.d.ts +39 -0
  59. package/dist/config/load.d.ts.map +1 -1
  60. package/dist/config/load.js +232 -1
  61. package/dist/config/load.js.map +1 -1
  62. package/dist/config/schema.d.ts +78 -0
  63. package/dist/config/schema.d.ts.map +1 -1
  64. package/dist/config/schema.js.map +1 -1
  65. package/dist/config/user-config.d.ts +23 -0
  66. package/dist/config/user-config.d.ts.map +1 -0
  67. package/dist/config/user-config.js +48 -0
  68. package/dist/config/user-config.js.map +1 -0
  69. package/dist/context/capabilities.d.ts +1 -1
  70. package/dist/context/capabilities.d.ts.map +1 -1
  71. package/dist/context/capabilities.js +1 -0
  72. package/dist/context/capabilities.js.map +1 -1
  73. package/dist/doctor/checks/browser.d.ts +15 -0
  74. package/dist/doctor/checks/browser.d.ts.map +1 -0
  75. package/dist/doctor/checks/browser.js +63 -0
  76. package/dist/doctor/checks/browser.js.map +1 -0
  77. package/dist/doctor/checks/index.d.ts +4 -1
  78. package/dist/doctor/checks/index.d.ts.map +1 -1
  79. package/dist/doctor/checks/index.js +8 -1
  80. package/dist/doctor/checks/index.js.map +1 -1
  81. package/dist/doctor/checks/scheduler.d.ts +10 -0
  82. package/dist/doctor/checks/scheduler.d.ts.map +1 -0
  83. package/dist/doctor/checks/scheduler.js +74 -0
  84. package/dist/doctor/checks/scheduler.js.map +1 -0
  85. package/dist/index.d.ts +1 -1
  86. package/dist/index.d.ts.map +1 -1
  87. package/dist/index.js +1 -1
  88. package/dist/index.js.map +1 -1
  89. package/dist/integrations/notifications/desktop/freedesktop.d.ts +10 -0
  90. package/dist/integrations/notifications/desktop/freedesktop.d.ts.map +1 -0
  91. package/dist/integrations/notifications/desktop/freedesktop.js +33 -0
  92. package/dist/integrations/notifications/desktop/freedesktop.js.map +1 -0
  93. package/dist/integrations/notifications/desktop/macos.d.ts +6 -0
  94. package/dist/integrations/notifications/desktop/macos.d.ts.map +1 -0
  95. package/dist/integrations/notifications/desktop/macos.js +17 -0
  96. package/dist/integrations/notifications/desktop/macos.js.map +1 -0
  97. package/dist/integrations/notifications/desktop/sanitize.d.ts +16 -0
  98. package/dist/integrations/notifications/desktop/sanitize.d.ts.map +1 -0
  99. package/dist/integrations/notifications/desktop/sanitize.js +49 -0
  100. package/dist/integrations/notifications/desktop/sanitize.js.map +1 -0
  101. package/dist/integrations/notifications/desktop/throttle.d.ts +10 -0
  102. package/dist/integrations/notifications/desktop/throttle.d.ts.map +1 -0
  103. package/dist/integrations/notifications/desktop/throttle.js +39 -0
  104. package/dist/integrations/notifications/desktop/throttle.js.map +1 -0
  105. package/dist/integrations/notifications/desktop/windows-toast.d.ts +23 -0
  106. package/dist/integrations/notifications/desktop/windows-toast.d.ts.map +1 -0
  107. package/dist/integrations/notifications/desktop/windows-toast.js +56 -0
  108. package/dist/integrations/notifications/desktop/windows-toast.js.map +1 -0
  109. package/dist/integrations/notifications/desktop.d.ts +82 -0
  110. package/dist/integrations/notifications/desktop.d.ts.map +1 -0
  111. package/dist/integrations/notifications/desktop.js +198 -0
  112. package/dist/integrations/notifications/desktop.js.map +1 -0
  113. package/dist/integrations/resident/session-step.d.ts.map +1 -1
  114. package/dist/integrations/resident/session-step.js +1 -0
  115. package/dist/integrations/resident/session-step.js.map +1 -1
  116. package/dist/integrations/subagents/runtime.d.ts +6 -0
  117. package/dist/integrations/subagents/runtime.d.ts.map +1 -1
  118. package/dist/integrations/subagents/runtime.js +14 -5
  119. package/dist/integrations/subagents/runtime.js.map +1 -1
  120. package/dist/permissions/browser-sites.d.ts +95 -0
  121. package/dist/permissions/browser-sites.d.ts.map +1 -0
  122. package/dist/permissions/browser-sites.js +270 -0
  123. package/dist/permissions/browser-sites.js.map +1 -0
  124. package/dist/schedule/build.d.ts +79 -0
  125. package/dist/schedule/build.d.ts.map +1 -0
  126. package/dist/schedule/build.js +246 -0
  127. package/dist/schedule/build.js.map +1 -0
  128. package/dist/schedule/changes.d.ts +22 -0
  129. package/dist/schedule/changes.d.ts.map +1 -0
  130. package/dist/schedule/changes.js +55 -0
  131. package/dist/schedule/changes.js.map +1 -0
  132. package/dist/schedule/commands/add.d.ts +24 -0
  133. package/dist/schedule/commands/add.d.ts.map +1 -0
  134. package/dist/schedule/commands/add.js +459 -0
  135. package/dist/schedule/commands/add.js.map +1 -0
  136. package/dist/schedule/commands/args.d.ts +22 -0
  137. package/dist/schedule/commands/args.d.ts.map +1 -0
  138. package/dist/schedule/commands/args.js +80 -0
  139. package/dist/schedule/commands/args.js.map +1 -0
  140. package/dist/schedule/commands/confirm-prompt.d.ts +6 -0
  141. package/dist/schedule/commands/confirm-prompt.d.ts.map +1 -0
  142. package/dist/schedule/commands/confirm-prompt.js +21 -0
  143. package/dist/schedule/commands/confirm-prompt.js.map +1 -0
  144. package/dist/schedule/commands/lifecycle.d.ts +39 -0
  145. package/dist/schedule/commands/lifecycle.d.ts.map +1 -0
  146. package/dist/schedule/commands/lifecycle.js +585 -0
  147. package/dist/schedule/commands/lifecycle.js.map +1 -0
  148. package/dist/schedule/commands/list.d.ts +33 -0
  149. package/dist/schedule/commands/list.d.ts.map +1 -0
  150. package/dist/schedule/commands/list.js +202 -0
  151. package/dist/schedule/commands/list.js.map +1 -0
  152. package/dist/schedule/commands/logs.d.ts +7 -0
  153. package/dist/schedule/commands/logs.d.ts.map +1 -0
  154. package/dist/schedule/commands/logs.js +106 -0
  155. package/dist/schedule/commands/logs.js.map +1 -0
  156. package/dist/schedule/commands/service.d.ts +16 -0
  157. package/dist/schedule/commands/service.d.ts.map +1 -0
  158. package/dist/schedule/commands/service.js +458 -0
  159. package/dist/schedule/commands/service.js.map +1 -0
  160. package/dist/schedule/daemon/daemon.d.ts +156 -0
  161. package/dist/schedule/daemon/daemon.d.ts.map +1 -0
  162. package/dist/schedule/daemon/daemon.js +1248 -0
  163. package/dist/schedule/daemon/daemon.js.map +1 -0
  164. package/dist/schedule/daemon/endpoint.d.ts +38 -0
  165. package/dist/schedule/daemon/endpoint.d.ts.map +1 -0
  166. package/dist/schedule/daemon/endpoint.js +158 -0
  167. package/dist/schedule/daemon/endpoint.js.map +1 -0
  168. package/dist/schedule/daemon/exit.d.ts +8 -0
  169. package/dist/schedule/daemon/exit.d.ts.map +1 -0
  170. package/dist/schedule/daemon/exit.js +8 -0
  171. package/dist/schedule/daemon/exit.js.map +1 -0
  172. package/dist/schedule/daemon/log.d.ts +12 -0
  173. package/dist/schedule/daemon/log.d.ts.map +1 -0
  174. package/dist/schedule/daemon/log.js +53 -0
  175. package/dist/schedule/daemon/log.js.map +1 -0
  176. package/dist/schedule/daemon/notify.d.ts +31 -0
  177. package/dist/schedule/daemon/notify.d.ts.map +1 -0
  178. package/dist/schedule/daemon/notify.js +89 -0
  179. package/dist/schedule/daemon/notify.js.map +1 -0
  180. package/dist/schedule/daemon/retention.d.ts +16 -0
  181. package/dist/schedule/daemon/retention.d.ts.map +1 -0
  182. package/dist/schedule/daemon/retention.js +46 -0
  183. package/dist/schedule/daemon/retention.js.map +1 -0
  184. package/dist/schedule/daemon/sessions.d.ts +23 -0
  185. package/dist/schedule/daemon/sessions.d.ts.map +1 -0
  186. package/dist/schedule/daemon/sessions.js +52 -0
  187. package/dist/schedule/daemon/sessions.js.map +1 -0
  188. package/dist/schedule/env.d.ts +28 -0
  189. package/dist/schedule/env.d.ts.map +1 -0
  190. package/dist/schedule/env.js +99 -0
  191. package/dist/schedule/env.js.map +1 -0
  192. package/dist/schedule/fire/browser-preflight.d.ts +41 -0
  193. package/dist/schedule/fire/browser-preflight.d.ts.map +1 -0
  194. package/dist/schedule/fire/browser-preflight.js +73 -0
  195. package/dist/schedule/fire/browser-preflight.js.map +1 -0
  196. package/dist/schedule/fire/fire.d.ts +78 -0
  197. package/dist/schedule/fire/fire.d.ts.map +1 -0
  198. package/dist/schedule/fire/fire.js +482 -0
  199. package/dist/schedule/fire/fire.js.map +1 -0
  200. package/dist/schedule/fire/result.d.ts +13 -0
  201. package/dist/schedule/fire/result.d.ts.map +1 -0
  202. package/dist/schedule/fire/result.js +18 -0
  203. package/dist/schedule/fire/result.js.map +1 -0
  204. package/dist/schedule/fire/unattended-note.d.ts +22 -0
  205. package/dist/schedule/fire/unattended-note.d.ts.map +1 -0
  206. package/dist/schedule/fire/unattended-note.js +46 -0
  207. package/dist/schedule/fire/unattended-note.js.map +1 -0
  208. package/dist/schedule/floor.d.ts +116 -0
  209. package/dist/schedule/floor.d.ts.map +1 -0
  210. package/dist/schedule/floor.js +1051 -0
  211. package/dist/schedule/floor.js.map +1 -0
  212. package/dist/schedule/folder.d.ts +34 -0
  213. package/dist/schedule/folder.d.ts.map +1 -0
  214. package/dist/schedule/folder.js +84 -0
  215. package/dist/schedule/folder.js.map +1 -0
  216. package/dist/schedule/paths.d.ts +49 -0
  217. package/dist/schedule/paths.d.ts.map +1 -0
  218. package/dist/schedule/paths.js +53 -0
  219. package/dist/schedule/paths.js.map +1 -0
  220. package/dist/schedule/policy.d.ts +141 -0
  221. package/dist/schedule/policy.d.ts.map +1 -0
  222. package/dist/schedule/policy.js +378 -0
  223. package/dist/schedule/policy.js.map +1 -0
  224. package/dist/schedule/resume-command.d.ts +36 -0
  225. package/dist/schedule/resume-command.d.ts.map +1 -0
  226. package/dist/schedule/resume-command.js +72 -0
  227. package/dist/schedule/resume-command.js.map +1 -0
  228. package/dist/schedule/service/detect.d.ts +22 -0
  229. package/dist/schedule/service/detect.d.ts.map +1 -0
  230. package/dist/schedule/service/detect.js +29 -0
  231. package/dist/schedule/service/detect.js.map +1 -0
  232. package/dist/schedule/service/index.d.ts +48 -0
  233. package/dist/schedule/service/index.d.ts.map +1 -0
  234. package/dist/schedule/service/index.js +352 -0
  235. package/dist/schedule/service/index.js.map +1 -0
  236. package/dist/schedule/service/launchd.d.ts +24 -0
  237. package/dist/schedule/service/launchd.d.ts.map +1 -0
  238. package/dist/schedule/service/launchd.js +84 -0
  239. package/dist/schedule/service/launchd.js.map +1 -0
  240. package/dist/schedule/service/manifest.d.ts +44 -0
  241. package/dist/schedule/service/manifest.d.ts.map +1 -0
  242. package/dist/schedule/service/manifest.js +16 -0
  243. package/dist/schedule/service/manifest.js.map +1 -0
  244. package/dist/schedule/service/names.d.ts +9 -0
  245. package/dist/schedule/service/names.d.ts.map +1 -0
  246. package/dist/schedule/service/names.js +22 -0
  247. package/dist/schedule/service/names.js.map +1 -0
  248. package/dist/schedule/service/quote.d.ts +24 -0
  249. package/dist/schedule/service/quote.d.ts.map +1 -0
  250. package/dist/schedule/service/quote.js +64 -0
  251. package/dist/schedule/service/quote.js.map +1 -0
  252. package/dist/schedule/service/runner.d.ts +17 -0
  253. package/dist/schedule/service/runner.d.ts.map +1 -0
  254. package/dist/schedule/service/runner.js +31 -0
  255. package/dist/schedule/service/runner.js.map +1 -0
  256. package/dist/schedule/service/systemd.d.ts +37 -0
  257. package/dist/schedule/service/systemd.d.ts.map +1 -0
  258. package/dist/schedule/service/systemd.js +96 -0
  259. package/dist/schedule/service/systemd.js.map +1 -0
  260. package/dist/schedule/service/windows-task.d.ts +51 -0
  261. package/dist/schedule/service/windows-task.d.ts.map +1 -0
  262. package/dist/schedule/service/windows-task.js +134 -0
  263. package/dist/schedule/service/windows-task.js.map +1 -0
  264. package/dist/schedule/service/wsl.d.ts +57 -0
  265. package/dist/schedule/service/wsl.d.ts.map +1 -0
  266. package/dist/schedule/service/wsl.js +111 -0
  267. package/dist/schedule/service/wsl.js.map +1 -0
  268. package/dist/schedule/store/atomic.d.ts +43 -0
  269. package/dist/schedule/store/atomic.d.ts.map +1 -0
  270. package/dist/schedule/store/atomic.js +135 -0
  271. package/dist/schedule/store/atomic.js.map +1 -0
  272. package/dist/schedule/store/claims.d.ts +26 -0
  273. package/dist/schedule/store/claims.d.ts.map +1 -0
  274. package/dist/schedule/store/claims.js +57 -0
  275. package/dist/schedule/store/claims.js.map +1 -0
  276. package/dist/schedule/store/digest.d.ts +18 -0
  277. package/dist/schedule/store/digest.d.ts.map +1 -0
  278. package/dist/schedule/store/digest.js +139 -0
  279. package/dist/schedule/store/digest.js.map +1 -0
  280. package/dist/schedule/store/history.d.ts +21 -0
  281. package/dist/schedule/store/history.d.ts.map +1 -0
  282. package/dist/schedule/store/history.js +114 -0
  283. package/dist/schedule/store/history.js.map +1 -0
  284. package/dist/schedule/store/jobs.d.ts +61 -0
  285. package/dist/schedule/store/jobs.d.ts.map +1 -0
  286. package/dist/schedule/store/jobs.js +210 -0
  287. package/dist/schedule/store/jobs.js.map +1 -0
  288. package/dist/schedule/store/state.d.ts +19 -0
  289. package/dist/schedule/store/state.d.ts.map +1 -0
  290. package/dist/schedule/store/state.js +38 -0
  291. package/dist/schedule/store/state.js.map +1 -0
  292. package/dist/schedule/types.d.ts +256 -0
  293. package/dist/schedule/types.d.ts.map +1 -0
  294. package/dist/schedule/types.js +9 -0
  295. package/dist/schedule/types.js.map +1 -0
  296. package/dist/skills/catalog.d.ts +96 -0
  297. package/dist/skills/catalog.d.ts.map +1 -0
  298. package/dist/skills/catalog.js +226 -0
  299. package/dist/skills/catalog.js.map +1 -0
  300. package/dist/skills/save.d.ts +148 -0
  301. package/dist/skills/save.d.ts.map +1 -0
  302. package/dist/skills/save.js +344 -0
  303. package/dist/skills/save.js.map +1 -0
  304. package/dist/skills/store.d.ts +103 -16
  305. package/dist/skills/store.d.ts.map +1 -1
  306. package/dist/skills/store.js +227 -30
  307. package/dist/skills/store.js.map +1 -1
  308. package/dist/tui/App.d.ts.map +1 -1
  309. package/dist/tui/App.js +591 -72
  310. package/dist/tui/App.js.map +1 -1
  311. package/dist/tui/LiveActivity.d.ts +8 -1
  312. package/dist/tui/LiveActivity.d.ts.map +1 -1
  313. package/dist/tui/LiveActivity.js +20 -4
  314. package/dist/tui/LiveActivity.js.map +1 -1
  315. package/dist/tui/PermissionOverlay.d.ts +24 -4
  316. package/dist/tui/PermissionOverlay.d.ts.map +1 -1
  317. package/dist/tui/PermissionOverlay.js +113 -15
  318. package/dist/tui/PermissionOverlay.js.map +1 -1
  319. package/dist/tui/SaveSkillOverlay.d.ts +33 -0
  320. package/dist/tui/SaveSkillOverlay.d.ts.map +1 -0
  321. package/dist/tui/SaveSkillOverlay.js +118 -0
  322. package/dist/tui/SaveSkillOverlay.js.map +1 -0
  323. package/dist/tui/agent.d.ts +185 -5
  324. package/dist/tui/agent.d.ts.map +1 -1
  325. package/dist/tui/agent.js +325 -54
  326. package/dist/tui/agent.js.map +1 -1
  327. package/dist/tui/browser-notices.d.ts +33 -0
  328. package/dist/tui/browser-notices.d.ts.map +1 -0
  329. package/dist/tui/browser-notices.js +102 -0
  330. package/dist/tui/browser-notices.js.map +1 -0
  331. package/dist/tui/permission-review.d.ts.map +1 -1
  332. package/dist/tui/permission-review.js +53 -4
  333. package/dist/tui/permission-review.js.map +1 -1
  334. package/dist/tui/schedule/host-commands.d.ts +34 -0
  335. package/dist/tui/schedule/host-commands.d.ts.map +1 -0
  336. package/dist/tui/schedule/host-commands.js +309 -0
  337. package/dist/tui/schedule/host-commands.js.map +1 -0
  338. package/dist/tui/schedule/integration.d.ts +62 -0
  339. package/dist/tui/schedule/integration.d.ts.map +1 -0
  340. package/dist/tui/schedule/integration.js +145 -0
  341. package/dist/tui/schedule/integration.js.map +1 -0
  342. package/dist/tui/schedule/loop-host.d.ts +42 -0
  343. package/dist/tui/schedule/loop-host.d.ts.map +1 -0
  344. package/dist/tui/schedule/loop-host.js +153 -0
  345. package/dist/tui/schedule/loop-host.js.map +1 -0
  346. package/dist/tui/schedule/resume.d.ts +122 -0
  347. package/dist/tui/schedule/resume.d.ts.map +1 -0
  348. package/dist/tui/schedule/resume.js +324 -0
  349. package/dist/tui/schedule/resume.js.map +1 -0
  350. package/dist/tui/schedule/startup.d.ts +11 -0
  351. package/dist/tui/schedule/startup.d.ts.map +1 -0
  352. package/dist/tui/schedule/startup.js +121 -0
  353. package/dist/tui/schedule/startup.js.map +1 -0
  354. package/dist/tui/schedule/tool-host.d.ts +44 -0
  355. package/dist/tui/schedule/tool-host.d.ts.map +1 -0
  356. package/dist/tui/schedule/tool-host.js +294 -0
  357. package/dist/tui/schedule/tool-host.js.map +1 -0
  358. package/dist/tui/skills/learning.d.ts +74 -0
  359. package/dist/tui/skills/learning.d.ts.map +1 -0
  360. package/dist/tui/skills/learning.js +131 -0
  361. package/dist/tui/skills/learning.js.map +1 -0
  362. package/dist/tui/skills/suggest-setting.d.ts +22 -0
  363. package/dist/tui/skills/suggest-setting.d.ts.map +1 -0
  364. package/dist/tui/skills/suggest-setting.js +55 -0
  365. package/dist/tui/skills/suggest-setting.js.map +1 -0
  366. package/dist/tui/skills/suggestion-ledger.d.ts +35 -0
  367. package/dist/tui/skills/suggestion-ledger.d.ts.map +1 -0
  368. package/dist/tui/skills/suggestion-ledger.js +52 -0
  369. package/dist/tui/skills/suggestion-ledger.js.map +1 -0
  370. package/dist/tui/slashCommands.d.ts +20 -0
  371. package/dist/tui/slashCommands.d.ts.map +1 -1
  372. package/dist/tui/slashCommands.js +76 -2
  373. package/dist/tui/slashCommands.js.map +1 -1
  374. package/dist/tui/turn-interruption.d.ts +20 -1
  375. package/dist/tui/turn-interruption.d.ts.map +1 -1
  376. package/dist/tui/turn-interruption.js +43 -0
  377. package/dist/tui/turn-interruption.js.map +1 -1
  378. package/dist/tui/types.d.ts +9 -1
  379. package/dist/tui/types.d.ts.map +1 -1
  380. package/package.json +6 -4
  381. package/skills/README.md +15 -0
  382. package/skills/browser-automation/SKILL.md +84 -0
  383. package/skills/schedule-task/SKILL.md +140 -0
  384. package/skills/skill-creator/SKILL.md +101 -0
@@ -0,0 +1,39 @@
1
+ /**
2
+ * `schedule pause | resume | remove | run-now | prune`.
3
+ *
4
+ * Resuming does not catch up what came due while the job was paused: the
5
+ * resume is a definition change, and the evaluator counts from it.
6
+ */
7
+ import type { CommandContext } from '../../commands/types.js';
8
+ import { EXIT_UNAVAILABLE } from '../../exit-codes.js';
9
+ import { type FireDependencies } from '../fire/fire.js';
10
+ import type { SchedulePaths } from '../paths.js';
11
+ import type { ScheduleJobState } from '../types.js';
12
+ export declare function pauseCommand(ctx: CommandContext, argv: readonly string[], resume?: boolean): Promise<number>;
13
+ export declare function removeCommand(ctx: CommandContext, argv: readonly string[]): Promise<number>;
14
+ /**
15
+ * Record the end of a job's parked run that was answered elsewhere (the TUI)
16
+ * and has since finished, as a scheduler's tick would. A scheduler that
17
+ * answers is asked to look now instead; with none, it is settled here.
18
+ * Idempotent: a run is settled only while the job's state still names it as
19
+ * parked and its turn is over, so a scheduler settling it too finds nothing
20
+ * left. Returns the job's state afterwards, or `undefined` for no such job.
21
+ */
22
+ export declare function settleAnsweredPark(paths: SchedulePaths, jobId: string): Promise<ScheduleJobState | undefined>;
23
+ export declare function runNowCommand(ctx: CommandContext, argv: readonly string[],
24
+ /** Test seam: what the foreground run is given. */
25
+ fireDeps?: Omit<FireDependencies, 'keepLogging'>): Promise<number>;
26
+ /**
27
+ * `schedule prune`: list — and with `--delete`, remove — run files and the
28
+ * sessions of runs that ended before `--older-than` (default 30 days).
29
+ * Sessions of runs still parked are never touched.
30
+ *
31
+ * A removed job's runs are included (without `--job`): `remove` keeps its
32
+ * history and run files, and nothing else would ever reach them. Once none
33
+ * of its runs is left, its history goes too.
34
+ */
35
+ export declare function pruneCommand(ctx: CommandContext, argv: readonly string[]): Promise<number>;
36
+ /** The size of what the scheduler keeps, for `status`. */
37
+ export declare function scheduleDiskUsage(root: string): number;
38
+ export { EXIT_UNAVAILABLE };
39
+ //# sourceMappingURL=lifecycle.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"lifecycle.d.ts","sourceRoot":"","sources":["../../../src/schedule/commands/lifecycle.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAaH,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,yBAAyB,CAAA;AAC7D,OAAO,EAAW,gBAAgB,EAAc,MAAM,qBAAqB,CAAA;AAM3E,OAAO,EAAE,KAAK,gBAAgB,EAAW,MAAM,iBAAiB,CAAA;AAEhE,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,aAAa,CAAA;AAahD,OAAO,KAAK,EAGX,gBAAgB,EAEhB,MAAM,aAAa,CAAA;AAIpB,wBAAsB,YAAY,CACjC,GAAG,EAAE,cAAc,EACnB,IAAI,EAAE,SAAS,MAAM,EAAE,EACvB,MAAM,UAAQ,GACZ,OAAO,CAAC,MAAM,CAAC,CA8CjB;AAED,wBAAsB,aAAa,CAAC,GAAG,EAAE,cAAc,EAAE,IAAI,EAAE,SAAS,MAAM,EAAE,GAAG,OAAO,CAAC,MAAM,CAAC,CAqEjG;AAgDD;;;;;;;GAOG;AACH,wBAAsB,kBAAkB,CACvC,KAAK,EAAE,aAAa,EACpB,KAAK,EAAE,MAAM,GACX,OAAO,CAAC,gBAAgB,GAAG,SAAS,CAAC,CAIvC;AAED,wBAAsB,aAAa,CAClC,GAAG,EAAE,cAAc,EACnB,IAAI,EAAE,SAAS,MAAM,EAAE;AACvB,mDAAmD;AACnD,QAAQ,GAAE,IAAI,CAAC,gBAAgB,EAAE,aAAa,CAAM,GAClD,OAAO,CAAC,MAAM,CAAC,CAoJjB;AAED;;;;;;;;GAQG;AACH,wBAAsB,YAAY,CAAC,GAAG,EAAE,cAAc,EAAE,IAAI,EAAE,SAAS,MAAM,EAAE,GAAG,OAAO,CAAC,MAAM,CAAC,CAoJhG;AAoFD,0DAA0D;AAC1D,wBAAgB,iBAAiB,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAoBtD;AAED,OAAO,EAAE,gBAAgB,EAAE,CAAA"}
@@ -0,0 +1,585 @@
1
+ /**
2
+ * `schedule pause | resume | remove | run-now | prune`.
3
+ *
4
+ * Resuming does not catch up what came due while the job was paused: the
5
+ * resume is a definition change, and the evaluator counts from it.
6
+ */
7
+ import { readdirSync, rmSync, statSync } from 'node:fs';
8
+ import { constants as osConstants } from 'node:os';
9
+ import { join } from 'node:path';
10
+ import { NOOP_LOGGER, SessionPaths, asSessionId, generateScheduleRunId, openSessionIndex, releaseHeldSessionLeases, } from '@namzu/sdk';
11
+ import { EXIT_OK, EXIT_UNAVAILABLE, EXIT_USAGE } from '../../exit-codes.js';
12
+ import { closeSessions, refreshIndex } from '../../integrations/sessions/store.js';
13
+ import { CLI_VERSION } from '../../version.js';
14
+ import { MANUAL_KEY_PREFIX, ScheduleDaemon, appendRunRecord } from '../daemon/daemon.js';
15
+ import { callEndpoint, readEndpoint } from '../daemon/endpoint.js';
16
+ import { abandonParkedTurn, sessionFacts, sessionLeaseLive } from '../daemon/sessions.js';
17
+ import { runFire } from '../fire/fire.js';
18
+ import { isFinal, readRunResult } from '../fire/result.js';
19
+ import { resumeCommand } from '../resume-command.js';
20
+ import { claimOccurrence } from '../store/claims.js';
21
+ import { appendHistory, foldHistory, readHistory } from '../store/history.js';
22
+ import { confirmationHolds, deleteJob, findJob, listJobs, readJob, updateJob, } from '../store/jobs.js';
23
+ import { readState, writeState } from '../store/state.js';
24
+ import { flag, has, interactive, parseArgs, parseMs, pathsFor } from './args.js';
25
+ import { askYesNo } from './confirm-prompt.js';
26
+ export async function pauseCommand(ctx, argv, resume = false) {
27
+ const args = parseArgs(argv, ['home']);
28
+ if (args.unknown.length > 0 || !args.positionals[0]) {
29
+ ctx.formatter.error({ message: `usage: namzu schedule ${resume ? 'resume' : 'pause'} <job>` });
30
+ return EXIT_USAGE;
31
+ }
32
+ const paths = pathsFor(args);
33
+ try {
34
+ const job = findJob(paths, args.positionals[0]);
35
+ if (resume) {
36
+ if (job.state !== 'paused') {
37
+ ctx.formatter.error({ message: `${job.name} is ${job.state}, not paused` });
38
+ return 1;
39
+ }
40
+ if (!confirmationHolds(job)) {
41
+ ctx.formatter.error({
42
+ message: `${job.name} changed since it was confirmed; confirm it with \`namzu schedule confirm ${job.name}\``,
43
+ });
44
+ return 1;
45
+ }
46
+ }
47
+ else if (job.state !== 'active' && job.state !== 'pending-confirmation') {
48
+ ctx.formatter.error({ message: `${job.name} is ${job.state}` });
49
+ return 1;
50
+ }
51
+ const now = new Date();
52
+ const next = updateJob(paths, job.id, job.revision, (j) => resume
53
+ ? { ...j, state: 'active', pausedAt: undefined, pausedBy: undefined }
54
+ : { ...j, state: 'paused', pausedAt: now.toISOString(), pausedBy: 'operator' });
55
+ appendHistory(paths, job.id, {
56
+ v: 1,
57
+ kind: 'job',
58
+ at: now.toISOString(),
59
+ action: resume ? 'resumed' : 'paused',
60
+ by: 'operator',
61
+ });
62
+ ctx.formatter.print({
63
+ text: `${next.name} ${resume ? 'resumed' : 'paused'}.`,
64
+ state: next.state,
65
+ });
66
+ return EXIT_OK;
67
+ }
68
+ catch (error) {
69
+ ctx.formatter.error({ message: error instanceof Error ? error.message : String(error) });
70
+ return 1;
71
+ }
72
+ }
73
+ export async function removeCommand(ctx, argv) {
74
+ const args = parseArgs(argv, ['home', 'yes!', 'force!']);
75
+ if (args.unknown.length > 0 || !args.positionals[0]) {
76
+ ctx.formatter.error({ message: 'usage: namzu schedule remove <job> [--yes] [--force]' });
77
+ return EXIT_USAGE;
78
+ }
79
+ const paths = pathsFor(args);
80
+ try {
81
+ const job = findJob(paths, args.positionals[0]);
82
+ const state = readState(paths, job.id);
83
+ if (state.activeRun && !has(args, 'force')) {
84
+ ctx.formatter.error({
85
+ message: state.activeRun.status === 'awaiting-approval'
86
+ ? `${job.name} has a run waiting for approval; pass --force to remove the job anyway (the waiting turn is abandoned)`
87
+ : `${job.name} has a run in progress; pass --force to remove the job anyway (the run is left to finish)`,
88
+ });
89
+ return 1;
90
+ }
91
+ if (!has(args, 'yes')) {
92
+ if (!interactive()) {
93
+ ctx.formatter.error({ message: 'no terminal to confirm on; pass --yes' });
94
+ return EXIT_USAGE;
95
+ }
96
+ if (!(await askYesNo(`Remove the scheduled job ${job.name}? Its history is kept.`)))
97
+ return 1;
98
+ }
99
+ // A park nobody can answer once the job is gone: its turn is closed and
100
+ // the run recorded now. A run still going records its own end.
101
+ const parked = state.activeRun?.status === 'awaiting-approval' ? state.activeRun : undefined;
102
+ if (parked) {
103
+ const abandoned = await abandonRemovedPark(paths, parked);
104
+ if (!abandoned.ok) {
105
+ ctx.formatter.error({ message: `${job.name}: ${abandoned.reason}; not removed` });
106
+ return 1;
107
+ }
108
+ }
109
+ deleteJob(paths, job.id);
110
+ if (parked) {
111
+ appendRunRecord(paths, job.id, parked, {
112
+ v: 1,
113
+ kind: 'schedule-run-result',
114
+ runId: parked.runId,
115
+ jobId: job.id,
116
+ startedAt: parked.startedAt,
117
+ ...(parked.sessionId ? { sessionId: parked.sessionId } : {}),
118
+ status: 'cancelled',
119
+ exitCode: 1,
120
+ reason: 'the job was removed while the run waited for approval',
121
+ }, new Date().toISOString());
122
+ }
123
+ appendHistory(paths, job.id, {
124
+ v: 1,
125
+ kind: 'job',
126
+ at: new Date().toISOString(),
127
+ action: 'removed',
128
+ by: 'operator',
129
+ });
130
+ ctx.formatter.print({ text: `Removed ${job.name}.` });
131
+ return EXIT_OK;
132
+ }
133
+ catch (error) {
134
+ ctx.formatter.error({ message: error instanceof Error ? error.message : String(error) });
135
+ return 1;
136
+ }
137
+ }
138
+ const REMOVED_PARK_REASON = 'Scheduled run: the job was removed';
139
+ /** Close the parked turn of a job being removed, unless someone is answering it right now. */
140
+ async function abandonRemovedPark(paths, run) {
141
+ if (!run.sessionId || !run.projectSlug || !run.turnId)
142
+ return { ok: true };
143
+ const ref = { home: paths.home, projectSlug: run.projectSlug, sessionId: run.sessionId };
144
+ if (await sessionLeaseLive(ref)) {
145
+ return { ok: false, reason: 'its waiting run is open in a session right now' };
146
+ }
147
+ const facts = await sessionFacts(ref);
148
+ if (facts?.activeTurn?.turnId !== run.turnId || !facts.activeTurn.paused)
149
+ return { ok: true };
150
+ try {
151
+ await abandonParkedTurn(ref, run.turnId, REMOVED_PARK_REASON);
152
+ return { ok: true };
153
+ }
154
+ catch (error) {
155
+ return {
156
+ ok: false,
157
+ reason: `its waiting turn could not be closed: ${error instanceof Error ? error.message : String(error)}`,
158
+ };
159
+ }
160
+ }
161
+ /** The epoch a foreground `run-now` records its run under. */
162
+ const FOREGROUND_EPOCH = 'foreground';
163
+ /** A daemon that starts nothing: it records and settles a foreground run as a scheduler would. */
164
+ function foregroundRecorder(paths) {
165
+ return new ScheduleDaemon({
166
+ paths,
167
+ log: NOOP_LOGGER,
168
+ version: CLI_VERSION,
169
+ epoch: FOREGROUND_EPOCH,
170
+ maxConcurrentRuns: 1,
171
+ // The operator is at this terminal.
172
+ notifications: false,
173
+ spawnFire: () => {
174
+ throw new Error('a foreground recorder starts no runs');
175
+ },
176
+ notify: async () => { },
177
+ fingerprint: () => '',
178
+ });
179
+ }
180
+ /**
181
+ * Record the end of a job's parked run that was answered elsewhere (the TUI)
182
+ * and has since finished, as a scheduler's tick would. A scheduler that
183
+ * answers is asked to look now instead; with none, it is settled here.
184
+ * Idempotent: a run is settled only while the job's state still names it as
185
+ * parked and its turn is over, so a scheduler settling it too finds nothing
186
+ * left. Returns the job's state afterwards, or `undefined` for no such job.
187
+ */
188
+ export async function settleAnsweredPark(paths, jobId) {
189
+ const endpoint = readEndpoint(paths.endpoint);
190
+ if (endpoint && (await callEndpoint(endpoint, 'reload')))
191
+ return readState(paths, jobId);
192
+ return foregroundRecorder(paths).reconcileJob(jobId);
193
+ }
194
+ export async function runNowCommand(ctx, argv,
195
+ /** Test seam: what the foreground run is given. */
196
+ fireDeps = {}) {
197
+ const args = parseArgs(argv, ['home']);
198
+ if (args.unknown.length > 0 || !args.positionals[0]) {
199
+ ctx.formatter.error({ message: 'usage: namzu schedule run-now <job>' });
200
+ return EXIT_USAGE;
201
+ }
202
+ const paths = pathsFor(args);
203
+ try {
204
+ const job = findJob(paths, args.positionals[0]);
205
+ const endpoint = readEndpoint(paths.endpoint);
206
+ if (endpoint) {
207
+ const answer = await callEndpoint(endpoint, 'run-now', { jobId: job.id });
208
+ if (answer) {
209
+ if (answer.ok) {
210
+ ctx.formatter.print({
211
+ text: `${job.name} queued with the scheduler; follow it with \`namzu schedule history ${job.name}\`.`,
212
+ });
213
+ return EXIT_OK;
214
+ }
215
+ ctx.formatter.error({ message: String(answer.message ?? 'refused') });
216
+ return 1;
217
+ }
218
+ }
219
+ // No daemon: run it here, in the foreground, with the same once-only claim.
220
+ if (job.state !== 'active' || !confirmationHolds(job)) {
221
+ ctx.formatter.error({ message: `${job.name} is not active and confirmed` });
222
+ return 1;
223
+ }
224
+ const recorder = foregroundRecorder(paths);
225
+ let state = readState(paths, job.id);
226
+ // An earlier foreground run whose process is gone (killed, the terminal
227
+ // closed) is settled first, as a scheduler would settle it.
228
+ if (state.activeRun?.daemonEpoch === FOREGROUND_EPOCH)
229
+ state = (await recorder.reconcileJob(job.id)) ?? state;
230
+ if (state.activeRun) {
231
+ ctx.formatter.error({
232
+ message: `${job.name} already has a run ${state.activeRun.status === 'awaiting-approval' ? 'waiting for approval' : 'in progress'}`,
233
+ });
234
+ return 1;
235
+ }
236
+ const runId = generateScheduleRunId();
237
+ const key = `${MANUAL_KEY_PREFIX}${runId}`;
238
+ const startedAt = new Date().toISOString();
239
+ if (!claimOccurrence(paths, {
240
+ jobId: job.id,
241
+ key,
242
+ runId,
243
+ daemonEpoch: FOREGROUND_EPOCH,
244
+ at: startedAt,
245
+ }))
246
+ return 1;
247
+ ctx.formatter.info(`The scheduler is not running; running ${job.name} here.`);
248
+ // Recorded as the job's run in progress, as a daemon's run is: a
249
+ // scheduler that starts meanwhile adopts it instead of starting the
250
+ // next occurrence beside it, and a park is found by `/resume`, held
251
+ // against later occurrences and expired like any other.
252
+ const run = {
253
+ runId,
254
+ key,
255
+ trigger: 'manual',
256
+ startedAt,
257
+ daemonEpoch: FOREGROUND_EPOCH,
258
+ status: 'running',
259
+ };
260
+ writeState(paths, { ...readState(paths, job.id), activeRun: run });
261
+ appendHistory(paths, job.id, {
262
+ v: 1,
263
+ kind: 'run',
264
+ at: startedAt,
265
+ runId,
266
+ key,
267
+ trigger: 'manual',
268
+ startedAt,
269
+ status: 'running',
270
+ });
271
+ // How the run ended is recorded once, whichever way it ends: runFire
272
+ // returning, its watchdog stopping the process, or a signal.
273
+ let recorded;
274
+ const record = (code, reason) => {
275
+ recorded ??= (async () => {
276
+ const written = readRunResult(paths, job.id, runId);
277
+ const result = isFinal(written)
278
+ ? written
279
+ : {
280
+ v: 1,
281
+ kind: 'schedule-run-result',
282
+ runId,
283
+ jobId: job.id,
284
+ startedAt,
285
+ ...(written ?? {}),
286
+ status: 'interrupted',
287
+ exitCode: code || 1,
288
+ reason,
289
+ };
290
+ if (!(await recorder.finalizeRun(job.id, runId, result)) && !readJob(paths, job.id)) {
291
+ // Removed with --force meanwhile: nothing else will record it.
292
+ appendRunRecord(paths, job.id, run, result, new Date().toISOString());
293
+ }
294
+ return result;
295
+ })();
296
+ return recorded;
297
+ };
298
+ const exit = fireDeps.exit ?? ((c) => process.exit(c));
299
+ const onSignal = (signal) => {
300
+ const code = 128 + (osConstants.signals[signal] ?? 1);
301
+ void record(code, `the run was interrupted (${signal})`)
302
+ .catch(() => undefined)
303
+ .then(() => releaseHeldSessionLeases().catch(() => undefined))
304
+ .finally(() => exit(code));
305
+ };
306
+ const handlers = ['SIGINT', 'SIGTERM', 'SIGHUP'].map((signal) => [signal, () => onSignal(signal)]);
307
+ for (const [signal, handler] of handlers)
308
+ process.on(signal, handler);
309
+ let code;
310
+ try {
311
+ // This terminal's logging stays as the operator set it; a run started by
312
+ // the daemon writes JSON lines into its log file instead.
313
+ code = await runFire(ctx, paths, { jobId: job.id, runId, key, revision: job.revision, trigger: 'manual' }, {
314
+ ...fireDeps,
315
+ keepLogging: true,
316
+ // The watchdog has written `timed-out`; record it before the process goes.
317
+ exit: (c) => {
318
+ void record(c, 'the run ended without recording a result')
319
+ .catch(() => undefined)
320
+ .finally(() => exit(c));
321
+ },
322
+ });
323
+ }
324
+ finally {
325
+ for (const [signal, handler] of handlers)
326
+ process.off(signal, handler);
327
+ }
328
+ const result = await record(code, 'the run ended without recording a result');
329
+ ctx.formatter.print({
330
+ text: `${job.name}: ${result?.status ?? 'interrupted'}${result?.reason ? ` — ${result.reason}` : ''}${result?.sessionId ? `\nsession ${result.sessionId}` : ''}${result?.status === 'awaiting-approval' && result.sessionId ? `\nanswer it: ${resumeCommand(job, result.sessionId)}` : ''}`,
331
+ status: result?.status,
332
+ });
333
+ return code;
334
+ }
335
+ catch (error) {
336
+ ctx.formatter.error({ message: error instanceof Error ? error.message : String(error) });
337
+ return 1;
338
+ }
339
+ }
340
+ /**
341
+ * `schedule prune`: list — and with `--delete`, remove — run files and the
342
+ * sessions of runs that ended before `--older-than` (default 30 days).
343
+ * Sessions of runs still parked are never touched.
344
+ *
345
+ * A removed job's runs are included (without `--job`): `remove` keeps its
346
+ * history and run files, and nothing else would ever reach them. Once none
347
+ * of its runs is left, its history goes too.
348
+ */
349
+ export async function pruneCommand(ctx, argv) {
350
+ const args = parseArgs(argv, ['home', 'job', 'older-than', 'delete!', 'yes!']);
351
+ if (args.unknown.length > 0) {
352
+ ctx.formatter.error({ message: `unknown option: ${args.unknown.join(', ')}` });
353
+ return EXIT_USAGE;
354
+ }
355
+ const paths = pathsFor(args);
356
+ const olderThan = parseMs('--older-than', flag(args, 'older-than')) ?? 30 * 86_400_000;
357
+ const cutoff = Date.now() - olderThan;
358
+ const live = flag(args, 'job')
359
+ ? [findJob(paths, flag(args, 'job'))]
360
+ : listJobs(paths).jobs;
361
+ const subjects = live.map((job) => {
362
+ const active = readState(paths, job.id).activeRun?.runId;
363
+ return { id: job.id, name: job.name, removed: false, ...(active ? { active } : {}) };
364
+ });
365
+ if (!flag(args, 'job')) {
366
+ const known = new Set(listJobIds(paths));
367
+ for (const id of removedJobIds(paths, known))
368
+ subjects.push({ id, name: `removed job ${id}`, removed: true });
369
+ }
370
+ const doomed = [];
371
+ /** Removed jobs every one of whose runs is doomed: their history goes too. */
372
+ const emptied = [];
373
+ for (const subject of subjects) {
374
+ const kept = new Set();
375
+ const seen = new Set();
376
+ for (const folded of foldHistory(readHistory(paths, subject.id))) {
377
+ if (folded.kind !== 'run')
378
+ continue;
379
+ seen.add(folded.runId);
380
+ // A removed job's run the history still shows open had nobody left to
381
+ // record its end: its own result, or its session, says whether it did.
382
+ const r = subject.removed ? await settleRemovedRun(paths, subject.id, folded) : folded;
383
+ if (r.runId === subject.active ||
384
+ r.status === 'awaiting-approval' ||
385
+ r.status === 'running' ||
386
+ !(Date.parse(r.endedAt ?? r.at) < cutoff)) {
387
+ kept.add(r.runId);
388
+ continue;
389
+ }
390
+ const result = readRunResult(paths, subject.id, r.runId);
391
+ doomed.push({
392
+ subject,
393
+ runId: r.runId,
394
+ ...(r.sessionId ? { sessionId: r.sessionId } : {}),
395
+ ...(result?.projectSlug ? { slug: result.projectSlug } : {}),
396
+ });
397
+ }
398
+ // Run files history does not name (a removed job's, or a run that never
399
+ // got a record): by the result's end time, else the file's.
400
+ if (subject.removed) {
401
+ for (const runId of runIdsOnDisk(paths, subject.id)) {
402
+ if (seen.has(runId))
403
+ continue;
404
+ const result = readRunResult(paths, subject.id, runId);
405
+ const ended = result?.endedAt
406
+ ? Date.parse(result.endedAt)
407
+ : mtimeOf(paths, subject.id, runId);
408
+ if (result?.status === 'running' ||
409
+ result?.status === 'awaiting-approval' ||
410
+ !(ended < cutoff)) {
411
+ kept.add(runId);
412
+ continue;
413
+ }
414
+ doomed.push({
415
+ subject,
416
+ runId,
417
+ ...(result?.sessionId ? { sessionId: result.sessionId } : {}),
418
+ ...(result?.projectSlug ? { slug: result.projectSlug } : {}),
419
+ });
420
+ }
421
+ if (kept.size === 0)
422
+ emptied.push(subject);
423
+ }
424
+ }
425
+ const lines = [
426
+ ...doomed.map((d) => `${d.subject.name} run ${d.runId}${d.sessionId ? ` session ${d.sessionId}` : ''}`),
427
+ ...emptied.map((subject) => `${subject.name} history`),
428
+ ];
429
+ if (!has(args, 'delete')) {
430
+ ctx.formatter.print(lines.length === 0
431
+ ? 'Nothing older than the cutoff.'
432
+ : `Would delete ${doomed.length} runs${emptied.length > 0 ? ` and the history of ${emptied.length} removed jobs` : ''} (pass --delete):\n${lines.join('\n')}`);
433
+ return EXIT_OK;
434
+ }
435
+ if (lines.length === 0) {
436
+ ctx.formatter.print('Nothing older than the cutoff.');
437
+ return EXIT_OK;
438
+ }
439
+ ctx.formatter.info(`Deleting:\n${lines.join('\n')}`);
440
+ if (!has(args, 'yes')) {
441
+ if (!interactive()) {
442
+ ctx.formatter.error({ message: 'no terminal to confirm on; pass --yes' });
443
+ return EXIT_USAGE;
444
+ }
445
+ if (!(await askYesNo('Delete these runs and their sessions?')))
446
+ return 1;
447
+ }
448
+ const touched = [];
449
+ for (const d of doomed) {
450
+ rmSync(paths.runResult(d.subject.id, d.runId), { force: true });
451
+ rmSync(paths.runLog(d.subject.id, d.runId), { force: true });
452
+ if (d.sessionId && d.slug) {
453
+ const sp = new SessionPaths({ home: paths.home, slug: d.slug });
454
+ const locator = { sessionId: asSessionId(d.sessionId) };
455
+ rmSync(sp.sessionLog(locator), { force: true });
456
+ rmSync(sp.sessionDir(locator), { recursive: true, force: true });
457
+ touched.push({ slug: d.slug, sessionId: d.sessionId });
458
+ }
459
+ }
460
+ for (const subject of emptied) {
461
+ rmSync(paths.historyOf(subject.id), { force: true });
462
+ rmSync(paths.runsOf(subject.id), { recursive: true, force: true });
463
+ }
464
+ // The session index learns each deleted session is gone. By slug, so a
465
+ // removed job's folder need not be known.
466
+ if (touched.length > 0) {
467
+ try {
468
+ const index = await openSessionIndex({ home: paths.home });
469
+ try {
470
+ for (const t of touched) {
471
+ await refreshIndex({ paths: new SessionPaths({ home: paths.home, slug: t.slug }), slug: t.slug, index }, asSessionId(t.sessionId)).catch(() => undefined);
472
+ }
473
+ }
474
+ finally {
475
+ closeSessions({ index });
476
+ }
477
+ }
478
+ catch { }
479
+ }
480
+ ctx.formatter.print({
481
+ text: `Deleted ${doomed.length} runs${emptied.length > 0 ? ` and the history of ${emptied.length} removed jobs` : ''}.`,
482
+ });
483
+ return EXIT_OK;
484
+ }
485
+ /**
486
+ * A removed job's run as it stands, when its history still shows it open:
487
+ * ended as its result file says, or `interrupted` once no process holds its
488
+ * session. A park is over: nobody can answer the park of a job that is gone.
489
+ */
490
+ async function settleRemovedRun(paths, jobId, r) {
491
+ if (r.status !== 'running' && r.status !== 'awaiting-approval')
492
+ return r;
493
+ const result = readRunResult(paths, jobId, r.runId);
494
+ if (isFinal(result) && result?.status !== 'awaiting-approval') {
495
+ return {
496
+ ...r,
497
+ status: result?.status,
498
+ endedAt: result?.endedAt ?? r.at,
499
+ ...(result?.sessionId ? { sessionId: result.sessionId } : {}),
500
+ };
501
+ }
502
+ const sessionId = result?.sessionId ?? r.sessionId;
503
+ if (sessionId && result?.projectSlug) {
504
+ const ref = { home: paths.home, projectSlug: result.projectSlug, sessionId };
505
+ if (await sessionLeaseLive(ref))
506
+ return r;
507
+ }
508
+ else if (r.status === 'running' && Date.now() - Date.parse(r.startedAt) < 60_000) {
509
+ return r;
510
+ }
511
+ const ended = mtimeOf(paths, jobId, r.runId);
512
+ return {
513
+ ...r,
514
+ status: r.status === 'awaiting-approval' ? 'cancelled' : 'interrupted',
515
+ endedAt: new Date(Number.isFinite(ended) ? ended : Date.parse(r.at)).toISOString(),
516
+ };
517
+ }
518
+ /** Job ids with a definition file. */
519
+ function listJobIds(paths) {
520
+ return namesIn(paths.jobs)
521
+ .filter((n) => n.endsWith('.json'))
522
+ .map((n) => n.slice(0, -'.json'.length));
523
+ }
524
+ /** Ids that have run files or history but no definition any more. */
525
+ function removedJobIds(paths, known) {
526
+ const ids = new Set([
527
+ ...namesIn(paths.runs),
528
+ ...namesIn(paths.history)
529
+ .filter((n) => n.endsWith('.jsonl'))
530
+ .map((n) => n.slice(0, -'.jsonl'.length)),
531
+ ]);
532
+ return [...ids].filter((id) => !known.has(id)).sort();
533
+ }
534
+ function runIdsOnDisk(paths, jobId) {
535
+ return [
536
+ ...new Set(namesIn(paths.runsOf(jobId))
537
+ .filter((n) => n.endsWith('.json') || n.endsWith('.log'))
538
+ .map((n) => n.replace(/\.(json|log)$/, ''))),
539
+ ];
540
+ }
541
+ function mtimeOf(paths, jobId, runId) {
542
+ for (const path of [paths.runResult(jobId, runId), paths.runLog(jobId, runId)]) {
543
+ try {
544
+ return statSync(path).mtimeMs;
545
+ }
546
+ catch { }
547
+ }
548
+ return Number.NaN;
549
+ }
550
+ function namesIn(dir) {
551
+ try {
552
+ return readdirSync(dir);
553
+ }
554
+ catch {
555
+ return [];
556
+ }
557
+ }
558
+ /** The size of what the scheduler keeps, for `status`. */
559
+ export function scheduleDiskUsage(root) {
560
+ let total = 0;
561
+ const visit = (dir) => {
562
+ let names;
563
+ try {
564
+ names = readdirSync(dir);
565
+ }
566
+ catch {
567
+ return;
568
+ }
569
+ for (const name of names) {
570
+ const path = join(dir, name);
571
+ try {
572
+ const st = statSync(path);
573
+ if (st.isDirectory())
574
+ visit(path);
575
+ else
576
+ total += st.size;
577
+ }
578
+ catch { }
579
+ }
580
+ };
581
+ visit(root);
582
+ return total;
583
+ }
584
+ export { EXIT_UNAVAILABLE };
585
+ //# sourceMappingURL=lifecycle.js.map