agentplane 0.1.9 → 0.2.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 (645) hide show
  1. package/README.md +4 -4
  2. package/assets/AGENTS.md +281 -70
  3. package/assets/agents/CODER.json +1 -0
  4. package/assets/agents/INTEGRATOR.json +1 -0
  5. package/assets/agents/ORCHESTRATOR.json +1 -0
  6. package/assets/agents/PLANNER.json +1 -0
  7. package/assets/agents/TESTER.json +1 -0
  8. package/dist/backends/task-backend/load.d.ts +13 -0
  9. package/dist/backends/task-backend/load.d.ts.map +1 -0
  10. package/dist/backends/task-backend/load.js +58 -0
  11. package/dist/backends/task-backend/local-backend.d.ts +28 -0
  12. package/dist/backends/task-backend/local-backend.d.ts.map +1 -0
  13. package/dist/backends/task-backend/local-backend.js +335 -0
  14. package/dist/backends/task-backend/redmine/client.d.ts +8 -0
  15. package/dist/backends/task-backend/redmine/client.d.ts.map +1 -0
  16. package/dist/backends/task-backend/redmine/client.js +60 -0
  17. package/dist/backends/task-backend/redmine/comments.d.ts +12 -0
  18. package/dist/backends/task-backend/redmine/comments.d.ts.map +1 -0
  19. package/dist/backends/task-backend/redmine/comments.js +54 -0
  20. package/dist/backends/task-backend/redmine/fields.d.ts +9 -0
  21. package/dist/backends/task-backend/redmine/fields.d.ts.map +1 -0
  22. package/dist/backends/task-backend/redmine/fields.js +38 -0
  23. package/dist/backends/task-backend/redmine/mapping.d.ts +20 -0
  24. package/dist/backends/task-backend/redmine/mapping.d.ts.map +1 -0
  25. package/dist/backends/task-backend/redmine/mapping.js +114 -0
  26. package/dist/backends/task-backend/redmine/parse.d.ts +3 -0
  27. package/dist/backends/task-backend/redmine/parse.d.ts.map +1 -0
  28. package/dist/backends/task-backend/redmine/parse.js +27 -0
  29. package/dist/backends/task-backend/redmine/remote.d.ts +19 -0
  30. package/dist/backends/task-backend/redmine/remote.d.ts.map +1 -0
  31. package/dist/backends/task-backend/redmine/remote.js +82 -0
  32. package/dist/backends/task-backend/redmine-backend.d.ts +80 -0
  33. package/dist/backends/task-backend/redmine-backend.d.ts.map +1 -0
  34. package/dist/backends/task-backend/redmine-backend.js +505 -0
  35. package/dist/backends/task-backend/shared/concurrency.d.ts +3 -0
  36. package/dist/backends/task-backend/shared/concurrency.d.ts.map +1 -0
  37. package/dist/backends/task-backend/shared/concurrency.js +21 -0
  38. package/dist/backends/task-backend/shared/constants.d.ts +4 -0
  39. package/dist/backends/task-backend/shared/constants.d.ts.map +1 -0
  40. package/dist/backends/task-backend/shared/constants.js +4 -0
  41. package/dist/backends/task-backend/shared/doc.d.ts +11 -0
  42. package/dist/backends/task-backend/shared/doc.d.ts.map +1 -0
  43. package/dist/backends/task-backend/shared/doc.js +78 -0
  44. package/dist/backends/task-backend/shared/errors.d.ts +10 -0
  45. package/dist/backends/task-backend/shared/errors.d.ts.map +1 -0
  46. package/dist/backends/task-backend/shared/errors.js +18 -0
  47. package/dist/backends/task-backend/shared/events.d.ts +3 -0
  48. package/dist/backends/task-backend/shared/events.d.ts.map +1 -0
  49. package/dist/backends/task-backend/shared/events.js +29 -0
  50. package/dist/backends/task-backend/shared/export.d.ts +15 -0
  51. package/dist/backends/task-backend/shared/export.d.ts.map +1 -0
  52. package/dist/backends/task-backend/shared/export.js +60 -0
  53. package/dist/backends/task-backend/shared/id.d.ts +13 -0
  54. package/dist/backends/task-backend/shared/id.d.ts.map +1 -0
  55. package/dist/backends/task-backend/shared/id.js +17 -0
  56. package/dist/backends/task-backend/shared/normalize.d.ts +8 -0
  57. package/dist/backends/task-backend/shared/normalize.d.ts.map +1 -0
  58. package/dist/backends/task-backend/shared/normalize.js +54 -0
  59. package/dist/backends/task-backend/shared/record.d.ts +4 -0
  60. package/dist/backends/task-backend/shared/record.d.ts.map +1 -0
  61. package/dist/backends/task-backend/shared/record.js +53 -0
  62. package/dist/backends/task-backend/shared/strings.d.ts +4 -0
  63. package/dist/backends/task-backend/shared/strings.d.ts.map +1 -0
  64. package/dist/backends/task-backend/shared/strings.js +21 -0
  65. package/dist/backends/task-backend/shared/types.d.ts +84 -0
  66. package/dist/backends/task-backend/shared/types.d.ts.map +1 -0
  67. package/dist/backends/task-backend/shared/types.js +1 -0
  68. package/dist/backends/task-backend/shared.d.ts +11 -0
  69. package/dist/backends/task-backend/shared.d.ts.map +1 -0
  70. package/dist/backends/task-backend/shared.js +9 -0
  71. package/dist/backends/task-backend.d.ts +4 -204
  72. package/dist/backends/task-backend.d.ts.map +1 -1
  73. package/dist/backends/task-backend.js +4 -1366
  74. package/dist/backends/task-index.js +2 -2
  75. package/dist/cli/archive.d.ts +0 -2
  76. package/dist/cli/archive.d.ts.map +1 -1
  77. package/dist/cli/archive.js +1 -2
  78. package/dist/cli/command-guide.d.ts.map +1 -1
  79. package/dist/cli/command-guide.js +25 -8
  80. package/dist/cli/parse/lifecycle.d.ts +64 -0
  81. package/dist/cli/parse/lifecycle.d.ts.map +1 -0
  82. package/dist/cli/parse/lifecycle.js +280 -0
  83. package/dist/cli/run-cli/command-catalog.d.ts +16 -0
  84. package/dist/cli/run-cli/command-catalog.d.ts.map +1 -0
  85. package/dist/cli/run-cli/command-catalog.js +204 -0
  86. package/dist/cli/run-cli/commands/config.d.ts +20 -0
  87. package/dist/cli/run-cli/commands/config.d.ts.map +1 -0
  88. package/dist/cli/run-cli/commands/config.js +130 -0
  89. package/dist/cli/run-cli/commands/core.d.ts +14 -0
  90. package/dist/cli/run-cli/commands/core.d.ts.map +1 -0
  91. package/dist/cli/run-cli/commands/core.js +144 -0
  92. package/dist/cli/run-cli/commands/ide.d.ts +13 -0
  93. package/dist/cli/run-cli/commands/ide.d.ts.map +1 -0
  94. package/dist/cli/run-cli/commands/ide.js +67 -0
  95. package/dist/cli/run-cli/commands/init/base-branch.d.ts +9 -0
  96. package/dist/cli/run-cli/commands/init/base-branch.d.ts.map +1 -0
  97. package/dist/cli/run-cli/commands/init/base-branch.js +11 -0
  98. package/dist/cli/run-cli/commands/init/conflicts.d.ts +11 -0
  99. package/dist/cli/run-cli/commands/init/conflicts.d.ts.map +1 -0
  100. package/dist/cli/run-cli/commands/init/conflicts.js +42 -0
  101. package/dist/cli/run-cli/commands/init/git.d.ts +8 -0
  102. package/dist/cli/run-cli/commands/init/git.d.ts.map +1 -0
  103. package/dist/cli/run-cli/commands/init/git.js +12 -0
  104. package/dist/cli/run-cli/commands/init/ide-sync.d.ts +9 -0
  105. package/dist/cli/run-cli/commands/init/ide-sync.d.ts.map +1 -0
  106. package/dist/cli/run-cli/commands/init/ide-sync.js +18 -0
  107. package/dist/cli/run-cli/commands/init/recipes.d.ts +2 -0
  108. package/dist/cli/run-cli/commands/init/recipes.d.ts.map +1 -0
  109. package/dist/cli/run-cli/commands/init/recipes.js +11 -0
  110. package/dist/cli/run-cli/commands/init/write-agents.d.ts +11 -0
  111. package/dist/cli/run-cli/commands/init/write-agents.d.ts.map +1 -0
  112. package/dist/cli/run-cli/commands/init/write-agents.js +30 -0
  113. package/dist/cli/run-cli/commands/init/write-config.d.ts +15 -0
  114. package/dist/cli/run-cli/commands/init/write-config.d.ts.map +1 -0
  115. package/dist/cli/run-cli/commands/init/write-config.js +45 -0
  116. package/dist/cli/run-cli/commands/init.d.ts +21 -0
  117. package/dist/cli/run-cli/commands/init.d.ts.map +1 -0
  118. package/dist/cli/run-cli/commands/init.js +332 -0
  119. package/dist/cli/run-cli/registry.run.d.ts +4 -0
  120. package/dist/cli/run-cli/registry.run.d.ts.map +1 -0
  121. package/dist/cli/run-cli/registry.run.js +19 -0
  122. package/dist/cli/run-cli.d.ts.map +1 -1
  123. package/dist/cli/run-cli.js +182 -2463
  124. package/dist/cli/spec/docs-render.d.ts +3 -0
  125. package/dist/cli/spec/docs-render.d.ts.map +1 -0
  126. package/dist/cli/spec/docs-render.js +118 -0
  127. package/dist/cli/spec/errors.d.ts +9 -0
  128. package/dist/cli/spec/errors.d.ts.map +1 -0
  129. package/dist/cli/spec/errors.js +18 -0
  130. package/dist/cli/spec/help-render.d.ts +43 -0
  131. package/dist/cli/spec/help-render.d.ts.map +1 -0
  132. package/dist/cli/spec/help-render.js +185 -0
  133. package/dist/cli/spec/help.d.ts +10 -0
  134. package/dist/cli/spec/help.d.ts.map +1 -0
  135. package/dist/cli/spec/help.js +64 -0
  136. package/dist/cli/spec/parse.d.ts +8 -0
  137. package/dist/cli/spec/parse.d.ts.map +1 -0
  138. package/dist/cli/spec/parse.js +188 -0
  139. package/dist/cli/spec/registry.d.ts +12 -0
  140. package/dist/cli/spec/registry.d.ts.map +1 -0
  141. package/dist/cli/spec/registry.js +47 -0
  142. package/dist/cli/spec/spec.d.ts +76 -0
  143. package/dist/cli/spec/spec.d.ts.map +1 -0
  144. package/dist/cli/spec/spec.js +1 -0
  145. package/dist/cli/spec/suggest.d.ts +2 -0
  146. package/dist/cli/spec/suggest.d.ts.map +1 -0
  147. package/dist/cli/spec/suggest.js +45 -0
  148. package/dist/commands/backend/sync.command.d.ts +12 -0
  149. package/dist/commands/backend/sync.command.d.ts.map +1 -0
  150. package/dist/commands/backend/sync.command.js +79 -0
  151. package/dist/commands/backend.d.ts +21 -8
  152. package/dist/commands/backend.d.ts.map +1 -1
  153. package/dist/commands/backend.js +28 -165
  154. package/dist/commands/block.command.d.ts +19 -0
  155. package/dist/commands/block.command.d.ts.map +1 -0
  156. package/dist/commands/block.command.js +143 -0
  157. package/dist/commands/branch/base.command.d.ts +20 -0
  158. package/dist/commands/branch/base.command.d.ts.map +1 -0
  159. package/dist/commands/branch/base.command.js +110 -0
  160. package/dist/commands/branch/base.d.ts +19 -0
  161. package/dist/commands/branch/base.d.ts.map +1 -0
  162. package/dist/commands/branch/base.js +114 -0
  163. package/dist/commands/branch/cleanup-merged.d.ts +11 -0
  164. package/dist/commands/branch/cleanup-merged.d.ts.map +1 -0
  165. package/dist/commands/branch/cleanup-merged.js +141 -0
  166. package/dist/commands/branch/index.d.ts +6 -59
  167. package/dist/commands/branch/index.d.ts.map +1 -1
  168. package/dist/commands/branch/index.js +6 -513
  169. package/dist/commands/branch/internal/archive-pr.d.ts +2 -0
  170. package/dist/commands/branch/internal/archive-pr.d.ts.map +1 -0
  171. package/dist/commands/branch/internal/archive-pr.js +17 -0
  172. package/dist/commands/branch/internal/work-validate.d.ts +3 -0
  173. package/dist/commands/branch/internal/work-validate.d.ts.map +1 -0
  174. package/dist/commands/branch/internal/work-validate.js +27 -0
  175. package/dist/commands/branch/remove.command.d.ts +10 -0
  176. package/dist/commands/branch/remove.command.d.ts.map +1 -0
  177. package/dist/commands/branch/remove.command.js +63 -0
  178. package/dist/commands/branch/remove.d.ts +9 -0
  179. package/dist/commands/branch/remove.d.ts.map +1 -0
  180. package/dist/commands/branch/remove.js +65 -0
  181. package/dist/commands/branch/status.command.d.ts +8 -0
  182. package/dist/commands/branch/status.command.d.ts.map +1 -0
  183. package/dist/commands/branch/status.command.js +36 -0
  184. package/dist/commands/branch/status.d.ts +7 -0
  185. package/dist/commands/branch/status.d.ts.map +1 -0
  186. package/dist/commands/branch/status.js +60 -0
  187. package/dist/commands/branch/work-start.command.d.ts +11 -0
  188. package/dist/commands/branch/work-start.command.d.ts.map +1 -0
  189. package/dist/commands/branch/work-start.command.js +80 -0
  190. package/dist/commands/branch/work-start.d.ts +11 -0
  191. package/dist/commands/branch/work-start.d.ts.map +1 -0
  192. package/dist/commands/branch/work-start.js +120 -0
  193. package/dist/commands/cleanup/merged.command.d.ts +17 -0
  194. package/dist/commands/cleanup/merged.command.d.ts.map +1 -0
  195. package/dist/commands/cleanup/merged.command.js +75 -0
  196. package/dist/commands/commit.command.d.ts +6 -0
  197. package/dist/commands/commit.command.d.ts.map +1 -0
  198. package/dist/commands/commit.command.js +24 -0
  199. package/dist/commands/commit.spec.d.ts +18 -0
  200. package/dist/commands/commit.spec.d.ts.map +1 -0
  201. package/dist/commands/commit.spec.js +119 -0
  202. package/dist/commands/docs/cli.command.d.ts +9 -0
  203. package/dist/commands/docs/cli.command.d.ts.map +1 -0
  204. package/dist/commands/docs/cli.command.js +51 -0
  205. package/dist/commands/finish.command.d.ts +28 -0
  206. package/dist/commands/finish.command.d.ts.map +1 -0
  207. package/dist/commands/finish.command.js +237 -0
  208. package/dist/commands/guard/clean.command.d.ts +7 -0
  209. package/dist/commands/guard/clean.command.d.ts.map +1 -0
  210. package/dist/commands/guard/clean.command.js +14 -0
  211. package/dist/commands/guard/commit.command.d.ts +19 -0
  212. package/dist/commands/guard/commit.command.d.ts.map +1 -0
  213. package/dist/commands/guard/commit.command.js +132 -0
  214. package/dist/commands/guard/guard.command.d.ts +5 -0
  215. package/dist/commands/guard/guard.command.d.ts.map +1 -0
  216. package/dist/commands/guard/guard.command.js +21 -0
  217. package/dist/commands/guard/impl/allow.d.ts +18 -0
  218. package/dist/commands/guard/impl/allow.d.ts.map +1 -0
  219. package/dist/commands/guard/impl/allow.js +77 -0
  220. package/dist/commands/guard/impl/close-message.d.ts +16 -0
  221. package/dist/commands/guard/impl/close-message.d.ts.map +1 -0
  222. package/dist/commands/guard/impl/close-message.js +156 -0
  223. package/dist/commands/guard/impl/commands.d.ts +32 -0
  224. package/dist/commands/guard/impl/commands.d.ts.map +1 -0
  225. package/dist/commands/guard/impl/commands.js +191 -0
  226. package/dist/commands/guard/impl/comment-commit.d.ts +25 -0
  227. package/dist/commands/guard/impl/comment-commit.d.ts.map +1 -0
  228. package/dist/commands/guard/impl/comment-commit.js +137 -0
  229. package/dist/commands/guard/impl/env.d.ts +10 -0
  230. package/dist/commands/guard/impl/env.d.ts.map +1 -0
  231. package/dist/commands/guard/impl/env.js +12 -0
  232. package/dist/commands/guard/impl/policy.d.ts +19 -0
  233. package/dist/commands/guard/impl/policy.d.ts.map +1 -0
  234. package/dist/commands/guard/impl/policy.js +46 -0
  235. package/dist/commands/guard/index.d.ts +4 -87
  236. package/dist/commands/guard/index.d.ts.map +1 -1
  237. package/dist/commands/guard/index.js +4 -481
  238. package/dist/commands/guard/suggest-allow.command.d.ts +7 -0
  239. package/dist/commands/guard/suggest-allow.command.d.ts.map +1 -0
  240. package/dist/commands/guard/suggest-allow.command.js +28 -0
  241. package/dist/commands/hooks/hooks.command.d.ts +5 -0
  242. package/dist/commands/hooks/hooks.command.d.ts.map +1 -0
  243. package/dist/commands/hooks/hooks.command.js +18 -0
  244. package/dist/commands/hooks/index.d.ts.map +1 -1
  245. package/dist/commands/hooks/index.js +36 -81
  246. package/dist/commands/hooks/install.command.d.ts +7 -0
  247. package/dist/commands/hooks/install.command.d.ts.map +1 -0
  248. package/dist/commands/hooks/install.command.js +14 -0
  249. package/dist/commands/hooks/run.command.d.ts +9 -0
  250. package/dist/commands/hooks/run.command.d.ts.map +1 -0
  251. package/dist/commands/hooks/run.command.js +39 -0
  252. package/dist/commands/hooks/uninstall.command.d.ts +7 -0
  253. package/dist/commands/hooks/uninstall.command.d.ts.map +1 -0
  254. package/dist/commands/hooks/uninstall.command.js +16 -0
  255. package/dist/commands/integrate.command.d.ts +14 -0
  256. package/dist/commands/integrate.command.d.ts.map +1 -0
  257. package/dist/commands/integrate.command.js +61 -0
  258. package/dist/commands/pr/check.d.ts +8 -0
  259. package/dist/commands/pr/check.d.ts.map +1 -0
  260. package/dist/commands/pr/check.js +78 -0
  261. package/dist/commands/pr/index.d.ts +5 -45
  262. package/dist/commands/pr/index.d.ts.map +1 -1
  263. package/dist/commands/pr/index.js +5 -857
  264. package/dist/commands/pr/integrate/artifacts.d.ts +14 -0
  265. package/dist/commands/pr/integrate/artifacts.d.ts.map +1 -0
  266. package/dist/commands/pr/integrate/artifacts.js +45 -0
  267. package/dist/commands/pr/integrate/cmd.d.ts +14 -0
  268. package/dist/commands/pr/integrate/cmd.d.ts.map +1 -0
  269. package/dist/commands/pr/integrate/cmd.js +150 -0
  270. package/dist/commands/pr/integrate/internal/finalize.d.ts +25 -0
  271. package/dist/commands/pr/integrate/internal/finalize.d.ts.map +1 -0
  272. package/dist/commands/pr/integrate/internal/finalize.js +86 -0
  273. package/dist/commands/pr/integrate/internal/merge.d.ts +40 -0
  274. package/dist/commands/pr/integrate/internal/merge.d.ts.map +1 -0
  275. package/dist/commands/pr/integrate/internal/merge.js +138 -0
  276. package/dist/commands/pr/integrate/internal/prepare.d.ts +33 -0
  277. package/dist/commands/pr/integrate/internal/prepare.d.ts.map +1 -0
  278. package/dist/commands/pr/integrate/internal/prepare.js +142 -0
  279. package/dist/commands/pr/integrate/internal/worktree.d.ts +14 -0
  280. package/dist/commands/pr/integrate/internal/worktree.d.ts.map +1 -0
  281. package/dist/commands/pr/integrate/internal/worktree.js +51 -0
  282. package/dist/commands/pr/integrate/verify.d.ts +22 -0
  283. package/dist/commands/pr/integrate/verify.d.ts.map +1 -0
  284. package/dist/commands/pr/integrate/verify.js +60 -0
  285. package/dist/commands/pr/integrate.d.ts +2 -0
  286. package/dist/commands/pr/integrate.d.ts.map +1 -0
  287. package/dist/commands/pr/integrate.js +1 -0
  288. package/dist/commands/pr/internal/pr-paths.d.ts +29 -0
  289. package/dist/commands/pr/internal/pr-paths.d.ts.map +1 -0
  290. package/dist/commands/pr/internal/pr-paths.js +38 -0
  291. package/dist/commands/pr/internal/review-template.d.ts +9 -0
  292. package/dist/commands/pr/internal/review-template.d.ts.map +1 -0
  293. package/dist/commands/pr/internal/review-template.js +62 -0
  294. package/dist/commands/pr/note.d.ts +10 -0
  295. package/dist/commands/pr/note.d.ts.map +1 -0
  296. package/dist/commands/pr/note.js +50 -0
  297. package/dist/commands/pr/open.d.ts +10 -0
  298. package/dist/commands/pr/open.d.ts.map +1 -0
  299. package/dist/commands/pr/open.js +80 -0
  300. package/dist/commands/pr/pr.command.d.ts +33 -0
  301. package/dist/commands/pr/pr.command.d.ts.map +1 -0
  302. package/dist/commands/pr/pr.command.js +172 -0
  303. package/dist/commands/pr/update.d.ts +8 -0
  304. package/dist/commands/pr/update.d.ts.map +1 -0
  305. package/dist/commands/pr/update.js +103 -0
  306. package/dist/commands/ready.command.d.ts +8 -0
  307. package/dist/commands/ready.command.d.ts.map +1 -0
  308. package/dist/commands/ready.command.js +28 -0
  309. package/dist/commands/recipes/cache-prune.command.d.ts +6 -0
  310. package/dist/commands/recipes/cache-prune.command.d.ts.map +1 -0
  311. package/dist/commands/recipes/cache-prune.command.js +30 -0
  312. package/dist/commands/recipes/cache.command.d.ts +6 -0
  313. package/dist/commands/recipes/cache.command.d.ts.map +1 -0
  314. package/dist/commands/recipes/cache.command.js +37 -0
  315. package/dist/commands/recipes/explain.command.d.ts +7 -0
  316. package/dist/commands/recipes/explain.command.d.ts.map +1 -0
  317. package/dist/commands/recipes/explain.command.js +10 -0
  318. package/dist/commands/recipes/impl/apply.d.ts +16 -0
  319. package/dist/commands/recipes/impl/apply.d.ts.map +1 -0
  320. package/dist/commands/recipes/impl/apply.js +97 -0
  321. package/dist/commands/recipes/impl/archive.d.ts +2 -0
  322. package/dist/commands/recipes/impl/archive.d.ts.map +1 -0
  323. package/dist/commands/recipes/impl/archive.js +19 -0
  324. package/dist/commands/recipes/impl/commands/cache-prune.d.ts +7 -0
  325. package/dist/commands/recipes/impl/commands/cache-prune.d.ts.map +1 -0
  326. package/dist/commands/recipes/impl/commands/cache-prune.js +94 -0
  327. package/dist/commands/recipes/impl/commands/explain.d.ts +6 -0
  328. package/dist/commands/recipes/impl/commands/explain.d.ts.map +1 -0
  329. package/dist/commands/recipes/impl/commands/explain.js +88 -0
  330. package/dist/commands/recipes/impl/commands/info.d.ts +6 -0
  331. package/dist/commands/recipes/impl/commands/info.d.ts.map +1 -0
  332. package/dist/commands/recipes/impl/commands/info.js +58 -0
  333. package/dist/commands/recipes/impl/commands/install.d.ts +11 -0
  334. package/dist/commands/recipes/impl/commands/install.d.ts.map +1 -0
  335. package/dist/commands/recipes/impl/commands/install.js +212 -0
  336. package/dist/commands/recipes/impl/commands/list-remote.d.ts +7 -0
  337. package/dist/commands/recipes/impl/commands/list-remote.d.ts.map +1 -0
  338. package/dist/commands/recipes/impl/commands/list-remote.js +53 -0
  339. package/dist/commands/recipes/impl/commands/list.d.ts +7 -0
  340. package/dist/commands/recipes/impl/commands/list.d.ts.map +1 -0
  341. package/dist/commands/recipes/impl/commands/list.js +38 -0
  342. package/dist/commands/recipes/impl/commands/remove.d.ts +6 -0
  343. package/dist/commands/recipes/impl/commands/remove.d.ts.map +1 -0
  344. package/dist/commands/recipes/impl/commands/remove.js +35 -0
  345. package/dist/commands/recipes/impl/commands.d.ts +8 -0
  346. package/dist/commands/recipes/impl/commands.d.ts.map +1 -0
  347. package/dist/commands/recipes/impl/commands.js +7 -0
  348. package/dist/commands/recipes/impl/constants.d.ts +13 -0
  349. package/dist/commands/recipes/impl/constants.d.ts.map +1 -0
  350. package/dist/commands/recipes/impl/constants.js +16 -0
  351. package/dist/commands/recipes/impl/format.d.ts +2 -0
  352. package/dist/commands/recipes/impl/format.d.ts.map +1 -0
  353. package/dist/commands/recipes/impl/format.js +9 -0
  354. package/dist/commands/recipes/impl/index.d.ts +12 -0
  355. package/dist/commands/recipes/impl/index.d.ts.map +1 -0
  356. package/dist/commands/recipes/impl/index.js +150 -0
  357. package/dist/commands/recipes/impl/installed-recipes.d.ts +4 -0
  358. package/dist/commands/recipes/impl/installed-recipes.d.ts.map +1 -0
  359. package/dist/commands/recipes/impl/installed-recipes.js +58 -0
  360. package/dist/commands/recipes/impl/manifest.d.ts +4 -0
  361. package/dist/commands/recipes/impl/manifest.d.ts.map +1 -0
  362. package/dist/commands/recipes/impl/manifest.js +43 -0
  363. package/dist/commands/recipes/impl/normalize.d.ts +5 -0
  364. package/dist/commands/recipes/impl/normalize.d.ts.map +1 -0
  365. package/dist/commands/recipes/impl/normalize.js +50 -0
  366. package/dist/commands/recipes/impl/paths.d.ts +13 -0
  367. package/dist/commands/recipes/impl/paths.d.ts.map +1 -0
  368. package/dist/commands/recipes/impl/paths.js +27 -0
  369. package/dist/commands/recipes/impl/project.d.ts +8 -0
  370. package/dist/commands/recipes/impl/project.d.ts.map +1 -0
  371. package/dist/commands/recipes/impl/project.js +23 -0
  372. package/dist/commands/recipes/impl/scenario.d.ts +16 -0
  373. package/dist/commands/recipes/impl/scenario.d.ts.map +1 -0
  374. package/dist/commands/recipes/impl/scenario.js +128 -0
  375. package/dist/commands/recipes/impl/types.d.ts +107 -0
  376. package/dist/commands/recipes/impl/types.d.ts.map +1 -0
  377. package/dist/commands/recipes/impl/types.js +1 -0
  378. package/dist/commands/recipes/info.command.d.ts +7 -0
  379. package/dist/commands/recipes/info.command.d.ts.map +1 -0
  380. package/dist/commands/recipes/info.command.js +10 -0
  381. package/dist/commands/recipes/install.command.d.ts +12 -0
  382. package/dist/commands/recipes/install.command.d.ts.map +1 -0
  383. package/dist/commands/recipes/install.command.js +161 -0
  384. package/dist/commands/recipes/list-remote.command.d.ts +6 -0
  385. package/dist/commands/recipes/list-remote.command.d.ts.map +1 -0
  386. package/dist/commands/recipes/list-remote.command.js +46 -0
  387. package/dist/commands/recipes/list.command.d.ts +6 -0
  388. package/dist/commands/recipes/list.command.d.ts.map +1 -0
  389. package/dist/commands/recipes/list.command.js +39 -0
  390. package/dist/commands/recipes/recipes.command.d.ts +6 -0
  391. package/dist/commands/recipes/recipes.command.d.ts.map +1 -0
  392. package/dist/commands/recipes/recipes.command.js +45 -0
  393. package/dist/commands/recipes/remove.command.d.ts +7 -0
  394. package/dist/commands/recipes/remove.command.d.ts.map +1 -0
  395. package/dist/commands/recipes/remove.command.js +10 -0
  396. package/dist/commands/recipes.d.ts +7 -81
  397. package/dist/commands/recipes.d.ts.map +1 -1
  398. package/dist/commands/recipes.js +6 -1457
  399. package/dist/commands/scenario/impl/commands.d.ts +19 -0
  400. package/dist/commands/scenario/impl/commands.d.ts.map +1 -0
  401. package/dist/commands/scenario/impl/commands.js +336 -0
  402. package/dist/commands/scenario/impl/report.d.ts +30 -0
  403. package/dist/commands/scenario/impl/report.d.ts.map +1 -0
  404. package/dist/commands/scenario/impl/report.js +99 -0
  405. package/dist/commands/scenario/info.command.d.ts +8 -0
  406. package/dist/commands/scenario/info.command.d.ts.map +1 -0
  407. package/dist/commands/scenario/info.command.js +27 -0
  408. package/dist/commands/scenario/list.command.d.ts +5 -0
  409. package/dist/commands/scenario/list.command.d.ts.map +1 -0
  410. package/dist/commands/scenario/list.command.js +9 -0
  411. package/dist/commands/scenario/run.command.d.ts +8 -0
  412. package/dist/commands/scenario/run.command.d.ts.map +1 -0
  413. package/dist/commands/scenario/run.command.js +27 -0
  414. package/dist/commands/scenario/scenario.command.d.ts +6 -0
  415. package/dist/commands/scenario/scenario.command.d.ts.map +1 -0
  416. package/dist/commands/scenario/scenario.command.js +37 -0
  417. package/dist/commands/scenario.d.ts +1 -6
  418. package/dist/commands/scenario.d.ts.map +1 -1
  419. package/dist/commands/scenario.js +1 -501
  420. package/dist/commands/shared/git-context.d.ts +23 -0
  421. package/dist/commands/shared/git-context.d.ts.map +1 -0
  422. package/dist/commands/shared/git-context.js +140 -0
  423. package/dist/commands/shared/policy-deny.d.ts +3 -0
  424. package/dist/commands/shared/policy-deny.d.ts.map +1 -0
  425. package/dist/commands/shared/policy-deny.js +12 -0
  426. package/dist/commands/shared/task-backend.d.ts +17 -5
  427. package/dist/commands/shared/task-backend.d.ts.map +1 -1
  428. package/dist/commands/shared/task-backend.js +34 -5
  429. package/dist/commands/shared/task-store.d.ts +16 -0
  430. package/dist/commands/shared/task-store.d.ts.map +1 -0
  431. package/dist/commands/shared/task-store.js +142 -0
  432. package/dist/commands/start.command.d.ts +19 -0
  433. package/dist/commands/start.command.d.ts.map +1 -0
  434. package/dist/commands/start.command.js +143 -0
  435. package/dist/commands/sync.command.d.ts +6 -0
  436. package/dist/commands/sync.command.d.ts.map +1 -0
  437. package/dist/commands/sync.command.js +57 -0
  438. package/dist/commands/task/add.command.d.ts +18 -0
  439. package/dist/commands/task/add.command.d.ts.map +1 -0
  440. package/dist/commands/task/add.command.js +157 -0
  441. package/dist/commands/task/add.d.ts +13 -3
  442. package/dist/commands/task/add.d.ts.map +1 -1
  443. package/dist/commands/task/add.js +21 -126
  444. package/dist/commands/task/block.d.ts +2 -2
  445. package/dist/commands/task/block.d.ts.map +1 -1
  446. package/dist/commands/task/block.js +13 -9
  447. package/dist/commands/task/comment.command.d.ts +10 -0
  448. package/dist/commands/task/comment.command.d.ts.map +1 -0
  449. package/dist/commands/task/comment.command.js +57 -0
  450. package/dist/commands/task/comment.d.ts +2 -0
  451. package/dist/commands/task/comment.d.ts.map +1 -1
  452. package/dist/commands/task/comment.js +10 -7
  453. package/dist/commands/task/derive.command.d.ts +13 -0
  454. package/dist/commands/task/derive.command.d.ts.map +1 -0
  455. package/dist/commands/task/derive.command.js +94 -0
  456. package/dist/commands/task/derive.d.ts +13 -0
  457. package/dist/commands/task/derive.d.ts.map +1 -0
  458. package/dist/commands/task/derive.js +71 -0
  459. package/dist/commands/task/doc-set.command.d.ts +12 -0
  460. package/dist/commands/task/doc-set.command.d.ts.map +1 -0
  461. package/dist/commands/task/doc-set.command.js +82 -0
  462. package/dist/commands/task/doc-show.command.d.ts +10 -0
  463. package/dist/commands/task/doc-show.command.d.ts.map +1 -0
  464. package/dist/commands/task/doc-show.command.js +54 -0
  465. package/dist/commands/task/doc.command.d.ts +7 -0
  466. package/dist/commands/task/doc.command.d.ts.map +1 -0
  467. package/dist/commands/task/doc.command.js +22 -0
  468. package/dist/commands/task/doc.d.ts +9 -6
  469. package/dist/commands/task/doc.d.ts.map +1 -1
  470. package/dist/commands/task/doc.js +61 -113
  471. package/dist/commands/task/export.command.d.ts +6 -0
  472. package/dist/commands/task/export.command.d.ts.map +1 -0
  473. package/dist/commands/task/export.command.js +17 -0
  474. package/dist/commands/task/export.d.ts +2 -0
  475. package/dist/commands/task/export.d.ts.map +1 -1
  476. package/dist/commands/task/export.js +7 -9
  477. package/dist/commands/task/finish.d.ts +5 -4
  478. package/dist/commands/task/finish.d.ts.map +1 -1
  479. package/dist/commands/task/finish.js +50 -17
  480. package/dist/commands/task/index.d.ts +14 -13
  481. package/dist/commands/task/index.d.ts.map +1 -1
  482. package/dist/commands/task/index.js +13 -13
  483. package/dist/commands/task/lint.command.d.ts +5 -0
  484. package/dist/commands/task/lint.command.d.ts.map +1 -0
  485. package/dist/commands/task/lint.command.js +11 -0
  486. package/dist/commands/task/list.command.d.ts +9 -0
  487. package/dist/commands/task/list.command.d.ts.map +1 -0
  488. package/dist/commands/task/list.command.js +68 -0
  489. package/dist/commands/task/list.d.ts +6 -2
  490. package/dist/commands/task/list.d.ts.map +1 -1
  491. package/dist/commands/task/list.js +12 -15
  492. package/dist/commands/task/migrate-doc.command.d.ts +9 -0
  493. package/dist/commands/task/migrate-doc.command.d.ts.map +1 -0
  494. package/dist/commands/task/migrate-doc.command.js +65 -0
  495. package/dist/commands/task/migrate-doc.d.ts +3 -3
  496. package/dist/commands/task/migrate-doc.d.ts.map +1 -1
  497. package/dist/commands/task/migrate-doc.js +40 -47
  498. package/dist/commands/task/migrate.command.d.ts +10 -0
  499. package/dist/commands/task/migrate.command.d.ts.map +1 -0
  500. package/dist/commands/task/migrate.command.js +50 -0
  501. package/dist/commands/task/migrate.d.ts +5 -1
  502. package/dist/commands/task/migrate.d.ts.map +1 -1
  503. package/dist/commands/task/migrate.js +10 -44
  504. package/dist/commands/task/new.command.d.ts +6 -0
  505. package/dist/commands/task/new.command.d.ts.map +1 -0
  506. package/dist/commands/task/new.command.js +13 -0
  507. package/dist/commands/task/new.d.ts +13 -4
  508. package/dist/commands/task/new.d.ts.map +1 -1
  509. package/dist/commands/task/new.js +30 -92
  510. package/dist/commands/task/new.spec.d.ts +4 -0
  511. package/dist/commands/task/new.spec.d.ts.map +1 -0
  512. package/dist/commands/task/new.spec.js +79 -0
  513. package/dist/commands/task/next.command.d.ts +9 -0
  514. package/dist/commands/task/next.command.d.ts.map +1 -0
  515. package/dist/commands/task/next.command.js +89 -0
  516. package/dist/commands/task/next.d.ts +4 -1
  517. package/dist/commands/task/next.d.ts.map +1 -1
  518. package/dist/commands/task/next.js +15 -16
  519. package/dist/commands/task/normalize.command.d.ts +9 -0
  520. package/dist/commands/task/normalize.command.d.ts.map +1 -0
  521. package/dist/commands/task/normalize.command.js +39 -0
  522. package/dist/commands/task/normalize.d.ts +4 -1
  523. package/dist/commands/task/normalize.d.ts.map +1 -1
  524. package/dist/commands/task/normalize.js +18 -31
  525. package/dist/commands/task/plan-approve.command.d.ts +10 -0
  526. package/dist/commands/task/plan-approve.command.d.ts.map +1 -0
  527. package/dist/commands/task/plan-approve.command.js +54 -0
  528. package/dist/commands/task/plan-reject.command.d.ts +10 -0
  529. package/dist/commands/task/plan-reject.command.d.ts.map +1 -0
  530. package/dist/commands/task/plan-reject.command.js +59 -0
  531. package/dist/commands/task/plan-set.command.d.ts +11 -0
  532. package/dist/commands/task/plan-set.command.d.ts.map +1 -0
  533. package/dist/commands/task/plan-set.command.js +76 -0
  534. package/dist/commands/task/plan.d.ts +23 -10
  535. package/dist/commands/task/plan.d.ts.map +1 -1
  536. package/dist/commands/task/plan.js +182 -177
  537. package/dist/commands/task/ready.d.ts +2 -0
  538. package/dist/commands/task/ready.d.ts.map +1 -1
  539. package/dist/commands/task/ready.js +4 -6
  540. package/dist/commands/task/scaffold.command.d.ts +12 -0
  541. package/dist/commands/task/scaffold.command.d.ts.map +1 -0
  542. package/dist/commands/task/scaffold.command.js +73 -0
  543. package/dist/commands/task/scaffold.d.ts +7 -3
  544. package/dist/commands/task/scaffold.d.ts.map +1 -1
  545. package/dist/commands/task/scaffold.js +57 -67
  546. package/dist/commands/task/scrub.command.d.ts +11 -0
  547. package/dist/commands/task/scrub.command.d.ts.map +1 -0
  548. package/dist/commands/task/scrub.command.js +72 -0
  549. package/dist/commands/task/scrub.d.ts +6 -3
  550. package/dist/commands/task/scrub.d.ts.map +1 -1
  551. package/dist/commands/task/scrub.js +12 -68
  552. package/dist/commands/task/search.command.d.ts +11 -0
  553. package/dist/commands/task/search.command.d.ts.map +1 -0
  554. package/dist/commands/task/search.command.js +101 -0
  555. package/dist/commands/task/search.d.ts +5 -1
  556. package/dist/commands/task/search.d.ts.map +1 -1
  557. package/dist/commands/task/search.js +14 -23
  558. package/dist/commands/task/set-status.command.d.ts +21 -0
  559. package/dist/commands/task/set-status.command.d.ts.map +1 -0
  560. package/dist/commands/task/set-status.command.js +171 -0
  561. package/dist/commands/task/set-status.d.ts +2 -0
  562. package/dist/commands/task/set-status.d.ts.map +1 -1
  563. package/dist/commands/task/set-status.js +14 -8
  564. package/dist/commands/task/shared.d.ts +5 -0
  565. package/dist/commands/task/shared.d.ts.map +1 -1
  566. package/dist/commands/task/shared.js +50 -0
  567. package/dist/commands/task/show.command.d.ts +8 -0
  568. package/dist/commands/task/show.command.d.ts.map +1 -0
  569. package/dist/commands/task/show.command.js +19 -0
  570. package/dist/commands/task/show.d.ts +2 -0
  571. package/dist/commands/task/show.d.ts.map +1 -1
  572. package/dist/commands/task/show.js +5 -7
  573. package/dist/commands/task/start.d.ts +2 -2
  574. package/dist/commands/task/start.d.ts.map +1 -1
  575. package/dist/commands/task/start.js +48 -11
  576. package/dist/commands/task/update.command.d.ts +18 -0
  577. package/dist/commands/task/update.command.d.ts.map +1 -0
  578. package/dist/commands/task/update.command.js +141 -0
  579. package/dist/commands/task/update.d.ts +13 -3
  580. package/dist/commands/task/update.d.ts.map +1 -1
  581. package/dist/commands/task/update.js +31 -122
  582. package/dist/commands/task/verify-ok.command.d.ts +13 -0
  583. package/dist/commands/task/verify-ok.command.d.ts.map +1 -0
  584. package/dist/commands/task/verify-ok.command.js +83 -0
  585. package/dist/commands/task/verify-record.d.ts +30 -8
  586. package/dist/commands/task/verify-record.d.ts.map +1 -1
  587. package/dist/commands/task/verify-record.js +107 -117
  588. package/dist/commands/task/verify-rework.command.d.ts +13 -0
  589. package/dist/commands/task/verify-rework.command.d.ts.map +1 -0
  590. package/dist/commands/task/verify-rework.command.js +83 -0
  591. package/dist/commands/task/verify-show.command.d.ts +9 -0
  592. package/dist/commands/task/verify-show.command.d.ts.map +1 -0
  593. package/dist/commands/task/verify-show.command.js +38 -0
  594. package/dist/commands/task/verify.command.d.ts +7 -0
  595. package/dist/commands/task/verify.command.d.ts.map +1 -0
  596. package/dist/commands/task/verify.command.js +20 -0
  597. package/dist/commands/upgrade.command.d.ts +6 -0
  598. package/dist/commands/upgrade.command.d.ts.map +1 -0
  599. package/dist/commands/upgrade.command.js +104 -0
  600. package/dist/commands/upgrade.d.ts +19 -2
  601. package/dist/commands/upgrade.d.ts.map +1 -1
  602. package/dist/commands/upgrade.js +281 -85
  603. package/dist/commands/verify.command.d.ts +16 -0
  604. package/dist/commands/verify.command.d.ts.map +1 -0
  605. package/dist/commands/verify.command.js +113 -0
  606. package/dist/commands/workflow.d.ts +4 -6
  607. package/dist/commands/workflow.d.ts.map +1 -1
  608. package/dist/commands/workflow.js +4 -7
  609. package/dist/meta/release.d.ts +2 -0
  610. package/dist/meta/release.d.ts.map +1 -0
  611. package/dist/meta/release.js +50 -0
  612. package/dist/policy/evaluate.d.ts +3 -0
  613. package/dist/policy/evaluate.d.ts.map +1 -0
  614. package/dist/policy/evaluate.js +27 -0
  615. package/dist/policy/result.d.ts +7 -0
  616. package/dist/policy/result.d.ts.map +1 -0
  617. package/dist/policy/result.js +21 -0
  618. package/dist/policy/rules/allowlist.d.ts +3 -0
  619. package/dist/policy/rules/allowlist.d.ts.map +1 -0
  620. package/dist/policy/rules/allowlist.js +30 -0
  621. package/dist/policy/rules/branch-pr-base.d.ts +3 -0
  622. package/dist/policy/rules/branch-pr-base.d.ts.map +1 -0
  623. package/dist/policy/rules/branch-pr-base.js +43 -0
  624. package/dist/policy/rules/clean-tree.d.ts +3 -0
  625. package/dist/policy/rules/clean-tree.d.ts.map +1 -0
  626. package/dist/policy/rules/clean-tree.js +19 -0
  627. package/dist/policy/rules/commit-subject.d.ts +3 -0
  628. package/dist/policy/rules/commit-subject.d.ts.map +1 -0
  629. package/dist/policy/rules/commit-subject.js +33 -0
  630. package/dist/policy/rules/protected-paths.d.ts +3 -0
  631. package/dist/policy/rules/protected-paths.d.ts.map +1 -0
  632. package/dist/policy/rules/protected-paths.js +53 -0
  633. package/dist/policy/types.d.ts +38 -0
  634. package/dist/policy/types.d.ts.map +1 -0
  635. package/dist/policy/types.js +1 -0
  636. package/dist/shared/write-if-changed.d.ts +3 -0
  637. package/dist/shared/write-if-changed.d.ts.map +1 -0
  638. package/dist/shared/write-if-changed.js +25 -0
  639. package/package.json +3 -3
  640. package/dist/cli/help.d.ts +0 -2
  641. package/dist/cli/help.d.ts.map +0 -1
  642. package/dist/cli/help.js +0 -127
  643. package/dist/commands/task/verify.d.ts +0 -2
  644. package/dist/commands/task/verify.d.ts.map +0 -1
  645. package/dist/commands/task/verify.js +0 -1
