agentplane 0.3.13 → 0.3.14

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 (276) hide show
  1. package/assets/RUNNER.md +1 -1
  2. package/assets/agents/ORCHESTRATOR.json +1 -1
  3. package/assets/agents/SKILL_EXTRACTOR.json +31 -0
  4. package/assets/framework.manifest.json +7 -0
  5. package/assets/policy/incidents.md +5 -3
  6. package/assets/policy/workflow.branch_pr.md +10 -5
  7. package/dist/.build-manifest.json +278 -178
  8. package/dist/cli/output.d.ts +29 -0
  9. package/dist/cli/output.d.ts.map +1 -1
  10. package/dist/cli/output.js +33 -0
  11. package/dist/cli/run-cli/command-catalog/core.d.ts.map +1 -1
  12. package/dist/cli/run-cli/command-catalog/core.js +29 -87
  13. package/dist/cli/run-cli/command-catalog/lifecycle.d.ts.map +1 -1
  14. package/dist/cli/run-cli/command-catalog/lifecycle.js +4 -12
  15. package/dist/cli/run-cli/command-catalog/project.d.ts +1 -1
  16. package/dist/cli/run-cli/command-catalog/project.d.ts.map +1 -1
  17. package/dist/cli/run-cli/command-catalog/project.js +16 -38
  18. package/dist/cli/run-cli/command-catalog/shared.d.ts +9 -6
  19. package/dist/cli/run-cli/command-catalog/shared.d.ts.map +1 -1
  20. package/dist/cli/run-cli/command-catalog/shared.js +23 -6
  21. package/dist/cli/run-cli/command-catalog/task.d.ts.map +1 -1
  22. package/dist/cli/run-cli/command-catalog/task.js +6 -18
  23. package/dist/cli/run-cli/command-catalog.d.ts +1 -1
  24. package/dist/cli/run-cli/command-catalog.d.ts.map +1 -1
  25. package/dist/cli/run-cli/commands/init/recipes.d.ts.map +1 -1
  26. package/dist/cli/run-cli/commands/init/recipes.js +1 -0
  27. package/dist/cli/run-cli.js +1 -1
  28. package/dist/cli/run-cli.test-helpers.d.ts +1 -74
  29. package/dist/cli/run-cli.test-helpers.d.ts.map +1 -1
  30. package/dist/cli/run-cli.test-helpers.js +1 -769
  31. package/dist/commands/branch/cleanup-merged.d.ts.map +1 -1
  32. package/dist/commands/branch/cleanup-merged.js +5 -9
  33. package/dist/commands/branch/work-start.command.d.ts.map +1 -1
  34. package/dist/commands/branch/work-start.command.js +1 -0
  35. package/dist/commands/commit.spec.d.ts.map +1 -1
  36. package/dist/commands/commit.spec.js +2 -0
  37. package/dist/commands/doctor/branch-pr.d.ts +1 -1
  38. package/dist/commands/doctor/branch-pr.d.ts.map +1 -1
  39. package/dist/commands/doctor/branch-pr.js +5 -2
  40. package/dist/commands/guard/impl/commands.d.ts.map +1 -1
  41. package/dist/commands/guard/impl/commands.js +4 -1
  42. package/dist/commands/guard/impl/comment-commit.d.ts.map +1 -1
  43. package/dist/commands/guard/impl/comment-commit.js +2 -1
  44. package/dist/commands/guard/impl/env.d.ts +6 -0
  45. package/dist/commands/guard/impl/env.d.ts.map +1 -1
  46. package/dist/commands/guard/impl/env.js +41 -0
  47. package/dist/commands/pr/internal/auto-commit.d.ts.map +1 -1
  48. package/dist/commands/pr/internal/auto-commit.js +2 -1
  49. package/dist/commands/pr/internal/sync-branch.d.ts +36 -0
  50. package/dist/commands/pr/internal/sync-branch.d.ts.map +1 -0
  51. package/dist/commands/pr/internal/sync-branch.js +113 -0
  52. package/dist/commands/pr/internal/sync-github.d.ts +28 -0
  53. package/dist/commands/pr/internal/sync-github.d.ts.map +1 -0
  54. package/dist/commands/pr/internal/sync-github.js +178 -0
  55. package/dist/commands/pr/internal/sync-model.d.ts +36 -0
  56. package/dist/commands/pr/internal/sync-model.d.ts.map +1 -0
  57. package/dist/commands/pr/internal/sync-model.js +1 -0
  58. package/dist/commands/pr/internal/sync-open-step.d.ts +10 -0
  59. package/dist/commands/pr/internal/sync-open-step.d.ts.map +1 -0
  60. package/dist/commands/pr/internal/sync-open-step.js +128 -0
  61. package/dist/commands/pr/internal/sync-support.d.ts +7 -0
  62. package/dist/commands/pr/internal/sync-support.d.ts.map +1 -0
  63. package/dist/commands/pr/internal/sync-support.js +29 -0
  64. package/dist/commands/pr/internal/sync-update-step.d.ts +6 -0
  65. package/dist/commands/pr/internal/sync-update-step.d.ts.map +1 -0
  66. package/dist/commands/pr/internal/sync-update-step.js +68 -0
  67. package/dist/commands/pr/internal/sync.d.ts +2 -6
  68. package/dist/commands/pr/internal/sync.d.ts.map +1 -1
  69. package/dist/commands/pr/internal/sync.js +83 -529
  70. package/dist/commands/pr/open.d.ts.map +1 -1
  71. package/dist/commands/pr/open.js +25 -8
  72. package/dist/commands/pr/pr.command.d.ts.map +1 -1
  73. package/dist/commands/pr/pr.command.js +7 -2
  74. package/dist/commands/recipes/impl/apply.d.ts +1 -1
  75. package/dist/commands/recipes/impl/apply.d.ts.map +1 -1
  76. package/dist/commands/recipes/impl/apply.js +1 -2
  77. package/dist/commands/recipes/impl/commands/active.d.ts.map +1 -1
  78. package/dist/commands/recipes/impl/commands/active.js +6 -5
  79. package/dist/commands/recipes/impl/commands/add.d.ts +1 -0
  80. package/dist/commands/recipes/impl/commands/add.d.ts.map +1 -1
  81. package/dist/commands/recipes/impl/commands/add.js +32 -27
  82. package/dist/commands/recipes/impl/commands/detach.d.ts.map +1 -1
  83. package/dist/commands/recipes/impl/commands/detach.js +35 -21
  84. package/dist/commands/recipes/impl/commands/disable.d.ts.map +1 -1
  85. package/dist/commands/recipes/impl/commands/disable.js +5 -3
  86. package/dist/commands/recipes/impl/commands/enable.d.ts.map +1 -1
  87. package/dist/commands/recipes/impl/commands/enable.js +5 -3
  88. package/dist/commands/recipes/impl/commands/explain.d.ts.map +1 -1
  89. package/dist/commands/recipes/impl/commands/explain.js +57 -47
  90. package/dist/commands/recipes/impl/commands/info.d.ts.map +1 -1
  91. package/dist/commands/recipes/impl/commands/info.js +25 -21
  92. package/dist/commands/recipes/impl/commands/install.d.ts +1 -1
  93. package/dist/commands/recipes/impl/commands/install.d.ts.map +1 -1
  94. package/dist/commands/recipes/impl/commands/install.js +3 -13
  95. package/dist/commands/recipes/impl/commands/list-remote.d.ts.map +1 -1
  96. package/dist/commands/recipes/impl/commands/list-remote.js +2 -3
  97. package/dist/commands/recipes/impl/commands/list.d.ts.map +1 -1
  98. package/dist/commands/recipes/impl/commands/list.js +7 -6
  99. package/dist/commands/recipes/impl/commands/remove.d.ts.map +1 -1
  100. package/dist/commands/recipes/impl/commands/remove.js +12 -7
  101. package/dist/commands/recipes/impl/commands/update.d.ts.map +1 -1
  102. package/dist/commands/recipes/impl/commands/update.js +38 -24
  103. package/dist/commands/recipes/impl/index.d.ts +1 -1
  104. package/dist/commands/recipes/impl/index.d.ts.map +1 -1
  105. package/dist/commands/recipes/impl/installed-recipes.d.ts +1 -1
  106. package/dist/commands/recipes/impl/installed-recipes.d.ts.map +1 -1
  107. package/dist/commands/recipes/impl/installed-recipes.js +1 -2
  108. package/dist/commands/recipes/impl/mutation-transaction.d.ts +7 -0
  109. package/dist/commands/recipes/impl/mutation-transaction.d.ts.map +1 -0
  110. package/dist/commands/recipes/impl/mutation-transaction.js +47 -0
  111. package/dist/commands/recipes/impl/overlay-project.d.ts +19 -3
  112. package/dist/commands/recipes/impl/overlay-project.d.ts.map +1 -1
  113. package/dist/commands/recipes/impl/overlay-project.js +76 -38
  114. package/dist/commands/recipes/impl/paths.d.ts +0 -3
  115. package/dist/commands/recipes/impl/paths.d.ts.map +1 -1
  116. package/dist/commands/recipes/impl/paths.js +0 -3
  117. package/dist/commands/recipes/impl/project-installed-recipes.d.ts +4 -1
  118. package/dist/commands/recipes/impl/project-installed-recipes.d.ts.map +1 -1
  119. package/dist/commands/recipes/impl/project-installed-recipes.js +6 -4
  120. package/dist/commands/recipes/impl/project-recipe-state.d.ts +1 -1
  121. package/dist/commands/recipes/impl/project-recipe-state.d.ts.map +1 -1
  122. package/dist/commands/recipes/impl/project-registry.d.ts +5 -1
  123. package/dist/commands/recipes/impl/project-registry.d.ts.map +1 -1
  124. package/dist/commands/recipes/impl/project-registry.js +34 -14
  125. package/dist/commands/recipes/impl/resolver.d.ts +1 -1
  126. package/dist/commands/recipes/impl/resolver.d.ts.map +1 -1
  127. package/dist/commands/recipes/impl/resolver.js +1 -1
  128. package/dist/commands/recipes/impl/types.d.ts +1 -1
  129. package/dist/commands/recipes/impl/types.d.ts.map +1 -1
  130. package/dist/commands/recipes/impl/version.d.ts +5 -0
  131. package/dist/commands/recipes/impl/version.d.ts.map +1 -0
  132. package/dist/commands/recipes/impl/version.js +9 -0
  133. package/dist/commands/recipes.d.ts +5 -4
  134. package/dist/commands/recipes.d.ts.map +1 -1
  135. package/dist/commands/recipes.js +3 -3
  136. package/dist/commands/release/apply.command.d.ts +1 -1
  137. package/dist/commands/release/apply.command.d.ts.map +1 -1
  138. package/dist/commands/release/apply.command.js +15 -379
  139. package/dist/commands/release/apply.mutation.d.ts +1 -0
  140. package/dist/commands/release/apply.mutation.d.ts.map +1 -1
  141. package/dist/commands/release/apply.mutation.js +24 -1
  142. package/dist/commands/release/apply.pipeline.d.ts +22 -0
  143. package/dist/commands/release/apply.pipeline.d.ts.map +1 -0
  144. package/dist/commands/release/apply.pipeline.js +371 -0
  145. package/dist/commands/release/apply.preflight.d.ts +2 -0
  146. package/dist/commands/release/apply.preflight.d.ts.map +1 -1
  147. package/dist/commands/release/apply.preflight.js +13 -4
  148. package/dist/commands/release/apply.types.d.ts +27 -0
  149. package/dist/commands/release/apply.types.d.ts.map +1 -1
  150. package/dist/commands/release.test-helpers.d.ts +4 -0
  151. package/dist/commands/release.test-helpers.d.ts.map +1 -1
  152. package/dist/commands/release.test-helpers.js +7 -0
  153. package/dist/commands/shared/reconcile-check.d.ts.map +1 -1
  154. package/dist/commands/shared/reconcile-check.js +2 -2
  155. package/dist/commands/shared/task-backend.d.ts +6 -1
  156. package/dist/commands/shared/task-backend.d.ts.map +1 -1
  157. package/dist/commands/shared/task-backend.js +34 -2
  158. package/dist/commands/shared/task-mutation.d.ts.map +1 -1
  159. package/dist/commands/shared/task-mutation.js +4 -4
  160. package/dist/commands/shared/task-store/intents.d.ts +34 -0
  161. package/dist/commands/shared/task-store/intents.d.ts.map +1 -0
  162. package/dist/commands/shared/task-store/intents.js +265 -0
  163. package/dist/commands/shared/task-store/readme.d.ts +28 -0
  164. package/dist/commands/shared/task-store/readme.d.ts.map +1 -0
  165. package/dist/commands/shared/task-store/readme.js +125 -0
  166. package/dist/commands/shared/task-store/store.d.ts +26 -0
  167. package/dist/commands/shared/task-store/store.d.ts.map +1 -0
  168. package/dist/commands/shared/task-store/store.js +105 -0
  169. package/dist/commands/shared/task-store/types.d.ts +94 -0
  170. package/dist/commands/shared/task-store/types.d.ts.map +1 -0
  171. package/dist/commands/shared/task-store/types.js +1 -0
  172. package/dist/commands/shared/task-store.d.ts +3 -109
  173. package/dist/commands/shared/task-store.d.ts.map +1 -1
  174. package/dist/commands/shared/task-store.js +2 -493
  175. package/dist/commands/task/block.d.ts.map +1 -1
  176. package/dist/commands/task/block.js +7 -2
  177. package/dist/commands/task/comment.d.ts.map +1 -1
  178. package/dist/commands/task/comment.js +7 -2
  179. package/dist/commands/task/finish-shared.d.ts.map +1 -1
  180. package/dist/commands/task/finish-shared.js +3 -3
  181. package/dist/commands/task/finish.d.ts.map +1 -1
  182. package/dist/commands/task/finish.js +102 -15
  183. package/dist/commands/task/hosted-merge-sync.d.ts.map +1 -1
  184. package/dist/commands/task/hosted-merge-sync.js +9 -4
  185. package/dist/commands/task/list.run.d.ts.map +1 -1
  186. package/dist/commands/task/list.run.js +14 -4
  187. package/dist/commands/task/new.command.d.ts.map +1 -1
  188. package/dist/commands/task/new.command.js +16 -2
  189. package/dist/commands/task/new.js +2 -2
  190. package/dist/commands/task/show.d.ts.map +1 -1
  191. package/dist/commands/task/show.js +3 -3
  192. package/dist/commands/task/update.d.ts.map +1 -1
  193. package/dist/commands/task/update.js +11 -3
  194. package/dist/runner/adapters/codex.d.ts.map +1 -1
  195. package/dist/runner/adapters/codex.js +3 -33
  196. package/dist/runner/adapters/custom.d.ts.map +1 -1
  197. package/dist/runner/adapters/custom.js +3 -30
  198. package/dist/runner/adapters/runtime-shared.d.ts +14 -0
  199. package/dist/runner/adapters/runtime-shared.d.ts.map +1 -0
  200. package/dist/runner/adapters/runtime-shared.js +36 -0
  201. package/dist/runner/context/base-prompt-sources.d.ts +30 -0
  202. package/dist/runner/context/base-prompt-sources.d.ts.map +1 -0
  203. package/dist/runner/context/base-prompt-sources.js +144 -0
  204. package/dist/runner/context/base-prompts.d.ts +3 -22
  205. package/dist/runner/context/base-prompts.d.ts.map +1 -1
  206. package/dist/runner/context/base-prompts.js +6 -450
  207. package/dist/runner/context/overlay-prompt-blocks.d.ts +7 -0
  208. package/dist/runner/context/overlay-prompt-blocks.d.ts.map +1 -0
  209. package/dist/runner/context/overlay-prompt-blocks.js +72 -0
  210. package/dist/runner/context/prompt-block-shared.d.ts +54 -0
  211. package/dist/runner/context/prompt-block-shared.d.ts.map +1 -0
  212. package/dist/runner/context/prompt-block-shared.js +106 -0
  213. package/dist/runner/context/recipe-context.d.ts +2 -1
  214. package/dist/runner/context/recipe-context.d.ts.map +1 -1
  215. package/dist/runner/context/recipe-context.js +2 -1
  216. package/dist/runner/context/recipe-prompt-blocks.d.ts +6 -0
  217. package/dist/runner/context/recipe-prompt-blocks.d.ts.map +1 -0
  218. package/dist/runner/context/recipe-prompt-blocks.js +143 -0
  219. package/dist/runner/usecases/scenario-materialize-task.js +2 -2
  220. package/dist/runner/usecases/task-run-inspect.js +2 -2
  221. package/dist/runner/usecases/task-run-lifecycle-shared.js +2 -2
  222. package/dist/runner/usecases/task-run.d.ts.map +1 -1
  223. package/dist/runner/usecases/task-run.js +4 -2
  224. package/dist/runtime/capabilities/recipe.d.ts +1 -1
  225. package/dist/runtime/capabilities/recipe.d.ts.map +1 -1
  226. package/dist/runtime/execution-context.d.ts +63 -0
  227. package/dist/runtime/execution-context.d.ts.map +1 -0
  228. package/dist/{usecases/context/resolve-context.js → runtime/execution-context.js} +23 -26
  229. package/dist/runtime/incidents/advice-strategy.d.ts +15 -0
  230. package/dist/runtime/incidents/advice-strategy.d.ts.map +1 -0
  231. package/dist/runtime/incidents/advice-strategy.js +54 -0
  232. package/dist/runtime/incidents/plan-strategy.d.ts +9 -0
  233. package/dist/runtime/incidents/plan-strategy.d.ts.map +1 -0
  234. package/dist/runtime/incidents/plan-strategy.js +205 -0
  235. package/dist/runtime/incidents/registry-strategy.d.ts +6 -0
  236. package/dist/runtime/incidents/registry-strategy.d.ts.map +1 -0
  237. package/dist/runtime/incidents/registry-strategy.js +280 -0
  238. package/dist/runtime/incidents/resolve.d.ts +3 -25
  239. package/dist/runtime/incidents/resolve.d.ts.map +1 -1
  240. package/dist/runtime/incidents/resolve.js +3 -683
  241. package/dist/runtime/incidents/shared.d.ts +34 -0
  242. package/dist/runtime/incidents/shared.d.ts.map +1 -0
  243. package/dist/runtime/incidents/shared.js +171 -0
  244. package/dist/testing/cli-harness/recipe-archives.d.ts +28 -0
  245. package/dist/testing/cli-harness/recipe-archives.d.ts.map +1 -0
  246. package/dist/testing/cli-harness/recipe-archives.js +374 -0
  247. package/dist/testing/cli-harness/stdio.d.ts +26 -0
  248. package/dist/testing/cli-harness/stdio.d.ts.map +1 -0
  249. package/dist/testing/cli-harness/stdio.js +84 -0
  250. package/dist/testing/cli-harness.d.ts +25 -0
  251. package/dist/testing/cli-harness.d.ts.map +1 -0
  252. package/dist/testing/cli-harness.js +313 -0
  253. package/dist/testing/index.d.ts +2 -0
  254. package/dist/testing/index.d.ts.map +1 -0
  255. package/dist/testing/index.js +1 -0
  256. package/package.json +7 -4
  257. package/dist/commands/recipes/impl/manifest.d.ts +0 -4
  258. package/dist/commands/recipes/impl/manifest.d.ts.map +0 -1
  259. package/dist/commands/recipes/impl/manifest.js +0 -7
  260. package/dist/commands/recipes/impl/normalize.d.ts +0 -8
  261. package/dist/commands/recipes/impl/normalize.d.ts.map +0 -1
  262. package/dist/commands/recipes/impl/normalize.js +0 -54
  263. package/dist/commands/recipes/impl/scenario.d.ts +0 -16
  264. package/dist/commands/recipes/impl/scenario.d.ts.map +0 -1
  265. package/dist/commands/recipes/impl/scenario.js +0 -262
  266. package/dist/recipes/bundled-recipes.d.ts +0 -17
  267. package/dist/recipes/bundled-recipes.d.ts.map +0 -1
  268. package/dist/recipes/bundled-recipes.js +0 -15
  269. package/dist/usecases/context/resolve-context.d.ts +0 -68
  270. package/dist/usecases/context/resolve-context.d.ts.map +0 -1
  271. package/dist/usecases/task/task-list-usecase.d.ts +0 -9
  272. package/dist/usecases/task/task-list-usecase.d.ts.map +0 -1
  273. package/dist/usecases/task/task-list-usecase.js +0 -17
  274. package/dist/usecases/task/task-new-usecase.d.ts +0 -9
  275. package/dist/usecases/task/task-new-usecase.d.ts.map +0 -1
  276. package/dist/usecases/task/task-new-usecase.js +0 -17