@@ -1,1457 +1,6 @@
1
- import { createPublicKey, verify } from "node:crypto";
2
- import { cp, mkdir, mkdtemp, readdir, readFile, rename, rm } from "node:fs/promises";
3
- import os from "node:os";
4
- import path from "node:path";
5
- import { atomicWriteFile, defaultConfig, loadConfig, resolveProject } from "@agentplaneorg/core";
6
- import { extractArchive } from "../cli/archive.js";
7
- import { sha256File } from "../cli/checksum.js";
8
- import { mapCoreError } from "../cli/error-map.js";
9
- import { fileExists, getPathKind } from "../cli/fs-utils.js";
10
- import { downloadToFile, fetchJson, fetchText } from "../cli/http.js";
11
- import { emptyStateMessage, infoMessage, invalidFieldMessage, invalidPathMessage, missingValueMessage, missingFileMessage, requiredFieldMessage, successMessage, usageMessage, } from "../cli/output.js";
12
- import { isRecord } from "../shared/guards.js";
13
- import { CliError } from "../shared/errors.js";
14
- import { dedupeStrings } from "../shared/strings.js";
15
- import { ensureNetworkApproved } from "./shared/network-approval.js";
16
- import { resolvePathFallback } from "./shared/path.js";
17
- const INSTALLED_RECIPES_NAME = "recipes.json";
18
- export const RECIPES_DIR_NAME = "recipes";
19
- export const RECIPES_SCENARIOS_DIR_NAME = "scenarios";
20
- export const RECIPES_SCENARIOS_INDEX_NAME = "scenarios.json";
21
- const RECIPES_REMOTE_INDEX_NAME = "recipes-index.json";
22
- const RECIPES_REMOTE_INDEX_SIG_NAME = "recipes-index.json.sig";
23
- const RECIPE_USAGE = "Usage: agentplane recipes <list|info|explain|install|remove|list-remote|cache> [args]";
24
- const RECIPE_USAGE_EXAMPLE = "agentplane recipes list";
25
- const RECIPE_INFO_USAGE = "Usage: agentplane recipes info <id>";
26
- const RECIPE_INFO_USAGE_EXAMPLE = "agentplane recipes info viewer";
27
- const RECIPE_EXPLAIN_USAGE = "Usage: agentplane recipes explain <id>";
28
- const RECIPE_EXPLAIN_USAGE_EXAMPLE = "agentplane recipes explain viewer";
29
- const RECIPE_INSTALL_USAGE = "Usage: agentplane recipes install --name <id> [--index <path|url>] [--refresh] [--yes] | --path <path> | --url <url> [--yes]";
30
- const RECIPE_INSTALL_USAGE_EXAMPLE = "agentplane recipes install --name viewer";
31
- const RECIPE_REMOVE_USAGE = "Usage: agentplane recipes remove <id>";
32
- const RECIPE_REMOVE_USAGE_EXAMPLE = "agentplane recipes remove viewer";
33
- const RECIPE_CACHE_USAGE = "Usage: agentplane recipes cache <prune> [args]";
34
- const RECIPE_CACHE_USAGE_EXAMPLE = "agentplane recipes cache prune --dry-run";
35
- const RECIPE_CACHE_PRUNE_USAGE = "Usage: agentplane recipes cache prune [--dry-run] [--all]";
36
- const RECIPE_CACHE_PRUNE_USAGE_EXAMPLE = "agentplane recipes cache prune --dry-run";
37
- const RECIPE_LIST_REMOTE_USAGE = "Usage: agentplane recipes list-remote [--refresh] [--index <path|url>] [--yes]";
38
- const RECIPE_LIST_REMOTE_USAGE_EXAMPLE = "agentplane recipes list-remote --refresh";
39
- const DEFAULT_RECIPES_INDEX_URL = "https://raw.githubusercontent.com/basilisk-labs/agentplane-recipes/main/index.json";
40
- const RECIPES_INDEX_PUBLIC_KEYS_ENV = "AGENTPLANE_RECIPES_INDEX_PUBLIC_KEYS";
41
- const RECIPES_INDEX_PUBLIC_KEYS = {
42
- "2026-02": `-----BEGIN PUBLIC KEY-----
43
- MCowBQYDK2VwAyEAeRWdXKVZtz0v+bnQS3zb24jMfa0gflsRUHQkeJkji6E=
44
- -----END PUBLIC KEY-----`,
45
- };
46
- const RECIPE_CONFLICT_MODES = ["fail", "rename", "overwrite"];
47
- const AGENTPLANE_HOME_ENV = "AGENTPLANE_HOME";
48
- const GLOBAL_RECIPES_DIR_NAME = "recipes";
49
- const PROJECT_RECIPES_CACHE_DIR_NAME = "recipes-cache";
50
- function isNotGitRepoError(err) {
51
- if (err instanceof Error) {
52
- return err.message.startsWith("Not a git repository");
53
- }
54
- return false;
55
- }
56
- async function maybeResolveProject(opts) {
57
- try {
58
- return await resolveProject({
59
- cwd: opts.cwd,
60
- rootOverride: opts.rootOverride ?? null,
61
- });
62
- }
63
- catch (err) {
64
- if (isNotGitRepoError(err)) {
65
- if (opts.rootOverride)
66
- throw err;
67
- return null;
68
- }
69
- throw err;
70
- }
71
- }
72
- function parseRecipeListRemoteFlags(args) {
73
- const out = { refresh: false, yes: false };
74
- for (let i = 0; i < args.length; i++) {
75
- const arg = args[i];
76
- if (!arg)
77
- continue;
78
- if (!arg.startsWith("--")) {
79
- throw new CliError({
80
- exitCode: 2,
81
- code: "E_USAGE",
82
- message: usageMessage(RECIPE_LIST_REMOTE_USAGE, RECIPE_LIST_REMOTE_USAGE_EXAMPLE),
83
- });
84
- }
85
- if (arg === "--refresh") {
86
- out.refresh = true;
87
- continue;
88
- }
89
- if (arg === "--yes") {
90
- out.yes = true;
91
- continue;
92
- }
93
- const next = args[i + 1];
94
- if (!next) {
95
- throw new CliError({ exitCode: 2, code: "E_USAGE", message: missingValueMessage(arg) });
96
- }
97
- switch (arg) {
98
- case "--index": {
99
- out.index = next;
100
- break;
101
- }
102
- default: {
103
- throw new CliError({
104
- exitCode: 2,
105
- code: "E_USAGE",
106
- message: usageMessage(RECIPE_LIST_REMOTE_USAGE, RECIPE_LIST_REMOTE_USAGE_EXAMPLE),
107
- });
108
- }
109
- }
110
- i++;
111
- }
112
- return out;
113
- }
114
- function normalizeRecipeId(value) {
115
- const trimmed = value.trim();
116
- if (!trimmed)
117
- throw new Error(requiredFieldMessage("manifest.id"));
118
- if (trimmed.includes("/") || trimmed.includes("\\")) {
119
- throw new Error(invalidPathMessage("manifest.id", "must not contain path separators"));
120
- }
121
- if (trimmed === "." || trimmed === "..") {
122
- throw new Error(invalidPathMessage("manifest.id", "must not be '.' or '..'"));
123
- }
124
- return trimmed;
125
- }
126
- function normalizeAgentId(value) {
127
- const trimmed = value.trim();
128
- if (!trimmed)
129
- throw new Error(requiredFieldMessage("agent.id"));
130
- if (trimmed.includes("/") || trimmed.includes("\\")) {
131
- throw new Error(invalidPathMessage("agent.id", "must not contain path separators"));
132
- }
133
- if (trimmed === "." || trimmed === "..") {
134
- throw new Error(invalidPathMessage("agent.id", "must not be '.' or '..'"));
135
- }
136
- return trimmed;
137
- }
138
- function normalizeScenarioId(value) {
139
- const trimmed = value.trim();
140
- if (!trimmed)
141
- throw new Error(requiredFieldMessage("scenario.id"));
142
- if (trimmed.includes("/") || trimmed.includes("\\")) {
143
- throw new Error(invalidPathMessage("scenario.id", "must not contain path separators"));
144
- }
145
- if (trimmed === "." || trimmed === "..") {
146
- throw new Error(invalidPathMessage("scenario.id", "must not be '.' or '..'"));
147
- }
148
- return trimmed;
149
- }
150
- function normalizeRecipeTags(value) {
151
- if (value === undefined)
152
- return [];
153
- if (!Array.isArray(value))
154
- throw new Error(invalidFieldMessage("manifest.tags", "string[]"));
155
- const tags = value.map((tag) => {
156
- if (typeof tag !== "string")
157
- throw new Error(invalidFieldMessage("manifest.tags", "string[]"));
158
- return tag.trim();
159
- });
160
- return dedupeStrings(tags);
161
- }
162
- function validateRecipeManifest(raw) {
163
- if (!isRecord(raw))
164
- throw new Error(invalidFieldMessage("manifest", "object"));
165
- if (raw.schema_version !== "1")
166
- throw new Error(invalidFieldMessage("manifest.schema_version", '"1"'));
167
- if (typeof raw.id !== "string")
168
- throw new Error(invalidFieldMessage("manifest.id", "string"));
169
- if (typeof raw.version !== "string")
170
- throw new Error(invalidFieldMessage("manifest.version", "string"));
171
- if (typeof raw.name !== "string")
172
- throw new Error(invalidFieldMessage("manifest.name", "string"));
173
- if (typeof raw.summary !== "string")
174
- throw new Error(invalidFieldMessage("manifest.summary", "string"));
175
- if (typeof raw.description !== "string")
176
- throw new Error(invalidFieldMessage("manifest.description", "string"));
177
- const id = normalizeRecipeId(raw.id);
178
- const version = raw.version.trim();
179
- if (!version)
180
- throw new Error(requiredFieldMessage("manifest.version"));
181
- const tags = normalizeRecipeTags(raw.tags);
182
- return {
183
- schema_version: "1",
184
- id,
185
- version,
186
- name: raw.name.trim(),
187
- summary: raw.summary.trim(),
188
- description: raw.description.trim(),
189
- tags: tags.length > 0 ? tags : undefined,
190
- agents: Array.isArray(raw.agents) ? raw.agents : undefined,
191
- tools: Array.isArray(raw.tools) ? raw.tools : undefined,
192
- scenarios: Array.isArray(raw.scenarios)
193
- ? raw.scenarios
194
- : undefined,
195
- };
196
- }
197
- function validateInstalledRecipesFile(raw) {
198
- if (!isRecord(raw))
199
- throw new Error(invalidFieldMessage("recipes.json", "object"));
200
- if (raw.schema_version !== 1)
201
- throw new Error(invalidFieldMessage("recipes.json.schema_version", "1"));
202
- if (!Array.isArray(raw.recipes))
203
- throw new Error(invalidFieldMessage("recipes.json.recipes", "array"));
204
- const updatedAt = typeof raw.updated_at === "string" ? raw.updated_at : "";
205
- const recipes = raw.recipes
206
- .filter((entry) => isRecord(entry))
207
- .map((entry) => {
208
- const manifest = validateRecipeManifest(entry.manifest);
209
- const id = typeof entry.id === "string" ? entry.id.trim() : manifest.id;
210
- const version = typeof entry.version === "string" ? entry.version.trim() : manifest.version;
211
- const source = typeof entry.source === "string" ? entry.source.trim() : "";
212
- const installedAt = typeof entry.installed_at === "string" ? entry.installed_at.trim() : "";
213
- if (!id || !version || !source || !installedAt) {
214
- throw new Error(invalidFieldMessage("recipes.json.recipes[]", "id, version, source, installed_at"));
215
- }
216
- if (id !== manifest.id || version !== manifest.version) {
217
- throw new Error(invalidFieldMessage("recipes.json.recipes[]", "id/version match manifest"));
218
- }
219
- const tags = normalizeRecipeTags(entry.tags ?? manifest.tags ?? []);
220
- return { id, version, source, installed_at: installedAt, tags, manifest };
221
- });
222
- return { schema_version: 1, updated_at: updatedAt, recipes };
223
- }
224
- function sortInstalledRecipes(file) {
225
- const recipes = [...file.recipes].toSorted((a, b) => a.id.localeCompare(b.id));
226
- return { schema_version: 1, updated_at: file.updated_at, recipes };
227
- }
228
- function loadRecipesIndexPublicKeys() {
229
- const raw = process.env[RECIPES_INDEX_PUBLIC_KEYS_ENV];
230
- if (!raw)
231
- return { ...RECIPES_INDEX_PUBLIC_KEYS };
232
- try {
233
- const parsed = JSON.parse(raw);
234
- const merged = { ...RECIPES_INDEX_PUBLIC_KEYS };
235
- for (const [key, value] of Object.entries(parsed)) {
236
- if (typeof value === "string" && value.trim())
237
- merged[key] = value.trim();
238
- }
239
- return merged;
240
- }
241
- catch {
242
- return { ...RECIPES_INDEX_PUBLIC_KEYS };
243
- }
244
- }
245
- function validateRecipesIndexSignature(raw) {
246
- if (!isRecord(raw))
247
- throw new Error(invalidFieldMessage("recipes index signature", "object"));
248
- if (raw.schema_version !== 1) {
249
- throw new Error(invalidFieldMessage("recipes index signature.schema_version", "1"));
250
- }
251
- const keyId = typeof raw.key_id === "string" ? raw.key_id.trim() : "";
252
- const signature = typeof raw.signature === "string" ? raw.signature.trim() : "";
253
- if (!keyId || !signature) {
254
- throw new Error(invalidFieldMessage("recipes index signature", "key_id, signature"));
255
- }
256
- const algorithm = typeof raw.algorithm === "string" ? raw.algorithm.trim() : undefined;
257
- return { schema_version: 1, key_id: keyId, signature, algorithm };
258
- }
259
- function verifyRecipesIndexSignature(indexText, signature) {
260
- if (signature.algorithm && signature.algorithm !== "ed25519") {
261
- throw new Error(invalidFieldMessage("recipes index signature.algorithm", "ed25519"));
262
- }
263
- const keys = loadRecipesIndexPublicKeys();
264
- const publicKey = keys[signature.key_id];
265
- if (!publicKey) {
266
- throw new Error(invalidFieldMessage("recipes index signature.key_id", "known key id"));
267
- }
268
- const key = createPublicKey(publicKey);
269
- const ok = verify(null, Buffer.from(indexText), key, Buffer.from(signature.signature, "base64"));
270
- if (!ok) {
271
- throw new Error("Invalid signature for recipes index");
272
- }
273
- }
274
- function signatureSourceForIndex(source) {
275
- return `${source}.sig`;
276
- }
277
- function validateRecipesIndex(raw) {
278
- if (!isRecord(raw))
279
- throw new Error(invalidFieldMessage("recipes index", "object"));
280
- if (raw.schema_version !== 1)
281
- throw new Error(invalidFieldMessage("recipes index.schema_version", "1"));
282
- if (!Array.isArray(raw.recipes))
283
- throw new Error(invalidFieldMessage("recipes index.recipes", "array"));
284
- const recipes = raw.recipes
285
- .filter((entry) => isRecord(entry))
286
- .map((entry) => {
287
- const id = typeof entry.id === "string" ? entry.id : "";
288
- const summary = typeof entry.summary === "string" ? entry.summary : "";
289
- const description = typeof entry.description === "string" ? entry.description : undefined;
290
- const versionsRaw = Array.isArray(entry.versions) ? entry.versions : [];
291
- if (!id || !summary || versionsRaw.length === 0) {
292
- throw new Error(invalidFieldMessage("recipes index.recipes[]", "id, summary, versions"));
293
- }
294
- const versions = versionsRaw
295
- .filter((version) => isRecord(version))
296
- .map((version) => {
297
- const versionId = typeof version.version === "string" ? version.version : "";
298
- const url = typeof version.url === "string" ? version.url : "";
299
- const sha256 = typeof version.sha256 === "string" ? version.sha256 : "";
300
- if (!versionId || !url || !sha256) {
301
- throw new Error(invalidFieldMessage("recipes index.recipes[].versions[]", "version, url, sha256"));
302
- }
303
- return {
304
- version: versionId,
305
- url,
306
- sha256,
307
- min_agentplane_version: typeof version.min_agentplane_version === "string"
308
- ? version.min_agentplane_version
309
- : undefined,
310
- tags: Array.isArray(version.tags)
311
- ? version.tags.filter((tag) => typeof tag === "string")
312
- : undefined,
313
- };
314
- });
315
- return { id, summary, description, versions };
316
- });
317
- return { schema_version: 1, recipes };
318
- }
319
- function validateScenarioDefinition(raw, sourcePath) {
320
- if (!isRecord(raw))
321
- throw new Error(invalidFieldMessage("scenario", "object", sourcePath));
322
- if (raw.schema_version !== undefined && raw.schema_version !== "1") {
323
- throw new Error(invalidFieldMessage("scenario.schema_version", '"1"', sourcePath));
324
- }
325
- const rawId = typeof raw.id === "string" ? raw.id : "";
326
- const id = normalizeScenarioId(rawId);
327
- const goal = typeof raw.goal === "string" ? raw.goal.trim() : "";
328
- if (!goal)
329
- throw new Error(requiredFieldMessage("scenario.goal", sourcePath));
330
- if (!("inputs" in raw))
331
- throw new Error(requiredFieldMessage("scenario.inputs", sourcePath));
332
- if (!("outputs" in raw))
333
- throw new Error(requiredFieldMessage("scenario.outputs", sourcePath));
334
- if (!Array.isArray(raw.steps)) {
335
- throw new Error(invalidFieldMessage("scenario.steps", "array", sourcePath));
336
- }
337
- return {
338
- schema_version: "1",
339
- id,
340
- summary: typeof raw.summary === "string" ? raw.summary.trim() : undefined,
341
- description: typeof raw.description === "string" ? raw.description.trim() : undefined,
342
- goal,
343
- inputs: raw.inputs,
344
- outputs: raw.outputs,
345
- steps: raw.steps,
346
- };
347
- }
348
- export async function readScenarioDefinition(filePath) {
349
- const raw = JSON.parse(await readFile(filePath, "utf8"));
350
- return validateScenarioDefinition(raw, filePath);
351
- }
352
- export async function readScenarioIndex(filePath) {
353
- const raw = JSON.parse(await readFile(filePath, "utf8"));
354
- if (!isRecord(raw))
355
- throw new Error(invalidFieldMessage("scenarios index", "object"));
356
- if (raw.schema_version !== 1)
357
- throw new Error(invalidFieldMessage("scenarios index.schema_version", "1"));
358
- if (!Array.isArray(raw.scenarios))
359
- throw new Error(invalidFieldMessage("scenarios index.scenarios", "array"));
360
- const scenarios = raw.scenarios
361
- .filter((entry) => isRecord(entry))
362
- .map((entry) => ({
363
- id: typeof entry.id === "string" ? entry.id : "",
364
- summary: typeof entry.summary === "string" ? entry.summary : undefined,
365
- }))
366
- .filter((entry) => entry.id);
367
- return { schema_version: 1, scenarios };
368
- }
369
- function formatJsonBlock(value, indent) {
370
- const payload = JSON.stringify(value, null, 2);
371
- if (!payload)
372
- return "";
373
- return payload
374
- .split("\n")
375
- .map((line) => `${indent}${line}`)
376
- .join("\n");
377
- }
378
- async function collectRecipeScenarioDetails(recipeDir, manifest) {
379
- const scenariosDir = path.join(recipeDir, RECIPES_SCENARIOS_DIR_NAME);
380
- if ((await getPathKind(scenariosDir)) === "dir") {
381
- const files = await readdir(scenariosDir);
382
- const jsonFiles = files.filter((file) => file.toLowerCase().endsWith(".json")).toSorted();
383
- const details = [];
384
- for (const file of jsonFiles) {
385
- const scenario = await readScenarioDefinition(path.join(scenariosDir, file));
386
- details.push({
387
- id: scenario.id,
388
- summary: scenario.summary,
389
- description: scenario.description,
390
- goal: scenario.goal,
391
- inputs: scenario.inputs,
392
- outputs: scenario.outputs,
393
- steps: scenario.steps,
394
- source: "definition",
395
- });
396
- }
397
- return details.toSorted((a, b) => a.id.localeCompare(b.id));
398
- }
399
- const scenariosIndexPath = path.join(recipeDir, RECIPES_SCENARIOS_INDEX_NAME);
400
- if (await fileExists(scenariosIndexPath)) {
401
- const index = await readScenarioIndex(scenariosIndexPath);
402
- return index.scenarios
403
- .map((scenario) => ({
404
- id: scenario.id,
405
- summary: scenario.summary,
406
- source: "index",
407
- }))
408
- .toSorted((a, b) => a.id.localeCompare(b.id));
409
- }
410
- const manifestScenarios = manifest.scenarios ?? [];
411
- if (manifestScenarios.length > 0) {
412
- return manifestScenarios
413
- .map((scenario) => ({
414
- id: scenario?.id ?? "",
415
- summary: scenario?.summary,
416
- source: "manifest",
417
- }))
418
- .filter((scenario) => scenario.id)
419
- .toSorted((a, b) => a.id.localeCompare(b.id));
420
- }
421
- return [];
422
- }
423
- export function normalizeScenarioToolStep(raw, sourcePath) {
424
- if (!isRecord(raw)) {
425
- throw new Error(invalidFieldMessage("scenario step", "object", sourcePath));
426
- }
427
- const tool = typeof raw.tool === "string" ? raw.tool.trim() : "";
428
- if (!tool) {
429
- throw new Error(requiredFieldMessage("scenario step.tool", sourcePath));
430
- }
431
- const args = Array.isArray(raw.args) ? raw.args.filter((arg) => typeof arg === "string") : [];
432
- if (Array.isArray(raw.args) && args.length !== raw.args.length) {
433
- throw new Error(invalidFieldMessage("scenario step.args", "string[]", sourcePath));
434
- }
435
- const env = {};
436
- if (raw.env !== undefined) {
437
- if (!isRecord(raw.env)) {
438
- throw new Error(invalidFieldMessage("scenario step.env", "object", sourcePath));
439
- }
440
- for (const [key, value] of Object.entries(raw.env)) {
441
- if (typeof value !== "string") {
442
- throw new Error(invalidFieldMessage("scenario step.env", "string map", sourcePath));
443
- }
444
- env[key] = value;
445
- }
446
- }
447
- return { tool, args, env };
448
- }
449
- export async function readInstalledRecipesFile(filePath) {
450
- try {
451
- const raw = JSON.parse(await readFile(filePath, "utf8"));
452
- return sortInstalledRecipes(validateInstalledRecipesFile(raw));
453
- }
454
- catch (err) {
455
- const code = err?.code;
456
- if (code === "ENOENT")
457
- return { schema_version: 1, updated_at: "", recipes: [] };
458
- throw err;
459
- }
460
- }
461
- async function writeInstalledRecipesFile(filePath, file) {
462
- const sorted = sortInstalledRecipes({
463
- ...file,
464
- updated_at: new Date().toISOString(),
465
- });
466
- await mkdir(path.dirname(filePath), { recursive: true });
467
- await atomicWriteFile(filePath, `${JSON.stringify(sorted, null, 2)}\n`, "utf8");
468
- }
469
- export async function readRecipeManifest(manifestPath) {
470
- const raw = JSON.parse(await readFile(manifestPath, "utf8"));
471
- return validateRecipeManifest(raw);
472
- }
473
- async function resolveRecipeRoot(extractedDir) {
474
- const rootManifest = path.join(extractedDir, "manifest.json");
475
- if (await fileExists(rootManifest))
476
- return extractedDir;
477
- const entries = await readdir(extractedDir, { withFileTypes: true });
478
- const dirs = entries.filter((entry) => entry.isDirectory()).map((entry) => entry.name);
479
- if (dirs.length !== 1) {
480
- throw new Error(missingFileMessage("manifest.json", "archive root"));
481
- }
482
- const candidate = path.join(extractedDir, dirs[0]);
483
- if (!(await fileExists(path.join(candidate, "manifest.json")))) {
484
- throw new Error(missingFileMessage("manifest.json", "archive root"));
485
- }
486
- return candidate;
487
- }
488
- function resolveAgentplaneHome() {
489
- const overridden = process.env[AGENTPLANE_HOME_ENV]?.trim();
490
- if (overridden)
491
- return overridden;
492
- return path.join(os.homedir(), ".agentplane");
493
- }
494
- function resolveGlobalRecipesDir() {
495
- return path.join(resolveAgentplaneHome(), GLOBAL_RECIPES_DIR_NAME);
496
- }
497
- export function resolveInstalledRecipesPath() {
498
- return path.join(resolveAgentplaneHome(), INSTALLED_RECIPES_NAME);
499
- }
500
- function resolveRecipesIndexCachePath() {
501
- return path.join(resolveAgentplaneHome(), RECIPES_REMOTE_INDEX_NAME);
502
- }
503
- export function resolveInstalledRecipeDir(entry) {
504
- return path.join(resolveGlobalRecipesDir(), entry.id, entry.version);
505
- }
506
- export function resolveProjectRecipesCacheDir(resolved) {
507
- return path.join(resolved.agentplaneDir, PROJECT_RECIPES_CACHE_DIR_NAME);
508
- }
509
- function parseRecipeInstallArgs(args) {
510
- let onConflict = "fail";
511
- let name = null;
512
- let localPath = null;
513
- let url = null;
514
- let index;
515
- let refresh = false;
516
- let yes = false;
517
- const positional = [];
518
- for (let i = 0; i < args.length; i++) {
519
- const arg = args[i];
520
- if (!arg)
521
- continue;
522
- if (arg === "--name") {
523
- const next = args[i + 1];
524
- if (!next)
525
- throw new CliError({
526
- exitCode: 2,
527
- code: "E_USAGE",
528
- message: usageMessage(RECIPE_INSTALL_USAGE, RECIPE_INSTALL_USAGE_EXAMPLE),
529
- });
530
- name = next;
531
- i++;
532
- continue;
533
- }
534
- if (arg === "--path") {
535
- const next = args[i + 1];
536
- if (!next)
537
- throw new CliError({
538
- exitCode: 2,
539
- code: "E_USAGE",
540
- message: usageMessage(RECIPE_INSTALL_USAGE, RECIPE_INSTALL_USAGE_EXAMPLE),
541
- });
542
- localPath = next;
543
- i++;
544
- continue;
545
- }
546
- if (arg === "--url") {
547
- const next = args[i + 1];
548
- if (!next)
549
- throw new CliError({
550
- exitCode: 2,
551
- code: "E_USAGE",
552
- message: usageMessage(RECIPE_INSTALL_USAGE, RECIPE_INSTALL_USAGE_EXAMPLE),
553
- });
554
- url = next;
555
- i++;
556
- continue;
557
- }
558
- if (arg === "--index") {
559
- const next = args[i + 1];
560
- if (!next)
561
- throw new CliError({
562
- exitCode: 2,
563
- code: "E_USAGE",
564
- message: usageMessage(RECIPE_INSTALL_USAGE, RECIPE_INSTALL_USAGE_EXAMPLE),
565
- });
566
- index = next;
567
- i++;
568
- continue;
569
- }
570
- if (arg === "--refresh") {
571
- refresh = true;
572
- continue;
573
- }
574
- if (arg === "--yes") {
575
- yes = true;
576
- continue;
577
- }
578
- if (arg === "--on-conflict") {
579
- const next = args[i + 1];
580
- if (!next)
581
- throw new CliError({
582
- exitCode: 2,
583
- code: "E_USAGE",
584
- message: usageMessage(RECIPE_INSTALL_USAGE, RECIPE_INSTALL_USAGE_EXAMPLE),
585
- });
586
- if (!RECIPE_CONFLICT_MODES.includes(next)) {
587
- throw new CliError({
588
- exitCode: 2,
589
- code: "E_USAGE",
590
- message: usageMessage(RECIPE_INSTALL_USAGE, RECIPE_INSTALL_USAGE_EXAMPLE),
591
- });
592
- }
593
- onConflict = next;
594
- i++;
595
- continue;
596
- }
597
- if (arg.startsWith("--")) {
598
- throw new CliError({
599
- exitCode: 2,
600
- code: "E_USAGE",
601
- message: usageMessage(RECIPE_INSTALL_USAGE, RECIPE_INSTALL_USAGE_EXAMPLE),
602
- });
603
- }
604
- positional.push(arg);
605
- }
606
- const explicitFlags = [name, localPath, url].filter(Boolean).length;
607
- if (explicitFlags > 1) {
608
- throw new CliError({
609
- exitCode: 2,
610
- code: "E_USAGE",
611
- message: usageMessage(RECIPE_INSTALL_USAGE, RECIPE_INSTALL_USAGE_EXAMPLE),
612
- });
613
- }
614
- if (positional.length > 1) {
615
- throw new CliError({
616
- exitCode: 2,
617
- code: "E_USAGE",
618
- message: usageMessage(RECIPE_INSTALL_USAGE, RECIPE_INSTALL_USAGE_EXAMPLE),
619
- });
620
- }
621
- if (positional.length > 0 && explicitFlags > 0) {
622
- throw new CliError({
623
- exitCode: 2,
624
- code: "E_USAGE",
625
- message: usageMessage(RECIPE_INSTALL_USAGE, RECIPE_INSTALL_USAGE_EXAMPLE),
626
- });
627
- }
628
- if (name)
629
- return { source: { type: "name", value: name }, index, refresh, onConflict, yes };
630
- if (localPath)
631
- return { source: { type: "path", value: localPath }, index, refresh, onConflict, yes };
632
- if (url)
633
- return { source: { type: "url", value: url }, index, refresh, onConflict, yes };
634
- if (positional.length === 1) {
635
- return { source: { type: "auto", value: positional[0] }, index, refresh, onConflict, yes };
636
- }
637
- throw new CliError({
638
- exitCode: 2,
639
- code: "E_USAGE",
640
- message: usageMessage(RECIPE_INSTALL_USAGE, RECIPE_INSTALL_USAGE_EXAMPLE),
641
- });
642
- }
643
- function parseRecipeListArgs(args) {
644
- const flags = { full: false };
645
- for (let i = 0; i < args.length; i++) {
646
- const arg = args[i];
647
- if (!arg)
648
- continue;
649
- if (arg === "--full") {
650
- flags.full = true;
651
- continue;
652
- }
653
- if (arg === "--tag") {
654
- const next = args[i + 1];
655
- if (!next)
656
- throw new CliError({
657
- exitCode: 2,
658
- code: "E_USAGE",
659
- message: usageMessage(RECIPE_USAGE, RECIPE_USAGE_EXAMPLE),
660
- });
661
- flags.tag = next.trim();
662
- i++;
663
- continue;
664
- }
665
- if (arg.startsWith("--")) {
666
- throw new CliError({
667
- exitCode: 2,
668
- code: "E_USAGE",
669
- message: usageMessage(RECIPE_USAGE, RECIPE_USAGE_EXAMPLE),
670
- });
671
- }
672
- throw new CliError({
673
- exitCode: 2,
674
- code: "E_USAGE",
675
- message: usageMessage(RECIPE_USAGE, RECIPE_USAGE_EXAMPLE),
676
- });
677
- }
678
- if (flags.tag !== undefined && !flags.tag) {
679
- throw new CliError({
680
- exitCode: 2,
681
- code: "E_USAGE",
682
- message: usageMessage(RECIPE_USAGE, RECIPE_USAGE_EXAMPLE),
683
- });
684
- }
685
- return flags;
686
- }
687
- function parseRecipeCachePruneArgs(args) {
688
- const flags = { dryRun: false, all: false };
689
- for (const arg of args) {
690
- if (!arg)
691
- continue;
692
- if (arg === "--dry-run") {
693
- flags.dryRun = true;
694
- continue;
695
- }
696
- if (arg === "--all") {
697
- flags.all = true;
698
- continue;
699
- }
700
- throw new CliError({
701
- exitCode: 2,
702
- code: "E_USAGE",
703
- message: usageMessage(RECIPE_CACHE_PRUNE_USAGE, RECIPE_CACHE_PRUNE_USAGE_EXAMPLE),
704
- });
705
- }
706
- return flags;
707
- }
708
- async function applyRecipeAgents(opts) {
709
- const agents = opts.manifest.agents ?? [];
710
- if (agents.length === 0)
711
- return;
712
- const agentsDir = path.join(opts.agentplaneDir, "agents");
713
- await mkdir(agentsDir, { recursive: true });
714
- for (const agent of agents) {
715
- const rawId = typeof agent?.id === "string" ? agent.id : "";
716
- const rawFile = typeof agent?.file === "string" ? agent.file : "";
717
- if (!rawId.trim() || !rawFile.trim()) {
718
- throw new Error("manifest.agents entries must include id and file");
719
- }
720
- const agentId = normalizeAgentId(rawId);
721
- const sourcePath = path.join(opts.recipeDir, rawFile);
722
- if (!(await fileExists(sourcePath))) {
723
- throw new Error(missingFileMessage("recipe agent file", rawFile));
724
- }
725
- const rawAgent = JSON.parse(await readFile(sourcePath, "utf8"));
726
- if (!isRecord(rawAgent)) {
727
- throw new Error(invalidFieldMessage("recipe agent file", "JSON object", rawFile));
728
- }
729
- const baseId = `${opts.manifest.id}__${agentId}`;
730
- let targetId = baseId;
731
- let targetPath = path.join(agentsDir, `${targetId}.json`);
732
- if (await getPathKind(targetPath)) {
733
- if (opts.onConflict === "fail") {
734
- throw new CliError({
735
- exitCode: 5,
736
- code: "E_IO",
737
- message: `Agent already exists: ${targetId}`,
738
- });
739
- }
740
- if (opts.onConflict === "rename") {
741
- let counter = 1;
742
- while (await getPathKind(targetPath)) {
743
- targetId = `${baseId}__${counter}`;
744
- targetPath = path.join(agentsDir, `${targetId}.json`);
745
- counter += 1;
746
- }
747
- }
748
- }
749
- rawAgent.id = targetId;
750
- await atomicWriteFile(targetPath, `${JSON.stringify(rawAgent, null, 2)}\n`, "utf8");
751
- }
752
- }
753
- async function applyRecipeScenarios(opts) {
754
- const scenariosDir = path.join(opts.recipeDir, RECIPES_SCENARIOS_DIR_NAME);
755
- const scenariosIndexPath = path.join(opts.recipeDir, RECIPES_SCENARIOS_INDEX_NAME);
756
- const payload = { schema_version: 1, scenarios: [] };
757
- if ((await getPathKind(scenariosDir)) === "dir") {
758
- const entries = await readdir(scenariosDir);
759
- const jsonEntries = entries.filter((entry) => entry.toLowerCase().endsWith(".json")).toSorted();
760
- for (const entry of jsonEntries) {
761
- const scenarioPath = path.join(scenariosDir, entry);
762
- const scenario = await readScenarioDefinition(scenarioPath);
763
- payload.scenarios.push({ id: scenario.id, summary: scenario.summary });
764
- }
765
- }
766
- else {
767
- const scenarios = opts.manifest.scenarios ?? [];
768
- payload.scenarios = scenarios
769
- .filter((scenario) => isRecord(scenario))
770
- .map((scenario) => ({
771
- id: typeof scenario.id === "string" ? scenario.id : "",
772
- summary: typeof scenario.summary === "string" ? scenario.summary : "",
773
- }))
774
- .filter((scenario) => scenario.id);
775
- }
776
- if (payload.scenarios.length === 0)
777
- return;
778
- await atomicWriteFile(scenariosIndexPath, `${JSON.stringify(payload, null, 2)}\n`, "utf8");
779
- }
780
- function isHttpUrl(value) {
781
- return value.startsWith("http://") || value.startsWith("https://");
782
- }
783
- async function readRecipesIndexText(source, cwd) {
784
- if (isHttpUrl(source)) {
785
- return await fetchText(source);
786
- }
787
- return await readFile(path.resolve(cwd, source), "utf8");
788
- }
789
- async function readRecipesIndexSignature(source, cwd) {
790
- const sigSource = signatureSourceForIndex(source);
791
- if (isHttpUrl(sigSource)) {
792
- const raw = await fetchJson(sigSource);
793
- return validateRecipesIndexSignature(raw);
794
- }
795
- const rawText = await readFile(path.resolve(cwd, sigSource), "utf8");
796
- return validateRecipesIndexSignature(JSON.parse(rawText));
797
- }
798
- async function loadRecipesRemoteIndex(opts) {
799
- const cachePath = resolveRecipesIndexCachePath();
800
- const cacheSigPath = path.join(path.dirname(cachePath), RECIPES_REMOTE_INDEX_SIG_NAME);
801
- const cacheDir = path.dirname(cachePath);
802
- let rawIndex;
803
- if (opts.refresh || !(await fileExists(cachePath))) {
804
- const source = opts.source ?? DEFAULT_RECIPES_INDEX_URL;
805
- const indexText = await readRecipesIndexText(source, opts.cwd);
806
- const signature = await readRecipesIndexSignature(source, opts.cwd);
807
- verifyRecipesIndexSignature(indexText, signature);
808
- rawIndex = JSON.parse(indexText);
809
- await mkdir(cacheDir, { recursive: true });
810
- await atomicWriteFile(cachePath, indexText, "utf8");
811
- await atomicWriteFile(cacheSigPath, `${JSON.stringify(signature, null, 2)}\n`, "utf8");
812
- }
813
- else {
814
- const [indexText, sigText] = await Promise.all([
815
- readFile(cachePath, "utf8"),
816
- readFile(cacheSigPath, "utf8"),
817
- ]);
818
- const signature = validateRecipesIndexSignature(JSON.parse(sigText));
819
- verifyRecipesIndexSignature(indexText, signature);
820
- rawIndex = JSON.parse(indexText);
821
- }
822
- return validateRecipesIndex(rawIndex);
823
- }
824
- async function cmdRecipeList(opts) {
825
- try {
826
- const flags = parseRecipeListArgs(opts.args);
827
- const filePath = resolveInstalledRecipesPath();
828
- const installed = await readInstalledRecipesFile(filePath);
829
- let recipes = installed.recipes;
830
- if (flags.tag) {
831
- const needle = flags.tag.toLowerCase();
832
- recipes = recipes.filter((entry) => entry.tags.some((tag) => tag.toLowerCase() === needle));
833
- }
834
- if (recipes.length === 0) {
835
- if (flags.tag) {
836
- process.stdout.write(`${emptyStateMessage(`installed recipes for tag ${flags.tag}`)}\n`);
837
- return 0;
838
- }
839
- process.stdout.write(`${emptyStateMessage("installed recipes", "Use `agentplane recipes list-remote` or `agentplane recipes install <id>`.")}\n`);
840
- return 0;
841
- }
842
- if (flags.full) {
843
- const payload = {
844
- schema_version: 1,
845
- updated_at: installed.updated_at,
846
- recipes,
847
- };
848
- process.stdout.write(`${JSON.stringify(payload, null, 2)}\n`);
849
- return 0;
850
- }
851
- for (const entry of recipes) {
852
- process.stdout.write(`${entry.id}@${entry.version} - ${entry.manifest.summary || "No summary"}\n`);
853
- }
854
- return 0;
855
- }
856
- catch (err) {
857
- if (err instanceof CliError)
858
- throw err;
859
- throw mapCoreError(err, { command: "recipes list", root: opts.rootOverride ?? null });
860
- }
861
- }
862
- async function cmdRecipeListRemote(opts) {
863
- const flags = parseRecipeListRemoteFlags(opts.args);
864
- try {
865
- const project = await maybeResolveProject({ cwd: opts.cwd, rootOverride: opts.rootOverride });
866
- let config = defaultConfig();
867
- if (project) {
868
- const loaded = await loadConfig(project.agentplaneDir);
869
- config = loaded.config;
870
- }
871
- const source = flags.index ?? DEFAULT_RECIPES_INDEX_URL;
872
- const cachePath = resolveRecipesIndexCachePath();
873
- const willFetchRemote = (flags.refresh || !(await fileExists(cachePath))) && isHttpUrl(source);
874
- if (willFetchRemote) {
875
- await ensureNetworkApproved({
876
- config,
877
- yes: flags.yes,
878
- reason: "recipes list-remote fetches the remote recipes index",
879
- });
880
- }
881
- const index = await loadRecipesRemoteIndex({
882
- cwd: opts.cwd,
883
- source: flags.index,
884
- refresh: flags.refresh,
885
- });
886
- for (const recipe of index.recipes) {
887
- const latest = [...recipe.versions]
888
- .toSorted((a, b) => a.version.localeCompare(b.version))
889
- .at(-1);
890
- if (!latest)
891
- continue;
892
- process.stdout.write(`${recipe.id}@${latest.version} - ${recipe.summary}\n`);
893
- }
894
- return 0;
895
- }
896
- catch (err) {
897
- if (err instanceof CliError)
898
- throw err;
899
- throw mapCoreError(err, { command: "recipes list-remote", root: opts.rootOverride ?? null });
900
- }
901
- }
902
- async function cmdRecipeInfo(opts) {
903
- try {
904
- const installed = await readInstalledRecipesFile(resolveInstalledRecipesPath());
905
- const entry = installed.recipes.find((recipe) => recipe.id === opts.id);
906
- if (!entry) {
907
- throw new CliError({
908
- exitCode: 5,
909
- code: "E_IO",
910
- message: `Recipe not installed: ${opts.id}`,
911
- });
912
- }
913
- const manifest = entry.manifest;
914
- process.stdout.write(`Recipe: ${manifest.id}@${manifest.version}\n`);
915
- process.stdout.write(`Name: ${manifest.name}\n`);
916
- process.stdout.write(`Summary: ${manifest.summary}\n`);
917
- process.stdout.write(`Description: ${manifest.description}\n`);
918
- if (manifest.tags && manifest.tags.length > 0) {
919
- process.stdout.write(`Tags: ${manifest.tags.join(", ")}\n`);
920
- }
921
- const agents = manifest.agents ?? [];
922
- const tools = manifest.tools ?? [];
923
- const scenarios = manifest.scenarios ?? [];
924
- if (agents.length > 0) {
925
- process.stdout.write("Agents:\n");
926
- for (const agent of agents) {
927
- const label = agent?.id ?? "unknown";
928
- const summary = agent?.summary ? ` - ${agent.summary}` : "";
929
- process.stdout.write(` - ${label}${summary}\n`);
930
- }
931
- }
932
- if (tools.length > 0) {
933
- process.stdout.write("Tools:\n");
934
- for (const tool of tools) {
935
- const label = tool?.id ?? "unknown";
936
- const summary = tool?.summary ? ` - ${tool.summary}` : "";
937
- process.stdout.write(` - ${label}${summary}\n`);
938
- }
939
- }
940
- if (scenarios.length > 0) {
941
- process.stdout.write("Scenarios:\n");
942
- for (const scenario of scenarios) {
943
- const label = scenario?.id ?? "unknown";
944
- const summary = scenario?.summary ? ` - ${scenario.summary}` : "";
945
- process.stdout.write(` - ${label}${summary}\n`);
946
- }
947
- }
948
- return 0;
949
- }
950
- catch (err) {
951
- if (err instanceof CliError)
952
- throw err;
953
- throw mapCoreError(err, { command: "recipes info", root: opts.rootOverride ?? null });
954
- }
955
- }
956
- async function cmdRecipeExplain(opts) {
957
- try {
958
- const installed = await readInstalledRecipesFile(resolveInstalledRecipesPath());
959
- const entry = installed.recipes.find((recipe) => recipe.id === opts.id);
960
- if (!entry) {
961
- throw new CliError({
962
- exitCode: 5,
963
- code: "E_IO",
964
- message: `Recipe not installed: ${opts.id}`,
965
- });
966
- }
967
- const manifest = entry.manifest;
968
- const recipeDir = resolveInstalledRecipeDir(entry);
969
- const scenarioDetails = await collectRecipeScenarioDetails(recipeDir, manifest);
970
- process.stdout.write(`Recipe: ${manifest.id}@${manifest.version}\n`);
971
- process.stdout.write(`Name: ${manifest.name}\n`);
972
- process.stdout.write(`Summary: ${manifest.summary}\n`);
973
- process.stdout.write(`Description: ${manifest.description}\n`);
974
- if (manifest.tags && manifest.tags.length > 0) {
975
- process.stdout.write(`Tags: ${manifest.tags.join(", ")}\n`);
976
- }
977
- const agents = manifest.agents ?? [];
978
- const tools = manifest.tools ?? [];
979
- if (agents.length > 0) {
980
- process.stdout.write("Agents:\n");
981
- for (const agent of agents) {
982
- const label = agent?.id ?? "unknown";
983
- const summary = agent?.summary ? ` - ${agent.summary}` : "";
984
- process.stdout.write(` - ${label}${summary}\n`);
985
- }
986
- }
987
- if (tools.length > 0) {
988
- process.stdout.write("Tools:\n");
989
- for (const tool of tools) {
990
- const label = tool?.id ?? "unknown";
991
- const summary = tool?.summary ? ` - ${tool.summary}` : "";
992
- process.stdout.write(` - ${label}${summary}\n`);
993
- }
994
- }
995
- if (scenarioDetails.length > 0) {
996
- process.stdout.write("Scenarios:\n");
997
- for (const scenario of scenarioDetails) {
998
- const summary = scenario.summary ? ` - ${scenario.summary}` : "";
999
- process.stdout.write(` - ${scenario.id}${summary}\n`);
1000
- if (scenario.description) {
1001
- process.stdout.write(` Description: ${scenario.description}\n`);
1002
- }
1003
- if (scenario.goal) {
1004
- process.stdout.write(` Goal: ${scenario.goal}\n`);
1005
- }
1006
- if (scenario.inputs !== undefined) {
1007
- const payload = formatJsonBlock(scenario.inputs, " ");
1008
- if (payload)
1009
- process.stdout.write(` Inputs:\n${payload}\n`);
1010
- }
1011
- if (scenario.outputs !== undefined) {
1012
- const payload = formatJsonBlock(scenario.outputs, " ");
1013
- if (payload)
1014
- process.stdout.write(` Outputs:\n${payload}\n`);
1015
- }
1016
- if (scenario.steps && scenario.steps.length > 0) {
1017
- process.stdout.write(" Steps:\n");
1018
- let stepIndex = 1;
1019
- for (const step of scenario.steps) {
1020
- process.stdout.write(` ${stepIndex}. ${JSON.stringify(step)}\n`);
1021
- stepIndex += 1;
1022
- }
1023
- continue;
1024
- }
1025
- if (scenario.source !== "definition") {
1026
- process.stdout.write(" Details: Scenario definition not found in recipe.\n");
1027
- }
1028
- }
1029
- }
1030
- return 0;
1031
- }
1032
- catch (err) {
1033
- if (err instanceof CliError)
1034
- throw err;
1035
- throw mapCoreError(err, { command: "recipes explain", root: opts.rootOverride ?? null });
1036
- }
1037
- }
1038
- async function cmdRecipeInstall(opts) {
1039
- try {
1040
- const project = await maybeResolveProject({ cwd: opts.cwd, rootOverride: opts.rootOverride });
1041
- let config = defaultConfig();
1042
- if (project) {
1043
- const loaded = await loadConfig(project.agentplaneDir);
1044
- config = loaded.config;
1045
- }
1046
- let networkApproved = false;
1047
- const ensureApproved = async (reason) => {
1048
- if (networkApproved)
1049
- return;
1050
- await ensureNetworkApproved({ config, yes: opts.yes, reason });
1051
- networkApproved = true;
1052
- };
1053
- const tempRoot = await mkdtemp(path.join(os.tmpdir(), "agentplane-recipe-"));
1054
- try {
1055
- let sourcePath = "";
1056
- let sourceLabel = "";
1057
- let expectedSha = "";
1058
- let indexTags = [];
1059
- const resolveFromIndex = async (recipeId) => {
1060
- const indexSource = opts.index ?? DEFAULT_RECIPES_INDEX_URL;
1061
- const cachePath = resolveRecipesIndexCachePath();
1062
- const willFetchRemote = (opts.refresh || !(await fileExists(cachePath))) && isHttpUrl(indexSource);
1063
- if (willFetchRemote) {
1064
- await ensureApproved("recipes install fetches the remote recipes index");
1065
- }
1066
- const index = await loadRecipesRemoteIndex({
1067
- cwd: opts.cwd,
1068
- source: opts.index,
1069
- refresh: opts.refresh,
1070
- });
1071
- const entry = index.recipes.find((recipe) => recipe.id === recipeId);
1072
- if (!entry) {
1073
- throw new CliError({
1074
- exitCode: 5,
1075
- code: "E_IO",
1076
- message: `Recipe not found in remote index: ${recipeId}`,
1077
- });
1078
- }
1079
- const latest = [...entry.versions]
1080
- .toSorted((a, b) => a.version.localeCompare(b.version))
1081
- .at(-1);
1082
- if (!latest) {
1083
- throw new CliError({
1084
- exitCode: 3,
1085
- code: "E_VALIDATION",
1086
- message: `Recipe ${entry.id} has no versions in the remote index`,
1087
- });
1088
- }
1089
- expectedSha = latest.sha256;
1090
- sourceLabel = `${entry.id}@${latest.version}`;
1091
- indexTags = normalizeRecipeTags(latest.tags ?? []);
1092
- if (isHttpUrl(latest.url)) {
1093
- await ensureApproved("recipes install downloads a recipe archive");
1094
- const url = new URL(latest.url);
1095
- const filename = path.basename(url.pathname) || "recipe.tar.gz";
1096
- const target = path.join(tempRoot, filename);
1097
- await downloadToFile(latest.url, target);
1098
- return target;
1099
- }
1100
- const resolved = path.resolve(opts.cwd, latest.url);
1101
- if (!(await fileExists(resolved))) {
1102
- throw new CliError({
1103
- exitCode: 5,
1104
- code: "E_IO",
1105
- message: `Recipe archive not found: ${latest.url}`,
1106
- });
1107
- }
1108
- return resolved;
1109
- };
1110
- const resolveSourcePath = async (source) => {
1111
- if (source.type === "name")
1112
- return await resolveFromIndex(source.value);
1113
- if (source.type === "url") {
1114
- await ensureApproved("recipes install downloads a recipe archive");
1115
- const url = new URL(source.value);
1116
- const filename = path.basename(url.pathname) || "recipe.tar.gz";
1117
- const target = path.join(tempRoot, filename);
1118
- sourceLabel = source.value;
1119
- await downloadToFile(source.value, target);
1120
- return target;
1121
- }
1122
- if (source.type === "path") {
1123
- const candidate = await resolvePathFallback(source.value);
1124
- if (!(await fileExists(candidate))) {
1125
- throw new CliError({
1126
- exitCode: 5,
1127
- code: "E_IO",
1128
- message: `Recipe archive not found: ${source.value}`,
1129
- });
1130
- }
1131
- sourceLabel = candidate;
1132
- return candidate;
1133
- }
1134
- if (isHttpUrl(source.value)) {
1135
- return await resolveSourcePath({ type: "url", value: source.value });
1136
- }
1137
- const candidate = await resolvePathFallback(source.value);
1138
- if (await fileExists(candidate)) {
1139
- return await resolveSourcePath({ type: "path", value: source.value });
1140
- }
1141
- return await resolveSourcePath({ type: "name", value: source.value });
1142
- };
1143
- sourcePath = await resolveSourcePath(opts.source);
1144
- if (!sourceLabel)
1145
- sourceLabel = opts.source.value;
1146
- const actualSha = expectedSha ? await sha256File(sourcePath) : "";
1147
- if (expectedSha && actualSha !== expectedSha) {
1148
- throw new CliError({
1149
- exitCode: 3,
1150
- code: "E_VALIDATION",
1151
- message: `Recipe checksum mismatch for ${sourceLabel}`,
1152
- });
1153
- }
1154
- await extractArchive({
1155
- archivePath: sourcePath,
1156
- destDir: tempRoot,
1157
- usage: RECIPE_INSTALL_USAGE,
1158
- example: RECIPE_INSTALL_USAGE_EXAMPLE,
1159
- });
1160
- const recipeRoot = await resolveRecipeRoot(tempRoot);
1161
- const manifest = await readRecipeManifest(path.join(recipeRoot, "manifest.json"));
1162
- const resolvedTags = manifest.tags && manifest.tags.length > 0 ? manifest.tags : normalizeRecipeTags(indexTags);
1163
- const manifestWithTags = resolvedTags.length > 0 ? { ...manifest, tags: resolvedTags } : manifest;
1164
- const installDir = resolveInstalledRecipeDir(manifestWithTags);
1165
- const installKind = await getPathKind(installDir);
1166
- if (installKind && installKind !== "dir") {
1167
- throw new CliError({
1168
- exitCode: 5,
1169
- code: "E_IO",
1170
- message: `Recipe install path is not a directory: ${installDir}`,
1171
- });
1172
- }
1173
- const hadExisting = Boolean(installKind);
1174
- if (installKind) {
1175
- await rm(installDir, { recursive: true, force: true });
1176
- }
1177
- await mkdir(path.dirname(installDir), { recursive: true });
1178
- await mkdir(resolveGlobalRecipesDir(), { recursive: true });
1179
- try {
1180
- await rename(recipeRoot, installDir);
1181
- }
1182
- catch (err) {
1183
- const code = err?.code;
1184
- if (code === "EXDEV") {
1185
- await cp(recipeRoot, installDir, { recursive: true });
1186
- }
1187
- else {
1188
- throw err;
1189
- }
1190
- }
1191
- try {
1192
- if (project) {
1193
- await applyRecipeAgents({
1194
- manifest: manifestWithTags,
1195
- recipeDir: installDir,
1196
- agentplaneDir: project.agentplaneDir,
1197
- onConflict: opts.onConflict,
1198
- });
1199
- }
1200
- await applyRecipeScenarios({ manifest: manifestWithTags, recipeDir: installDir });
1201
- }
1202
- catch (err) {
1203
- if (!hadExisting) {
1204
- await rm(installDir, { recursive: true, force: true });
1205
- }
1206
- throw err;
1207
- }
1208
- const recipesPath = resolveInstalledRecipesPath();
1209
- const installed = await readInstalledRecipesFile(recipesPath);
1210
- const updated = installed.recipes.filter((entry) => entry.id !== manifestWithTags.id);
1211
- updated.push({
1212
- id: manifestWithTags.id,
1213
- version: manifestWithTags.version,
1214
- source: sourceLabel,
1215
- installed_at: new Date().toISOString(),
1216
- tags: resolvedTags,
1217
- manifest: manifestWithTags,
1218
- });
1219
- await writeInstalledRecipesFile(recipesPath, {
1220
- schema_version: 1,
1221
- updated_at: installed.updated_at,
1222
- recipes: updated,
1223
- });
1224
- process.stdout.write(`Installed recipe ${manifestWithTags.id}@${manifestWithTags.version}\n`);
1225
- return 0;
1226
- }
1227
- finally {
1228
- await rm(tempRoot, { recursive: true, force: true });
1229
- }
1230
- }
1231
- catch (err) {
1232
- if (err instanceof CliError)
1233
- throw err;
1234
- throw mapCoreError(err, { command: "recipes install", root: opts.rootOverride ?? null });
1235
- }
1236
- }
1237
- async function cmdRecipeRemove(opts) {
1238
- try {
1239
- const recipesPath = resolveInstalledRecipesPath();
1240
- const installed = await readInstalledRecipesFile(recipesPath);
1241
- const entry = installed.recipes.find((recipe) => recipe.id === opts.id);
1242
- if (!entry) {
1243
- throw new CliError({
1244
- exitCode: 5,
1245
- code: "E_IO",
1246
- message: `Recipe not installed: ${opts.id}`,
1247
- });
1248
- }
1249
- const recipeDir = resolveInstalledRecipeDir(entry);
1250
- await rm(recipeDir, { recursive: true, force: true });
1251
- const updated = installed.recipes.filter((recipe) => recipe.id !== opts.id);
1252
- await writeInstalledRecipesFile(recipesPath, {
1253
- schema_version: 1,
1254
- updated_at: installed.updated_at,
1255
- recipes: updated,
1256
- });
1257
- process.stdout.write(`${successMessage("removed recipe", `${entry.id}@${entry.version}`)}\n`);
1258
- return 0;
1259
- }
1260
- catch (err) {
1261
- if (err instanceof CliError)
1262
- throw err;
1263
- throw mapCoreError(err, { command: "recipes remove", root: opts.rootOverride ?? null });
1264
- }
1265
- }
1266
- async function listRecipeCacheEntries(cacheDir) {
1267
- const entries = [];
1268
- const recipeDirs = await readdir(cacheDir, { withFileTypes: true });
1269
- for (const recipeDir of recipeDirs) {
1270
- if (!recipeDir.isDirectory())
1271
- continue;
1272
- const recipeId = recipeDir.name;
1273
- const versionRoot = path.join(cacheDir, recipeId);
1274
- const versions = await readdir(versionRoot, { withFileTypes: true });
1275
- for (const versionDir of versions) {
1276
- if (!versionDir.isDirectory())
1277
- continue;
1278
- const version = versionDir.name;
1279
- entries.push({
1280
- id: recipeId,
1281
- version,
1282
- path: path.join(versionRoot, version),
1283
- });
1284
- }
1285
- }
1286
- return entries;
1287
- }
1288
- async function cmdRecipeCachePrune(opts) {
1289
- const flags = parseRecipeCachePruneArgs(opts.args);
1290
- try {
1291
- const cacheDir = resolveGlobalRecipesDir();
1292
- if (!(await fileExists(cacheDir))) {
1293
- process.stdout.write(`${infoMessage(`recipe cache directory not found: ${cacheDir}`)}\n`);
1294
- return 0;
1295
- }
1296
- const cacheEntries = await listRecipeCacheEntries(cacheDir);
1297
- if (cacheEntries.length === 0) {
1298
- process.stdout.write(`${infoMessage("recipe cache is empty")}\n`);
1299
- return 0;
1300
- }
1301
- if (flags.all) {
1302
- if (flags.dryRun) {
1303
- for (const entry of cacheEntries) {
1304
- process.stdout.write(`${infoMessage(`dry-run: would remove ${entry.id}@${entry.version}`)}\n`);
1305
- }
1306
- process.stdout.write(`${infoMessage(`dry-run: would remove ${cacheEntries.length} cached recipes`)}\n`);
1307
- return 0;
1308
- }
1309
- await rm(cacheDir, { recursive: true, force: true });
1310
- await writeInstalledRecipesFile(resolveInstalledRecipesPath(), {
1311
- schema_version: 1,
1312
- updated_at: "",
1313
- recipes: [],
1314
- });
1315
- process.stdout.write(`${successMessage("removed cached recipes", undefined, `count=${cacheEntries.length}`)}\n`);
1316
- return 0;
1317
- }
1318
- const installed = await readInstalledRecipesFile(resolveInstalledRecipesPath());
1319
- const keep = new Set(installed.recipes.map((entry) => `${entry.id}@${entry.version}`));
1320
- const prune = cacheEntries.filter((entry) => !keep.has(`${entry.id}@${entry.version}`));
1321
- if (prune.length === 0) {
1322
- process.stdout.write(`${infoMessage("recipe cache already clean (no uninstalled entries)")}\n`);
1323
- return 0;
1324
- }
1325
- if (flags.dryRun) {
1326
- for (const entry of prune) {
1327
- process.stdout.write(`${infoMessage(`dry-run: would remove ${entry.id}@${entry.version}`)}\n`);
1328
- }
1329
- process.stdout.write(`${infoMessage(`dry-run: would remove ${prune.length} cached recipes`)}\n`);
1330
- return 0;
1331
- }
1332
- const recipeDirs = new Set();
1333
- for (const entry of prune) {
1334
- recipeDirs.add(path.dirname(entry.path));
1335
- await rm(entry.path, { recursive: true, force: true });
1336
- }
1337
- for (const recipeDir of recipeDirs) {
1338
- const remaining = await readdir(recipeDir);
1339
- if (remaining.length === 0) {
1340
- await rm(recipeDir, { recursive: true, force: true });
1341
- }
1342
- }
1343
- process.stdout.write(`${successMessage("removed cached recipes", undefined, `count=${prune.length}`)}\n`);
1344
- return 0;
1345
- }
1346
- catch (err) {
1347
- if (err instanceof CliError)
1348
- throw err;
1349
- throw mapCoreError(err, { command: "recipes cache prune", root: opts.rootOverride ?? null });
1350
- }
1351
- }
1352
- export async function cmdRecipes(opts) {
1353
- const subcommand = opts.command;
1354
- if (!subcommand) {
1355
- throw new CliError({
1356
- exitCode: 2,
1357
- code: "E_USAGE",
1358
- message: usageMessage(RECIPE_USAGE, RECIPE_USAGE_EXAMPLE),
1359
- });
1360
- }
1361
- if (subcommand === "list") {
1362
- return await cmdRecipeList({
1363
- cwd: opts.cwd,
1364
- rootOverride: opts.rootOverride,
1365
- args: opts.args,
1366
- });
1367
- }
1368
- if (subcommand === "list-remote") {
1369
- return await cmdRecipeListRemote({
1370
- cwd: opts.cwd,
1371
- rootOverride: opts.rootOverride,
1372
- args: opts.args,
1373
- });
1374
- }
1375
- if (subcommand === "info") {
1376
- if (opts.args.length !== 1) {
1377
- throw new CliError({
1378
- exitCode: 2,
1379
- code: "E_USAGE",
1380
- message: usageMessage(RECIPE_INFO_USAGE, RECIPE_INFO_USAGE_EXAMPLE),
1381
- });
1382
- }
1383
- return await cmdRecipeInfo({
1384
- cwd: opts.cwd,
1385
- rootOverride: opts.rootOverride,
1386
- id: opts.args[0],
1387
- });
1388
- }
1389
- if (subcommand === "explain") {
1390
- if (opts.args.length !== 1) {
1391
- throw new CliError({
1392
- exitCode: 2,
1393
- code: "E_USAGE",
1394
- message: usageMessage(RECIPE_EXPLAIN_USAGE, RECIPE_EXPLAIN_USAGE_EXAMPLE),
1395
- });
1396
- }
1397
- return await cmdRecipeExplain({
1398
- cwd: opts.cwd,
1399
- rootOverride: opts.rootOverride,
1400
- id: opts.args[0],
1401
- });
1402
- }
1403
- if (subcommand === "install") {
1404
- const parsed = parseRecipeInstallArgs(opts.args);
1405
- return await cmdRecipeInstall({
1406
- cwd: opts.cwd,
1407
- rootOverride: opts.rootOverride,
1408
- source: parsed.source,
1409
- index: parsed.index,
1410
- refresh: parsed.refresh,
1411
- onConflict: parsed.onConflict,
1412
- yes: parsed.yes,
1413
- });
1414
- }
1415
- if (subcommand === "remove") {
1416
- if (opts.args.length !== 1) {
1417
- throw new CliError({
1418
- exitCode: 2,
1419
- code: "E_USAGE",
1420
- message: usageMessage(RECIPE_REMOVE_USAGE, RECIPE_REMOVE_USAGE_EXAMPLE),
1421
- });
1422
- }
1423
- return await cmdRecipeRemove({
1424
- cwd: opts.cwd,
1425
- rootOverride: opts.rootOverride,
1426
- id: opts.args[0],
1427
- });
1428
- }
1429
- if (subcommand === "cache") {
1430
- const cacheSub = opts.args[0];
1431
- const cacheArgs = opts.args.slice(1);
1432
- if (!cacheSub) {
1433
- throw new CliError({
1434
- exitCode: 2,
1435
- code: "E_USAGE",
1436
- message: usageMessage(RECIPE_CACHE_USAGE, RECIPE_CACHE_USAGE_EXAMPLE),
1437
- });
1438
- }
1439
- if (cacheSub === "prune") {
1440
- return await cmdRecipeCachePrune({
1441
- cwd: opts.cwd,
1442
- rootOverride: opts.rootOverride,
1443
- args: cacheArgs,
1444
- });
1445
- }
1446
- throw new CliError({
1447
- exitCode: 2,
1448
- code: "E_USAGE",
1449
- message: usageMessage(RECIPE_CACHE_USAGE, RECIPE_CACHE_USAGE_EXAMPLE),
1450
- });
1451
- }
1452
- throw new CliError({
1453
- exitCode: 2,
1454
- code: "E_USAGE",
1455
- message: usageMessage(RECIPE_USAGE, RECIPE_USAGE_EXAMPLE),
1456
- });
1457
- }
1
+ export { RECIPES_DIR_NAME, RECIPES_SCENARIOS_DIR_NAME, RECIPES_SCENARIOS_INDEX_NAME, } from "./recipes/impl/constants.js";
2
+ export { readRecipeManifest } from "./recipes/impl/manifest.js";
3
+ export { readInstalledRecipesFile } from "./recipes/impl/installed-recipes.js";
4
+ export { resolveInstalledRecipeDir, resolveInstalledRecipesPath, resolveProjectRecipesCacheDir, } from "./recipes/impl/paths.js";
5
+ export { normalizeScenarioToolStep, readScenarioDefinition, readScenarioIndex, } from "./recipes/impl/scenario.js";
6
+ export { cmdRecipeCachePruneParsed, cmdRecipeExplainParsed, cmdRecipeInfoParsed, cmdRecipeInstall, cmdRecipeListParsed, cmdRecipeListRemoteParsed, cmdRecipeRemoveParsed, } from "./recipes/impl/commands.js";