@@ -1,6 +1,8 @@
1
1
  import path from "node:path";
2
+ import { collectRecipeScenarioDetails } from "@agentplaneorg/recipes";
2
3
  import { resolveProject } from "@agentplaneorg/core";
3
4
  import { mapCoreError } from "../../../../cli/error-map.js";
5
+ import { createCliEmitter } from "../../../../cli/output.js";
4
6
  import { exitCodeForError } from "../../../../cli/exit-codes.js";
5
7
  import { CliError } from "../../../../shared/errors.js";
6
8
  import { formatJsonBlock } from "../format.js";
@@ -8,7 +10,7 @@ import { readActiveRecipeIds } from "../overlay-project.js";
8
10
  import { readProjectInstalledRecipes } from "../project-installed-recipes.js";
9
11
  import { inspectProjectRecipe } from "../project-recipe-state.js";
10
12
  import { resolveProjectRecipesDir, resolveProjectInstalledRecipeDir } from "../paths.js";
11
- import { collectRecipeScenarioDetails } from "../scenario.js";
13
+ const output = createCliEmitter();
12
14
  export async function cmdRecipeExplainParsed(opts) {
13
15
  try {
14
16
  const resolved = await resolveProject({
@@ -33,145 +35,153 @@ export async function cmdRecipeExplainParsed(opts) {
33
35
  ? path.join(resolveProjectRecipesDir(resolved), entry.project_path)
34
36
  : resolveProjectInstalledRecipeDir(resolved, entry.id);
35
37
  const scenarioDetails = await collectRecipeScenarioDetails(recipeDir, manifest);
36
- process.stdout.write(`Recipe: ${manifest.id}@${manifest.version}\n`);
37
- process.stdout.write(`Kind: ${manifest.kind}\n`);
38
- process.stdout.write(`Schema: ${manifest.schema_version}\n`);
39
- process.stdout.write(`Active: ${activeIds.includes(entry.id) ? "yes" : "no"}\n`);
40
- process.stdout.write(`Materialization: ${entry.materialization}\n`);
41
- process.stdout.write(`State: ${inspection.state}\n`);
42
- process.stdout.write(`Source ref: ${entry.source_ref}\n`);
43
- process.stdout.write(`Cache source: ${inspection.cache_present ? "present" : "missing"}\n`);
44
- process.stdout.write(`Source sha256: ${entry.source_sha256}\n`);
45
- process.stdout.write(`Vendored sha256: ${inspection.current_vendored_sha256}\n`);
46
- process.stdout.write(`Name: ${manifest.name}\n`);
47
- process.stdout.write(`Summary: ${manifest.summary}\n`);
48
- process.stdout.write(`Description: ${manifest.description}\n`);
38
+ output.lines([
39
+ `Recipe: ${manifest.id}@${manifest.version}`,
40
+ `Kind: ${manifest.kind}`,
41
+ `Schema: ${manifest.schema_version}`,
42
+ `Active: ${activeIds.includes(entry.id) ? "yes" : "no"}`,
43
+ `Materialization: ${entry.materialization}`,
44
+ `State: ${inspection.state}`,
45
+ `Source ref: ${entry.source_ref}`,
46
+ `Cache source: ${inspection.cache_present ? "present" : "missing"}`,
47
+ `Source sha256: ${entry.source_sha256}`,
48
+ `Vendored sha256: ${inspection.current_vendored_sha256}`,
49
+ `Name: ${manifest.name}`,
50
+ `Summary: ${manifest.summary}`,
51
+ `Description: ${manifest.description}`,
52
+ ]);
49
53
  if (manifest.tags && manifest.tags.length > 0) {
50
- process.stdout.write(`Tags: ${manifest.tags.join(", ")}\n`);
54
+ output.line(`Tags: ${manifest.tags.join(", ")}`);
51
55
  }
52
56
  if (manifest.compatibility) {
53
57
  const payload = formatJsonBlock(manifest.compatibility, " ");
54
58
  if (payload)
55
- process.stdout.write(`Compatibility:\n${payload}\n`);
59
+ output.jsonSection("Compatibility", manifest.compatibility);
56
60
  }
57
61
  const skills = manifest.skills ?? [];
58
62
  const agents = manifest.agents ?? [];
59
63
  const tools = manifest.tools ?? [];
60
64
  if (skills.length > 0) {
61
- process.stdout.write("Skills:\n");
65
+ output.line("Skills:");
62
66
  for (const skill of skills) {
63
- process.stdout.write(` - ${skill.id} - ${skill.summary}\n`);
67
+ output.line(` - ${skill.id} - ${skill.summary}`);
64
68
  }
65
69
  }
66
70
  if (agents.length > 0) {
67
- process.stdout.write("Agents:\n");
71
+ output.line("Agents:");
68
72
  for (const agent of agents) {
69
- process.stdout.write(` - ${agent.display_name} (${agent.id}) - ${agent.summary} [role=${agent.role}]\n`);
73
+ output.line(` - ${agent.display_name} (${agent.id}) - ${agent.summary} [role=${agent.role}]`);
70
74
  }
71
75
  }
72
76
  if (tools.length > 0) {
73
- process.stdout.write("Tools:\n");
77
+ output.line("Tools:");
74
78
  for (const tool of tools) {
75
- process.stdout.write(` - ${tool.id} - ${tool.summary}\n`);
79
+ output.line(` - ${tool.id} - ${tool.summary}`);
76
80
  }
77
81
  }
78
82
  const prompts = manifest.prompts ?? [];
79
83
  const validators = manifest.validators ?? [];
80
84
  if (prompts.length > 0) {
81
- process.stdout.write("Overlay prompts:\n");
85
+ output.line("Overlay prompts:");
82
86
  for (const prompt of prompts) {
83
- process.stdout.write(` - ${prompt.id} [surface=${prompt.surface}, strength=${prompt.strength ?? "default"}, file=${prompt.file}]\n`);
87
+ output.line(` - ${prompt.id} [surface=${prompt.surface}, strength=${prompt.strength ?? "default"}, file=${prompt.file}]`);
84
88
  }
85
89
  }
86
90
  if (validators.length > 0) {
87
- process.stdout.write("Overlay validators:\n");
91
+ output.line("Overlay validators:");
88
92
  for (const validator of validators) {
89
- process.stdout.write(` - ${validator.id} [kind=${validator.kind}, phase=${validator.phase}]\n`);
93
+ output.line(` - ${validator.id} [kind=${validator.kind}, phase=${validator.phase}]`);
90
94
  }
91
95
  }
92
96
  if (manifest.templates && Object.keys(manifest.templates).length > 0) {
93
97
  const payload = formatJsonBlock(manifest.templates, " ");
94
98
  if (payload)
95
- process.stdout.write(`Templates:\n${payload}\n`);
99
+ output.jsonSection("Templates", manifest.templates);
96
100
  }
97
101
  if (scenarioDetails.length > 0) {
98
- process.stdout.write("Scenarios:\n");
102
+ output.line("Scenarios:");
99
103
  for (const scenario of scenarioDetails) {
100
104
  const title = scenario.name ? `${scenario.name} (${scenario.id})` : scenario.id;
101
105
  const summary = scenario.summary ? ` - ${scenario.summary}` : "";
102
- process.stdout.write(` - ${title}${summary}\n`);
106
+ output.line(` - ${title}${summary}`);
103
107
  if (scenario.description) {
104
- process.stdout.write(` Description: ${scenario.description}\n`);
108
+ output.line(` Description: ${scenario.description}`);
105
109
  }
106
110
  if (scenario.goal) {
107
- process.stdout.write(` Goal: ${scenario.goal}\n`);
111
+ output.line(` Goal: ${scenario.goal}`);
108
112
  }
109
113
  if (scenario.use_when && scenario.use_when.length > 0) {
110
114
  const payload = formatJsonBlock(scenario.use_when, " ");
111
115
  if (payload)
112
- process.stdout.write(` Use when:\n${payload}\n`);
116
+ output.jsonSection(" Use when", scenario.use_when, { indent: " " });
113
117
  }
114
118
  if (scenario.avoid_when && scenario.avoid_when.length > 0) {
115
119
  const payload = formatJsonBlock(scenario.avoid_when, " ");
116
120
  if (payload)
117
- process.stdout.write(` Avoid when:\n${payload}\n`);
121
+ output.jsonSection(" Avoid when", scenario.avoid_when, { indent: " " });
118
122
  }
119
123
  if (scenario.required_inputs && scenario.required_inputs.length > 0) {
120
124
  const payload = formatJsonBlock(scenario.required_inputs, " ");
121
- if (payload)
122
- process.stdout.write(` Required inputs:\n${payload}\n`);
125
+ if (payload) {
126
+ output.jsonSection(" Required inputs", scenario.required_inputs, {
127
+ indent: " ",
128
+ });
129
+ }
123
130
  }
124
131
  if (scenario.inputs !== undefined) {
125
132
  const payload = formatJsonBlock(scenario.inputs, " ");
126
133
  if (payload)
127
- process.stdout.write(` Inputs:\n${payload}\n`);
134
+ output.jsonSection(" Inputs", scenario.inputs, { indent: " " });
128
135
  }
129
136
  if (scenario.outputs !== undefined) {
130
137
  const payload = formatJsonBlock(scenario.outputs, " ");
131
138
  if (payload)
132
- process.stdout.write(` Outputs:\n${payload}\n`);
139
+ output.jsonSection(" Outputs", scenario.outputs, { indent: " " });
133
140
  }
134
141
  if (scenario.permissions && scenario.permissions.length > 0) {
135
142
  const payload = formatJsonBlock(scenario.permissions, " ");
136
143
  if (payload)
137
- process.stdout.write(` Permissions:\n${payload}\n`);
144
+ output.jsonSection(" Permissions", scenario.permissions, { indent: " " });
138
145
  }
139
146
  if (scenario.artifacts && scenario.artifacts.length > 0) {
140
147
  const payload = formatJsonBlock(scenario.artifacts, " ");
141
148
  if (payload)
142
- process.stdout.write(` Artifacts:\n${payload}\n`);
149
+ output.jsonSection(" Artifacts", scenario.artifacts, { indent: " " });
143
150
  }
144
151
  if (scenario.agents_involved && scenario.agents_involved.length > 0) {
145
152
  const payload = formatJsonBlock(scenario.agents_involved, " ");
146
- if (payload)
147
- process.stdout.write(` Agents involved:\n${payload}\n`);
153
+ if (payload) {
154
+ output.jsonSection(" Agents involved", scenario.agents_involved, {
155
+ indent: " ",
156
+ });
157
+ }
148
158
  }
149
159
  if (scenario.skills_used && scenario.skills_used.length > 0) {
150
160
  const payload = formatJsonBlock(scenario.skills_used, " ");
151
161
  if (payload)
152
- process.stdout.write(` Skills used:\n${payload}\n`);
162
+ output.jsonSection(" Skills used", scenario.skills_used, { indent: " " });
153
163
  }
154
164
  if (scenario.tools_used && scenario.tools_used.length > 0) {
155
165
  const payload = formatJsonBlock(scenario.tools_used, " ");
156
166
  if (payload)
157
- process.stdout.write(` Tools used:\n${payload}\n`);
167
+ output.jsonSection(" Tools used", scenario.tools_used, { indent: " " });
158
168
  }
159
169
  if (scenario.run_profile) {
160
170
  const payload = formatJsonBlock(scenario.run_profile, " ");
161
171
  if (payload)
162
- process.stdout.write(` Run profile:\n${payload}\n`);
172
+ output.jsonSection(" Run profile", scenario.run_profile, { indent: " " });
163
173
  }
164
174
  if (scenario.steps && scenario.steps.length > 0) {
165
- process.stdout.write(" Steps:\n");
175
+ output.line(" Steps:");
166
176
  let stepIndex = 1;
167
177
  for (const step of scenario.steps) {
168
- process.stdout.write(` ${stepIndex}. ${JSON.stringify(step)}\n`);
178
+ output.line(` ${stepIndex}. ${JSON.stringify(step)}`);
169
179
  stepIndex += 1;
170
180
  }
171
181
  continue;
172
182
  }
173
183
  if (scenario.source !== "definition") {
174
- process.stdout.write(" Details: Scenario definition not found in recipe.\n");
184
+ output.line(" Details: Scenario definition not found in recipe.");
175
185
  }
176
186
  }
177
187
  }
@@ -1 +1 @@
1
- {"version":3,"file":"info.d.ts","sourceRoot":"","sources":["../../../../../src/commands/recipes/impl/commands/info.ts"],"names":[],"mappings":"AAQA,wBAAsB,mBAAmB,CAAC,IAAI,EAAE;IAC9C,GAAG,EAAE,MAAM,CAAC;IACZ,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,EAAE,EAAE,MAAM,CAAC;CACZ,GAAG,OAAO,CAAC,MAAM,CAAC,CAmFlB"}
1
+ {"version":3,"file":"info.d.ts","sourceRoot":"","sources":["../../../../../src/commands/recipes/impl/commands/info.ts"],"names":[],"mappings":"AAWA,wBAAsB,mBAAmB,CAAC,IAAI,EAAE;IAC9C,GAAG,EAAE,MAAM,CAAC;IACZ,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,EAAE,EAAE,MAAM,CAAC;CACZ,GAAG,OAAO,CAAC,MAAM,CAAC,CAmFlB"}
@@ -1,9 +1,11 @@
1
1
  import { mapCoreError } from "../../../../cli/error-map.js";
2
+ import { createCliEmitter } from "../../../../cli/output.js";
2
3
  import { exitCodeForError } from "../../../../cli/exit-codes.js";
3
4
  import { CliError } from "../../../../shared/errors.js";
4
5
  import { formatJsonBlock } from "../format.js";
5
6
  import { readInstalledRecipesFile } from "../installed-recipes.js";
6
7
  import { resolveInstalledRecipesPath } from "../paths.js";
8
+ const output = createCliEmitter();
7
9
  export async function cmdRecipeInfoParsed(opts) {
8
10
  try {
9
11
  const installed = await readInstalledRecipesFile(resolveInstalledRecipesPath());
@@ -16,20 +18,22 @@ export async function cmdRecipeInfoParsed(opts) {
16
18
  });
17
19
  }
18
20
  const manifest = entry.manifest;
19
- process.stdout.write(`Recipe: ${manifest.id}@${manifest.version}\n`);
20
- process.stdout.write(`Kind: ${manifest.kind}\n`);
21
- process.stdout.write(`Schema: ${manifest.schema_version}\n`);
22
- process.stdout.write("Cached: yes\n");
23
- process.stdout.write(`Name: ${manifest.name}\n`);
24
- process.stdout.write(`Summary: ${manifest.summary}\n`);
25
- process.stdout.write(`Description: ${manifest.description}\n`);
21
+ output.lines([
22
+ `Recipe: ${manifest.id}@${manifest.version}`,
23
+ `Kind: ${manifest.kind}`,
24
+ `Schema: ${manifest.schema_version}`,
25
+ "Cached: yes",
26
+ `Name: ${manifest.name}`,
27
+ `Summary: ${manifest.summary}`,
28
+ `Description: ${manifest.description}`,
29
+ ]);
26
30
  if (manifest.tags && manifest.tags.length > 0) {
27
- process.stdout.write(`Tags: ${manifest.tags.join(", ")}\n`);
31
+ output.line(`Tags: ${manifest.tags.join(", ")}`);
28
32
  }
29
33
  if (manifest.compatibility) {
30
34
  const payload = formatJsonBlock(manifest.compatibility, " ");
31
35
  if (payload)
32
- process.stdout.write(`Compatibility:\n${payload}\n`);
36
+ output.jsonSection("Compatibility", manifest.compatibility);
33
37
  }
34
38
  const skills = manifest.skills ?? [];
35
39
  const agents = manifest.agents ?? [];
@@ -38,40 +42,40 @@ export async function cmdRecipeInfoParsed(opts) {
38
42
  const prompts = manifest.prompts ?? [];
39
43
  const validators = manifest.validators ?? [];
40
44
  if (skills.length > 0) {
41
- process.stdout.write("Skills:\n");
45
+ output.line("Skills:");
42
46
  for (const skill of skills) {
43
- process.stdout.write(` - ${skill.id} - ${skill.summary}\n`);
47
+ output.line(` - ${skill.id} - ${skill.summary}`);
44
48
  }
45
49
  }
46
50
  if (agents.length > 0) {
47
- process.stdout.write("Agents:\n");
51
+ output.line("Agents:");
48
52
  for (const agent of agents) {
49
53
  const label = `${agent.display_name} (${agent.id})`;
50
- process.stdout.write(` - ${label} - ${agent.summary}\n`);
54
+ output.line(` - ${label} - ${agent.summary}`);
51
55
  }
52
56
  }
53
57
  if (tools.length > 0) {
54
- process.stdout.write("Tools:\n");
58
+ output.line("Tools:");
55
59
  for (const tool of tools) {
56
- process.stdout.write(` - ${tool.id} - ${tool.summary}\n`);
60
+ output.line(` - ${tool.id} - ${tool.summary}`);
57
61
  }
58
62
  }
59
63
  if (prompts.length > 0) {
60
- process.stdout.write("Prompts:\n");
64
+ output.line("Prompts:");
61
65
  for (const prompt of prompts) {
62
- process.stdout.write(` - ${prompt.id} [surface=${prompt.surface}, strength=${prompt.strength ?? "default"}]\n`);
66
+ output.line(` - ${prompt.id} [surface=${prompt.surface}, strength=${prompt.strength ?? "default"}]`);
63
67
  }
64
68
  }
65
69
  if (validators.length > 0) {
66
- process.stdout.write("Validators:\n");
70
+ output.line("Validators:");
67
71
  for (const validator of validators) {
68
- process.stdout.write(` - ${validator.id} [kind=${validator.kind}, phase=${validator.phase}]\n`);
72
+ output.line(` - ${validator.id} [kind=${validator.kind}, phase=${validator.phase}]`);
69
73
  }
70
74
  }
71
75
  if (scenarios.length > 0) {
72
- process.stdout.write("Scenarios:\n");
76
+ output.line("Scenarios:");
73
77
  for (const scenario of scenarios) {
74
- process.stdout.write(` - ${scenario.name} (${scenario.id}) - ${scenario.summary} [mode=${scenario.run_profile.mode}]\n`);
78
+ output.line(` - ${scenario.name} (${scenario.id}) - ${scenario.summary} [mode=${scenario.run_profile.mode}]`);
75
79
  }
76
80
  }
77
81
  return 0;
@@ -1,4 +1,4 @@
1
- import type { RecipeConflictMode, RecipeInstallSource } from "../types.js";
1
+ import { type RecipeConflictMode, type RecipeInstallSource } from "@agentplaneorg/recipes";
2
2
  export declare function cmdRecipeInstall(opts: {
3
3
  cwd: string;
4
4
  rootOverride?: string;
@@ -1 +1 @@
1
- {"version":3,"file":"install.d.ts","sourceRoot":"","sources":["../../../../../src/commands/recipes/impl/commands/install.ts"],"names":[],"mappings":"AAiCA,OAAO,KAAK,EAAE,kBAAkB,EAAE,mBAAmB,EAAE,MAAM,aAAa,CAAC;AAM3E,wBAAsB,gBAAgB,CAAC,IAAI,EAAE;IAC3C,GAAG,EAAE,MAAM,CAAC;IACZ,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,MAAM,EAAE,mBAAmB,CAAC;IAC5B,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,OAAO,EAAE,OAAO,CAAC;IACjB,UAAU,EAAE,kBAAkB,CAAC;IAC/B,GAAG,EAAE,OAAO,CAAC;CACd,GAAG,OAAO,CAAC,MAAM,CAAC,CAgOlB"}
1
+ {"version":3,"file":"install.d.ts","sourceRoot":"","sources":["../../../../../src/commands/recipes/impl/commands/install.ts"],"names":[],"mappings":"AAIA,OAAO,EAGL,KAAK,kBAAkB,EACvB,KAAK,mBAAmB,EACzB,MAAM,wBAAwB,CAAC;AA8BhC,wBAAsB,gBAAgB,CAAC,IAAI,EAAE;IAC3C,GAAG,EAAE,MAAM,CAAC;IACZ,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,MAAM,EAAE,mBAAmB,CAAC;IAC5B,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,OAAO,EAAE,OAAO,CAAC;IACjB,UAAU,EAAE,kBAAkB,CAAC;IAC/B,GAAG,EAAE,OAAO,CAAC;CACd,GAAG,OAAO,CAAC,MAAM,CAAC,CAuNlB"}
@@ -1,6 +1,7 @@
1
1
  import { cp, mkdir, mkdtemp, rm } from "node:fs/promises";
2
2
  import os from "node:os";
3
3
  import path from "node:path";
4
+ import { normalizeRecipeTags, readRecipeManifest, } from "@agentplaneorg/recipes";
4
5
  import { defaultConfig, loadConfig, resolveProject } from "@agentplaneorg/core";
5
6
  import { extractArchive } from "../../../../cli/archive.js";
6
7
  import { sha256File } from "../../../../cli/checksum.js";
@@ -8,7 +9,6 @@ import { mapCoreError } from "../../../../cli/error-map.js";
8
9
  import { exitCodeForError } from "../../../../cli/exit-codes.js";
9
10
  import { fileExists, getPathKind } from "../../../../cli/fs-utils.js";
10
11
  import { downloadToFile } from "../../../../cli/http.js";
11
- import { getBundledRecipeEntry, resolveBundledRecipeSourcePath, } from "../../../../recipes/bundled-recipes.js";
12
12
  import { CliError } from "../../../../shared/errors.js";
13
13
  import { ensureNetworkApproved } from "../../../shared/network-approval.js";
14
14
  import { resolvePathFallback } from "../../../shared/path.js";
@@ -17,9 +17,8 @@ import { resolveRecipeRoot } from "../archive.js";
17
17
  import { DEFAULT_RECIPES_INDEX_URL } from "../constants.js";
18
18
  import { loadRecipesRemoteIndex, willFetchRemoteRecipesIndex } from "../index.js";
19
19
  import { readInstalledRecipesFile, writeInstalledRecipesFile } from "../installed-recipes.js";
20
- import { readRecipeManifest } from "../manifest.js";
21
- import { normalizeRecipeTags } from "../normalize.js";
22
20
  import { resolveGlobalRecipesDir, resolveInstalledRecipeDir, resolveInstalledRecipesPath, resolveRecipesIndexCachePath, } from "../paths.js";
21
+ import { pickLatestRecipeVersion } from "../version.js";
23
22
  function isHttpUrl(value) {
24
23
  return value.startsWith("http://") || value.startsWith("https://");
25
24
  }
@@ -74,9 +73,7 @@ export async function cmdRecipeInstall(opts) {
74
73
  message: `Recipe not found in remote index: ${recipeId}`,
75
74
  });
76
75
  }
77
- const latest = [...entry.versions]
78
- .toSorted((a, b) => a.version.localeCompare(b.version))
79
- .at(-1);
76
+ const latest = pickLatestRecipeVersion(entry.versions);
80
77
  if (!latest) {
81
78
  throw new CliError({
82
79
  exitCode: 3,
@@ -107,13 +104,6 @@ export async function cmdRecipeInstall(opts) {
107
104
  };
108
105
  const resolveSourcePath = async (source) => {
109
106
  if (source.type === "name") {
110
- const bundledPath = resolveBundledRecipeSourcePath(source.value);
111
- if (bundledPath && (await fileExists(path.join(bundledPath, "manifest.json")))) {
112
- const bundledEntry = getBundledRecipeEntry(source.value);
113
- const bundledVersion = bundledEntry?.versions.at(-1)?.version ?? "unknown";
114
- sourceLabel = `bundled:${source.value}@${bundledVersion}`;
115
- return { kind: "directory", path: bundledPath };
116
- }
117
107
  return await resolveFromIndex(source.value);
118
108
  }
119
109
  if (source.type === "url") {
@@ -1 +1 @@
1
- {"version":3,"file":"list-remote.d.ts","sourceRoot":"","sources":["../../../../../src/commands/recipes/impl/commands/list-remote.ts"],"names":[],"mappings":"AAWA,OAAO,KAAK,EAAE,qBAAqB,EAAE,MAAM,aAAa,CAAC;AAEzD,wBAAsB,yBAAyB,CAAC,IAAI,EAAE;IACpD,GAAG,EAAE,MAAM,CAAC;IACZ,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,KAAK,EAAE,qBAAqB,CAAC;CAC9B,GAAG,OAAO,CAAC,MAAM,CAAC,CAyClB"}
1
+ {"version":3,"file":"list-remote.d.ts","sourceRoot":"","sources":["../../../../../src/commands/recipes/impl/commands/list-remote.ts"],"names":[],"mappings":"AAWA,OAAO,KAAK,EAAE,qBAAqB,EAAE,MAAM,aAAa,CAAC;AAGzD,wBAAsB,yBAAyB,CAAC,IAAI,EAAE;IACpD,GAAG,EAAE,MAAM,CAAC;IACZ,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,KAAK,EAAE,qBAAqB,CAAC;CAC9B,GAAG,OAAO,CAAC,MAAM,CAAC,CAuClB"}
@@ -7,6 +7,7 @@ import { DEFAULT_RECIPES_INDEX_URL } from "../constants.js";
7
7
  import { loadRecipesRemoteIndex, willFetchRemoteRecipesIndex } from "../index.js";
8
8
  import { maybeResolveProject } from "../project.js";
9
9
  import { resolveRecipesIndexCachePath } from "../paths.js";
10
+ import { pickLatestRecipeVersion } from "../version.js";
10
11
  export async function cmdRecipeListRemoteParsed(opts) {
11
12
  const flags = opts.flags;
12
13
  try {
@@ -37,9 +38,7 @@ export async function cmdRecipeListRemoteParsed(opts) {
37
38
  refresh: flags.refresh,
38
39
  });
39
40
  for (const recipe of index.recipes) {
40
- const latest = [...recipe.versions]
41
- .toSorted((a, b) => a.version.localeCompare(b.version))
42
- .at(-1);
41
+ const latest = pickLatestRecipeVersion(recipe.versions);
43
42
  if (!latest)
44
43
  continue;
45
44
  process.stdout.write(`${recipe.id}@${latest.version} - ${recipe.summary}\n`);
@@ -1 +1 @@
1
- {"version":3,"file":"list.d.ts","sourceRoot":"","sources":["../../../../../src/commands/recipes/impl/commands/list.ts"],"names":[],"mappings":"AAMA,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,aAAa,CAAC;AAEnD,wBAAsB,mBAAmB,CAAC,IAAI,EAAE;IAC9C,GAAG,EAAE,MAAM,CAAC;IACZ,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,KAAK,EAAE,eAAe,CAAC;CACxB,GAAG,OAAO,CAAC,MAAM,CAAC,CAkDlB"}
1
+ {"version":3,"file":"list.d.ts","sourceRoot":"","sources":["../../../../../src/commands/recipes/impl/commands/list.ts"],"names":[],"mappings":"AAMA,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,aAAa,CAAC;AAInD,wBAAsB,mBAAmB,CAAC,IAAI,EAAE;IAC9C,GAAG,EAAE,MAAM,CAAC;IACZ,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,KAAK,EAAE,eAAe,CAAC;CACxB,GAAG,OAAO,CAAC,MAAM,CAAC,CA4ClB"}
@@ -1,8 +1,9 @@
1
1
  import { mapCoreError } from "../../../../cli/error-map.js";
2
- import { emptyStateMessage } from "../../../../cli/output.js";
2
+ import { createCliEmitter, emptyStateMessage } from "../../../../cli/output.js";
3
3
  import { CliError } from "../../../../shared/errors.js";
4
4
  import { readInstalledRecipesFile } from "../installed-recipes.js";
5
5
  import { resolveInstalledRecipesPath } from "../paths.js";
6
+ const output = createCliEmitter();
6
7
  export async function cmdRecipeListParsed(opts) {
7
8
  const flags = opts.flags;
8
9
  try {
@@ -14,22 +15,22 @@ export async function cmdRecipeListParsed(opts) {
14
15
  }
15
16
  if (recipes.length === 0) {
16
17
  if (flags.tag) {
17
- process.stdout.write(`${emptyStateMessage(`cached recipes for tag ${flags.tag}`)}\n`);
18
+ output.line(emptyStateMessage(`cached recipes for tag ${flags.tag}`));
18
19
  return 0;
19
20
  }
20
- process.stdout.write(`${emptyStateMessage("cached recipes", "Use `agentplane recipes list-remote` or `agentplane recipes install <id>`.")}\n`);
21
+ output.line(emptyStateMessage("cached recipes", "Use `agentplane recipes list-remote` or `agentplane recipes install <id>`."));
21
22
  return 0;
22
23
  }
23
24
  if (flags.full) {
24
- process.stdout.write(`${JSON.stringify({
25
+ output.json({
25
26
  schema_version: 1,
26
27
  updated_at: installed.updated_at,
27
28
  recipes,
28
- }, null, 2)}\n`);
29
+ });
29
30
  return 0;
30
31
  }
31
32
  for (const entry of recipes) {
32
- process.stdout.write(`${entry.id}@${entry.version} [${entry.manifest.kind}] - ${entry.manifest.summary || "No summary"}\n`);
33
+ output.line(`${entry.id}@${entry.version} [${entry.manifest.kind}] - ${entry.manifest.summary || "No summary"}`);
33
34
  }
34
35
  return 0;
35
36
  }
@@ -1 +1 @@
1
- {"version":3,"file":"remove.d.ts","sourceRoot":"","sources":["../../../../../src/commands/recipes/impl/commands/remove.ts"],"names":[],"mappings":"AAeA,wBAAsB,qBAAqB,CAAC,IAAI,EAAE;IAChD,GAAG,EAAE,MAAM,CAAC;IACZ,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,EAAE,EAAE,MAAM,CAAC;CACZ,GAAG,OAAO,CAAC,MAAM,CAAC,CAkClB"}
1
+ {"version":3,"file":"remove.d.ts","sourceRoot":"","sources":["../../../../../src/commands/recipes/impl/commands/remove.ts"],"names":[],"mappings":"AAiBA,wBAAsB,qBAAqB,CAAC,IAAI,EAAE;IAChD,GAAG,EAAE,MAAM,CAAC;IACZ,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,EAAE,EAAE,MAAM,CAAC;CACZ,GAAG,OAAO,CAAC,MAAM,CAAC,CAuClB"}
@@ -1,13 +1,13 @@
1
1
  import { loadConfig, resolveProject } from "@agentplaneorg/core";
2
- import { rm } from "node:fs/promises";
3
2
  import { mapCoreError } from "../../../../cli/error-map.js";
4
3
  import { exitCodeForError } from "../../../../cli/exit-codes.js";
5
4
  import { successMessage } from "../../../../cli/output.js";
6
5
  import { CliError } from "../../../../shared/errors.js";
7
6
  import { ensureActionApproved } from "../../../shared/approval-requirements.js";
8
- import { refreshProjectOverlayArtifacts, setRecipeActive } from "../overlay-project.js";
7
+ import { runVendoredRecipeMutation } from "../mutation-transaction.js";
8
+ import { publishProjectRecipesState } from "../overlay-project.js";
9
9
  import { readProjectInstalledRecipes } from "../project-installed-recipes.js";
10
- import { removeProjectRecipeRegistryEntry } from "../project-registry.js";
10
+ import { readProjectRecipesRegistry, removeProjectRecipeRegistryEntryFromFile, } from "../project-registry.js";
11
11
  import { resolveProjectInstalledRecipeDir } from "../paths.js";
12
12
  export async function cmdRecipeRemoveParsed(opts) {
13
13
  try {
@@ -17,6 +17,7 @@ export async function cmdRecipeRemoveParsed(opts) {
17
17
  });
18
18
  const loaded = await loadConfig(resolved.agentplaneDir);
19
19
  const installed = await readProjectInstalledRecipes(resolved);
20
+ const registry = await readProjectRecipesRegistry(resolved);
20
21
  const entry = installed.recipes.find((recipe) => recipe.id === opts.id);
21
22
  if (!entry) {
22
23
  throw new CliError({
@@ -32,10 +33,14 @@ export async function cmdRecipeRemoveParsed(opts) {
32
33
  yes: false,
33
34
  reason: `recipes remove ${entry.id}@${entry.version}`,
34
35
  });
35
- await rm(recipeDir, { recursive: true, force: true });
36
- await setRecipeActive({ project: resolved, recipeId: entry.id, active: false });
37
- await removeProjectRecipeRegistryEntry({ project: resolved, recipeId: entry.id });
38
- await refreshProjectOverlayArtifacts(resolved);
36
+ await runVendoredRecipeMutation({
37
+ targetDir: recipeDir,
38
+ mode: "remove",
39
+ commit: async () => {
40
+ const nextRegistry = removeProjectRecipeRegistryEntryFromFile(registry, entry.id);
41
+ await publishProjectRecipesState({ project: resolved, registry: nextRegistry });
42
+ },
43
+ });
39
44
  process.stdout.write(`${successMessage("removed recipe", `${entry.id}@${entry.version}`)}\n`);
40
45
  return 0;
41
46
  }
@@ -1 +1 @@
1
- {"version":3,"file":"update.d.ts","sourceRoot":"","sources":["../../../../../src/commands/recipes/impl/commands/update.ts"],"names":[],"mappings":"AAwBA,wBAAsB,qBAAqB,CAAC,IAAI,EAAE;IAChD,GAAG,EAAE,MAAM,CAAC;IACZ,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,EAAE,EAAE,MAAM,CAAC;IACX,KAAK,EAAE,OAAO,CAAC;CAChB,GAAG,OAAO,CAAC,MAAM,CAAC,CAuFlB"}
1
+ {"version":3,"file":"update.d.ts","sourceRoot":"","sources":["../../../../../src/commands/recipes/impl/commands/update.ts"],"names":[],"mappings":"AA4BA,wBAAsB,qBAAqB,CAAC,IAAI,EAAE;IAChD,GAAG,EAAE,MAAM,CAAC;IACZ,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,EAAE,EAAE,MAAM,CAAC;IACX,KAAK,EAAE,OAAO,CAAC;CAChB,GAAG,OAAO,CAAC,MAAM,CAAC,CAkGlB"}
@@ -1,14 +1,15 @@
1
- import { cp, rm, symlink } from "node:fs/promises";
1
+ import { cp, symlink } from "node:fs/promises";
2
+ import { normalizeRecipeTags } from "@agentplaneorg/recipes";
2
3
  import { loadConfig, resolveProject } from "@agentplaneorg/core";
3
4
  import { mapCoreError } from "../../../../cli/error-map.js";
4
5
  import { exitCodeForError } from "../../../../cli/exit-codes.js";
5
6
  import { CliError } from "../../../../shared/errors.js";
6
7
  import { ensureActionApproved } from "../../../shared/approval-requirements.js";
7
8
  import { readInstalledRecipesFile } from "../installed-recipes.js";
8
- import { normalizeRecipeTags } from "../normalize.js";
9
- import { readActiveRecipeIds, refreshProjectOverlayArtifacts } from "../overlay-project.js";
9
+ import { runVendoredRecipeMutation } from "../mutation-transaction.js";
10
+ import { publishProjectRecipesState } from "../overlay-project.js";
10
11
  import { hashRecipeTree, inspectProjectRecipe } from "../project-recipe-state.js";
11
- import { upsertProjectRecipeRegistryEntry } from "../project-registry.js";
12
+ import { readProjectRecipesRegistry, replaceProjectRecipeRegistryEntry, } from "../project-registry.js";
12
13
  import { resolveInstalledRecipesPath, resolveProjectVendoredRecipeDir } from "../paths.js";
13
14
  function buildModifiedRecipeError(id) {
14
15
  return new CliError({
@@ -35,6 +36,14 @@ export async function cmdRecipeUpdateParsed(opts) {
35
36
  if (inspection.state === "modified" && !opts.force) {
36
37
  throw buildModifiedRecipeError(inspection.entry.id);
37
38
  }
39
+ const currentSourceSha256 = inspection.current_source_sha256;
40
+ if (!currentSourceSha256) {
41
+ throw new CliError({
42
+ exitCode: exitCodeForError("E_IO"),
43
+ code: "E_IO",
44
+ message: `Cached source hash is missing for ${inspection.entry.id}@${inspection.entry.version}`,
45
+ });
46
+ }
38
47
  const cache = await readInstalledRecipesFile(resolveInstalledRecipesPath());
39
48
  const cached = cache.recipes.find((entry) => entry.id === inspection.entry.id && entry.version === inspection.entry.version);
40
49
  if (!cached) {
@@ -44,7 +53,7 @@ export async function cmdRecipeUpdateParsed(opts) {
44
53
  message: `Recipe not found in global cache: ${inspection.entry.id}@${inspection.entry.version}`,
45
54
  });
46
55
  }
47
- const activeIds = await readActiveRecipeIds(project);
56
+ const registry = await readProjectRecipesRegistry(project);
48
57
  if (inspection.entry.materialization === "copy" &&
49
58
  inspection.state === "clean" &&
50
59
  inspection.current_source_sha256 === inspection.entry.source_sha256) {
@@ -58,27 +67,32 @@ export async function cmdRecipeUpdateParsed(opts) {
58
67
  reason: `recipes update ${inspection.entry.id}@${inspection.entry.version}`,
59
68
  });
60
69
  const targetDir = resolveProjectVendoredRecipeDir(project, inspection.entry.id);
61
- await rm(targetDir, { recursive: true, force: true });
62
- await (inspection.entry.materialization === "link"
63
- ? symlink(inspection.source_dir, targetDir, "dir")
64
- : cp(inspection.source_dir, targetDir, { recursive: true }));
65
- const vendoredSha256 = await hashRecipeTree(targetDir);
66
- await upsertProjectRecipeRegistryEntry({
67
- project,
68
- entry: {
69
- id: inspection.entry.id,
70
- version: inspection.entry.version,
71
- path: inspection.entry.project_path,
72
- active: activeIds.includes(inspection.entry.id),
73
- materialization: inspection.entry.materialization,
74
- source_ref: inspection.entry.source_ref,
75
- source_sha256: inspection.current_source_sha256,
76
- vendored_sha256: vendoredSha256,
77
- installed_at: inspection.entry.installed_at,
78
- tags: normalizeRecipeTags(cached.tags ?? cached.manifest.tags ?? []),
70
+ await runVendoredRecipeMutation({
71
+ targetDir,
72
+ mode: "replace",
73
+ materialize: async (nextTargetDir) => {
74
+ await (inspection.entry.materialization === "link"
75
+ ? symlink(inspection.source_dir, nextTargetDir, "dir")
76
+ : cp(inspection.source_dir, nextTargetDir, { recursive: true }));
77
+ },
78
+ commit: async () => {
79
+ const vendoredSha256 = await hashRecipeTree(targetDir);
80
+ const existingEntry = registry.recipes.find((entry) => entry.id === inspection.entry.id);
81
+ const nextRegistry = replaceProjectRecipeRegistryEntry(registry, {
82
+ id: inspection.entry.id,
83
+ version: inspection.entry.version,
84
+ path: inspection.entry.project_path,
85
+ active: existingEntry?.active === true,
86
+ materialization: inspection.entry.materialization,
87
+ source_ref: inspection.entry.source_ref,
88
+ source_sha256: currentSourceSha256,
89
+ vendored_sha256: vendoredSha256,
90
+ installed_at: inspection.entry.installed_at,
91
+ tags: normalizeRecipeTags(cached.tags ?? cached.manifest.tags ?? []),
92
+ });
93
+ await publishProjectRecipesState({ project, registry: nextRegistry });
79
94
  },
80
95
  });
81
- await refreshProjectOverlayArtifacts(project);
82
96
  const verb = inspection.entry.materialization === "link"
83
97
  ? "Refreshed linked recipe"
84
98
  : "Updated vendored recipe";
@@ -1,4 +1,4 @@
1
- import type { RecipesIndex } from "./types.js";
1
+ import type { RecipesIndex } from "@agentplaneorg/recipes";
2
2
  export declare function loadRecipesRemoteIndex(opts: {
3
3
  cwd: string;
4
4
  source?: string;