akm-cli 0.6.1 → 0.7.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (333) hide show
  1. package/CHANGELOG.md +66 -0
  2. package/dist/{cli.js → src/cli.js} +712 -34
  3. package/dist/{commands → src/commands}/config-cli.js +47 -4
  4. package/dist/src/commands/distill.js +283 -0
  5. package/dist/src/commands/events.js +108 -0
  6. package/dist/src/commands/history.js +191 -0
  7. package/dist/{commands → src/commands}/installed-stashes.js +1 -1
  8. package/dist/src/commands/proposal.js +119 -0
  9. package/dist/src/commands/propose.js +171 -0
  10. package/dist/src/commands/reflect.js +193 -0
  11. package/dist/{commands → src/commands}/registry-search.js +71 -7
  12. package/dist/{commands → src/commands}/remember.js +12 -0
  13. package/dist/{commands → src/commands}/search.js +104 -4
  14. package/dist/{commands → src/commands}/self-update.js +4 -3
  15. package/dist/{commands → src/commands}/show.js +73 -0
  16. package/dist/{commands → src/commands}/source-add.js +5 -1
  17. package/dist/{commands → src/commands}/source-manage.js +7 -1
  18. package/dist/{core → src/core}/asset-ref.js +5 -5
  19. package/dist/{core → src/core}/asset-spec.js +12 -0
  20. package/dist/{core → src/core}/common.js +1 -1
  21. package/dist/{core → src/core}/config.js +203 -121
  22. package/dist/{core → src/core}/errors.js +4 -0
  23. package/dist/src/core/events.js +239 -0
  24. package/dist/src/core/lesson-lint.js +86 -0
  25. package/dist/src/core/proposals.js +406 -0
  26. package/dist/src/core/warn.js +72 -0
  27. package/dist/{core → src/core}/write-source.js +80 -5
  28. package/dist/{indexer → src/indexer}/db-search.js +114 -24
  29. package/dist/{indexer → src/indexer}/db.js +76 -23
  30. package/dist/{indexer → src/indexer}/file-context.js +0 -3
  31. package/dist/src/indexer/graph-boost.js +179 -0
  32. package/dist/src/indexer/graph-extraction.js +212 -0
  33. package/dist/{indexer → src/indexer}/indexer.js +88 -7
  34. package/dist/{indexer → src/indexer}/matchers.js +1 -1
  35. package/dist/src/indexer/memory-inference.js +263 -0
  36. package/dist/{indexer → src/indexer}/metadata.js +111 -3
  37. package/dist/{indexer → src/indexer}/search-source.js +4 -2
  38. package/dist/src/integrations/agent/config.js +292 -0
  39. package/dist/src/integrations/agent/detect.js +94 -0
  40. package/dist/src/integrations/agent/index.js +17 -0
  41. package/dist/src/integrations/agent/profiles.js +65 -0
  42. package/dist/src/integrations/agent/prompts.js +167 -0
  43. package/dist/src/integrations/agent/spawn.js +272 -0
  44. package/dist/{integrations → src/integrations}/github.js +9 -3
  45. package/dist/{integrations → src/integrations}/lockfile.js +0 -26
  46. package/dist/{llm → src/llm}/client.js +33 -2
  47. package/dist/{llm → src/llm}/embedders/remote.js +37 -3
  48. package/dist/src/llm/feature-gate.js +108 -0
  49. package/dist/src/llm/graph-extract.js +107 -0
  50. package/dist/src/llm/index-passes.js +35 -0
  51. package/dist/src/llm/memory-infer.js +86 -0
  52. package/dist/{output → src/output}/cli-hints.js +15 -2
  53. package/dist/{output → src/output}/renderers.js +63 -2
  54. package/dist/src/output/shapes.js +523 -0
  55. package/dist/src/output/text.js +1116 -0
  56. package/dist/{registry → src/registry}/build-index.js +19 -8
  57. package/dist/{registry → src/registry}/factory.js +0 -8
  58. package/dist/{registry → src/registry}/providers/static-index.js +6 -3
  59. package/dist/{registry → src/registry}/resolve.js +68 -2
  60. package/dist/{setup → src/setup}/setup.js +52 -5
  61. package/dist/{sources → src/sources}/providers/git.js +7 -15
  62. package/dist/{wiki → src/wiki}/wiki.js +54 -6
  63. package/dist/{workflows → src/workflows}/runs.js +37 -3
  64. package/dist/tests/add-website-source.test.js +119 -0
  65. package/dist/tests/agent/agent-config-loader.test.js +70 -0
  66. package/dist/tests/agent/agent-config.test.js +221 -0
  67. package/dist/tests/agent/agent-detect.test.js +100 -0
  68. package/dist/tests/agent/agent-spawn.test.js +234 -0
  69. package/dist/tests/agent-output.test.js +186 -0
  70. package/dist/tests/architecture/agent-no-llm-sdk-guard.test.js +103 -0
  71. package/dist/tests/architecture/agent-spawn-seam.test.js +193 -0
  72. package/dist/tests/architecture/llm-stateless-seam.test.js +112 -0
  73. package/dist/tests/asset-ref.test.js +192 -0
  74. package/dist/tests/asset-registry.test.js +103 -0
  75. package/dist/tests/asset-spec.test.js +241 -0
  76. package/dist/tests/bench/attribution.test.js +996 -0
  77. package/dist/tests/bench/cleanup-sigint.test.js +83 -0
  78. package/dist/tests/bench/cleanup.js +234 -0
  79. package/dist/tests/bench/cleanup.test.js +166 -0
  80. package/dist/tests/bench/cli.js +1018 -0
  81. package/dist/tests/bench/cli.test.js +445 -0
  82. package/dist/tests/bench/compare.test.js +556 -0
  83. package/dist/tests/bench/corpus.js +317 -0
  84. package/dist/tests/bench/corpus.test.js +258 -0
  85. package/dist/tests/bench/doctor.js +525 -0
  86. package/dist/tests/bench/driver.js +401 -0
  87. package/dist/tests/bench/driver.test.js +584 -0
  88. package/dist/tests/bench/environment.js +233 -0
  89. package/dist/tests/bench/environment.test.js +199 -0
  90. package/dist/tests/bench/evolve-metrics.js +179 -0
  91. package/dist/tests/bench/evolve-metrics.test.js +187 -0
  92. package/dist/tests/bench/evolve.js +647 -0
  93. package/dist/tests/bench/evolve.test.js +624 -0
  94. package/dist/tests/bench/failure-modes.test.js +349 -0
  95. package/dist/tests/bench/feedback-integrity.test.js +457 -0
  96. package/dist/tests/bench/leakage.test.js +228 -0
  97. package/dist/tests/bench/learning-curve.test.js +134 -0
  98. package/dist/tests/bench/metrics.js +2395 -0
  99. package/dist/tests/bench/metrics.test.js +1150 -0
  100. package/dist/tests/bench/no-os-tmpdir-invariant.test.js +43 -0
  101. package/dist/tests/bench/opencode-config.js +194 -0
  102. package/dist/tests/bench/opencode-config.test.js +370 -0
  103. package/dist/tests/bench/report.js +1885 -0
  104. package/dist/tests/bench/report.test.js +1038 -0
  105. package/dist/tests/bench/run-config.js +355 -0
  106. package/dist/tests/bench/run-config.test.js +298 -0
  107. package/dist/tests/bench/run-curate-test.js +32 -0
  108. package/dist/tests/bench/run-failing-tasks.js +56 -0
  109. package/dist/tests/bench/run-full-bench.js +51 -0
  110. package/dist/tests/bench/run-items36-targeted.js +69 -0
  111. package/dist/tests/bench/run-nano-quick.js +42 -0
  112. package/dist/tests/bench/run-waveg-targeted.js +62 -0
  113. package/dist/tests/bench/runner.js +699 -0
  114. package/dist/tests/bench/runner.test.js +958 -0
  115. package/dist/tests/bench/search-bridge.test.js +331 -0
  116. package/dist/tests/bench/tmp.js +131 -0
  117. package/dist/tests/bench/trajectory.js +116 -0
  118. package/dist/tests/bench/trajectory.test.js +127 -0
  119. package/dist/tests/bench/verifier.js +114 -0
  120. package/dist/tests/bench/verifier.test.js +118 -0
  121. package/dist/tests/bench/workflow-evaluator.js +557 -0
  122. package/dist/tests/bench/workflow-evaluator.test.js +421 -0
  123. package/dist/tests/bench/workflow-spec.js +345 -0
  124. package/dist/tests/bench/workflow-spec.test.js +363 -0
  125. package/dist/tests/bench/workflow-trace.js +472 -0
  126. package/dist/tests/bench/workflow-trace.test.js +254 -0
  127. package/dist/tests/benchmark-search-quality.js +536 -0
  128. package/dist/tests/benchmark-suite.js +1441 -0
  129. package/dist/tests/capture-cli.test.js +112 -0
  130. package/dist/tests/cli-errors.test.js +204 -0
  131. package/dist/tests/commands/events.test.js +370 -0
  132. package/dist/tests/commands/history.test.js +418 -0
  133. package/dist/tests/commands/import.test.js +103 -0
  134. package/dist/tests/commands/proposal-cli.test.js +209 -0
  135. package/dist/tests/commands/reflect-propose-cli.test.js +333 -0
  136. package/dist/tests/commands/remember.test.js +97 -0
  137. package/dist/tests/commands/scope-flags.test.js +300 -0
  138. package/dist/tests/commands/search.test.js +537 -0
  139. package/dist/tests/commands/show-indexer-parity.test.js +117 -0
  140. package/dist/tests/commands/show.test.js +294 -0
  141. package/dist/tests/common.test.js +266 -0
  142. package/dist/tests/completions.test.js +142 -0
  143. package/dist/tests/config-cli.test.js +193 -0
  144. package/dist/tests/config-llm-features.test.js +139 -0
  145. package/dist/tests/config.test.js +569 -0
  146. package/dist/tests/contracts/migration-baseline.test.js +43 -0
  147. package/dist/tests/contracts/reflect-propose-envelope.test.js +139 -0
  148. package/dist/tests/contracts/spec-helpers.js +46 -0
  149. package/dist/tests/contracts/v1-spec-section-11-proposal-queue.test.js +228 -0
  150. package/dist/tests/contracts/v1-spec-section-12-agent-config.test.js +56 -0
  151. package/dist/tests/contracts/v1-spec-section-13-lesson-type.test.js +34 -0
  152. package/dist/tests/contracts/v1-spec-section-14-llm-features.test.js +94 -0
  153. package/dist/tests/contracts/v1-spec-section-4-1-asset-types.test.js +39 -0
  154. package/dist/tests/contracts/v1-spec-section-4-2-quality-rules.test.js +44 -0
  155. package/dist/tests/contracts/v1-spec-section-5-configuration.test.js +47 -0
  156. package/dist/tests/contracts/v1-spec-section-6-orchestration.test.js +40 -0
  157. package/dist/tests/contracts/v1-spec-section-7-module-layout.test.js +58 -0
  158. package/dist/tests/contracts/v1-spec-section-8-extension-points.test.js +34 -0
  159. package/dist/tests/contracts/v1-spec-section-9-4-cli-surface.test.js +75 -0
  160. package/dist/tests/contracts/v1-spec-section-9-7-llm-agent-boundary.test.js +36 -0
  161. package/dist/tests/core/write-source.test.js +366 -0
  162. package/dist/tests/curate-command.test.js +87 -0
  163. package/dist/tests/db-scoring.test.js +201 -0
  164. package/dist/tests/db.test.js +654 -0
  165. package/dist/tests/distill-cli-flag.test.js +208 -0
  166. package/dist/tests/distill.test.js +515 -0
  167. package/dist/tests/docker-install.test.js +120 -0
  168. package/dist/tests/e2e.test.js +1419 -0
  169. package/dist/tests/embedder.test.js +340 -0
  170. package/dist/tests/embedding-model-config.test.js +379 -0
  171. package/dist/tests/feedback-command.test.js +172 -0
  172. package/dist/tests/file-context.test.js +552 -0
  173. package/dist/tests/fixtures/scripts/git/summarize-diff.js +9 -0
  174. package/dist/tests/fixtures/scripts/lint/eslint-check.js +7 -0
  175. package/dist/tests/fixtures/stashes/load.js +166 -0
  176. package/dist/tests/fixtures/stashes/load.test.js +97 -0
  177. package/dist/tests/fixtures/stashes/ranking-baseline/scripts/mem0-search.js +12 -0
  178. package/dist/tests/frontmatter.test.js +190 -0
  179. package/dist/tests/fts-field-weighting.test.js +254 -0
  180. package/dist/tests/fuzzy-search.test.js +230 -0
  181. package/dist/tests/git-provider-clone.test.js +45 -0
  182. package/dist/tests/github.test.js +161 -0
  183. package/dist/tests/graph-boost-ranking.test.js +305 -0
  184. package/dist/tests/graph-extraction.test.js +282 -0
  185. package/dist/tests/helpers/usage-events.js +8 -0
  186. package/dist/tests/index-pass-llm.test.js +161 -0
  187. package/dist/tests/indexer.test.js +570 -0
  188. package/dist/tests/info-command.test.js +166 -0
  189. package/dist/tests/init.test.js +69 -0
  190. package/dist/tests/install-script.test.js +246 -0
  191. package/dist/tests/integration/agent-real-profile.test.js +94 -0
  192. package/dist/tests/issue-36-repro.test.js +304 -0
  193. package/dist/tests/issues-191-194.test.js +160 -0
  194. package/dist/tests/lesson-lint.test.js +111 -0
  195. package/dist/tests/llm-client.test.js +115 -0
  196. package/dist/tests/llm-feature-gate.test.js +151 -0
  197. package/dist/tests/llm.test.js +139 -0
  198. package/dist/tests/lockfile.test.js +216 -0
  199. package/dist/tests/manifest.test.js +205 -0
  200. package/dist/tests/markdown.test.js +126 -0
  201. package/dist/tests/matchers-unit.test.js +189 -0
  202. package/dist/tests/memory-inference.test.js +299 -0
  203. package/dist/tests/merge-scoring.test.js +136 -0
  204. package/dist/tests/metadata.test.js +313 -0
  205. package/dist/tests/migration-help.test.js +89 -0
  206. package/dist/tests/origin-resolve.test.js +124 -0
  207. package/dist/tests/output-baseline.test.js +218 -0
  208. package/dist/tests/output-shapes-unit.test.js +478 -0
  209. package/dist/tests/parallel-search.test.js +272 -0
  210. package/dist/tests/parameter-metadata.test.js +365 -0
  211. package/dist/tests/paths.test.js +177 -0
  212. package/dist/tests/progressive-disclosure.test.js +280 -0
  213. package/dist/tests/proposals.test.js +279 -0
  214. package/dist/tests/proposed-quality.test.js +271 -0
  215. package/dist/tests/provider-registry.test.js +32 -0
  216. package/dist/tests/ranking-regression.test.js +548 -0
  217. package/dist/tests/reflect-propose.test.js +455 -0
  218. package/dist/tests/registry-build-index.test.js +394 -0
  219. package/dist/tests/registry-cli.test.js +290 -0
  220. package/dist/tests/registry-index-v2.test.js +430 -0
  221. package/dist/tests/registry-install.test.js +728 -0
  222. package/dist/tests/registry-providers/parity.test.js +189 -0
  223. package/dist/tests/registry-providers/skills-sh.test.js +309 -0
  224. package/dist/tests/registry-providers/static-index.test.js +238 -0
  225. package/dist/tests/registry-resolve.test.js +126 -0
  226. package/dist/tests/registry-search.test.js +923 -0
  227. package/dist/tests/remember-frontmatter.test.js +378 -0
  228. package/dist/tests/remember-unit.test.js +123 -0
  229. package/dist/tests/ripgrep-install.test.js +251 -0
  230. package/dist/tests/ripgrep-resolve.test.js +108 -0
  231. package/dist/tests/ripgrep.test.js +163 -0
  232. package/dist/tests/save-command.test.js +94 -0
  233. package/dist/tests/save-trust-qa-fixes.test.js +270 -0
  234. package/dist/tests/scoring-pipeline.test.js +648 -0
  235. package/dist/tests/search-include-proposed-cli.test.js +118 -0
  236. package/dist/tests/self-update.test.js +442 -0
  237. package/dist/tests/semantic-search-e2e.test.js +512 -0
  238. package/dist/tests/semantic-status.test.js +471 -0
  239. package/dist/tests/setup-run.integration.js +877 -0
  240. package/dist/tests/setup-wizard.test.js +198 -0
  241. package/dist/tests/setup.test.js +131 -0
  242. package/dist/tests/source-add.test.js +11 -0
  243. package/dist/tests/source-clone.test.js +254 -0
  244. package/dist/tests/source-manage.test.js +366 -0
  245. package/dist/tests/source-providers/filesystem.test.js +82 -0
  246. package/dist/tests/source-providers/git.test.js +252 -0
  247. package/dist/tests/source-providers/website.test.js +128 -0
  248. package/dist/tests/source-qa-fixes.test.js +286 -0
  249. package/dist/tests/source-registry.test.js +350 -0
  250. package/dist/tests/source-resolve.test.js +100 -0
  251. package/dist/tests/source-source.test.js +281 -0
  252. package/dist/tests/source.test.js +533 -0
  253. package/dist/tests/tar-utils-scan.test.js +73 -0
  254. package/dist/tests/toggle-components.test.js +73 -0
  255. package/dist/tests/usage-telemetry.test.js +265 -0
  256. package/dist/tests/utility-scoring.test.js +558 -0
  257. package/dist/tests/vault-load-error.test.js +78 -0
  258. package/dist/tests/vault-qa-fixes.test.js +194 -0
  259. package/dist/tests/vault.test.js +429 -0
  260. package/dist/tests/vector-search.test.js +608 -0
  261. package/dist/tests/walker.test.js +252 -0
  262. package/dist/tests/wave2-cluster-bc.test.js +228 -0
  263. package/dist/tests/wave2-cluster-d.test.js +180 -0
  264. package/dist/tests/wave2-cluster-e.test.js +179 -0
  265. package/dist/tests/wiki-qa-fixes.test.js +270 -0
  266. package/dist/tests/wiki.test.js +529 -0
  267. package/dist/tests/workflow-cli.test.js +271 -0
  268. package/dist/tests/workflow-markdown.test.js +171 -0
  269. package/dist/tests/workflow-path-escape.test.js +132 -0
  270. package/dist/tests/workflow-qa-fixes.test.js +395 -0
  271. package/dist/tests/workflows/indexer-rejection.test.js +213 -0
  272. package/docs/README.md +8 -0
  273. package/docs/migration/release-notes/0.7.0.md +244 -0
  274. package/package.json +2 -2
  275. package/dist/core/warn.js +0 -27
  276. package/dist/output/shapes.js +0 -212
  277. package/dist/output/text.js +0 -520
  278. /package/dist/{commands → src/commands}/completions.js +0 -0
  279. /package/dist/{commands → src/commands}/curate.js +0 -0
  280. /package/dist/{commands → src/commands}/info.js +0 -0
  281. /package/dist/{commands → src/commands}/init.js +0 -0
  282. /package/dist/{commands → src/commands}/install-audit.js +0 -0
  283. /package/dist/{commands → src/commands}/migration-help.js +0 -0
  284. /package/dist/{commands → src/commands}/source-clone.js +0 -0
  285. /package/dist/{commands → src/commands}/vault.js +0 -0
  286. /package/dist/{core → src/core}/asset-registry.js +0 -0
  287. /package/dist/{core → src/core}/frontmatter.js +0 -0
  288. /package/dist/{core → src/core}/markdown.js +0 -0
  289. /package/dist/{core → src/core}/paths.js +0 -0
  290. /package/dist/{indexer → src/indexer}/manifest.js +0 -0
  291. /package/dist/{indexer → src/indexer}/search-fields.js +0 -0
  292. /package/dist/{indexer → src/indexer}/semantic-status.js +0 -0
  293. /package/dist/{indexer → src/indexer}/usage-events.js +0 -0
  294. /package/dist/{indexer → src/indexer}/walker.js +0 -0
  295. /package/dist/{llm → src/llm}/embedder.js +0 -0
  296. /package/dist/{llm → src/llm}/embedders/cache.js +0 -0
  297. /package/dist/{llm → src/llm}/embedders/local.js +0 -0
  298. /package/dist/{llm → src/llm}/embedders/types.js +0 -0
  299. /package/dist/{llm → src/llm}/metadata-enhance.js +0 -0
  300. /package/dist/{output → src/output}/context.js +0 -0
  301. /package/dist/{registry → src/registry}/create-provider-registry.js +0 -0
  302. /package/dist/{registry → src/registry}/origin-resolve.js +0 -0
  303. /package/dist/{registry → src/registry}/providers/index.js +0 -0
  304. /package/dist/{registry → src/registry}/providers/skills-sh.js +0 -0
  305. /package/dist/{registry → src/registry}/providers/types.js +0 -0
  306. /package/dist/{registry → src/registry}/types.js +0 -0
  307. /package/dist/{setup → src/setup}/detect.js +0 -0
  308. /package/dist/{setup → src/setup}/ripgrep-install.js +0 -0
  309. /package/dist/{setup → src/setup}/ripgrep-resolve.js +0 -0
  310. /package/dist/{setup → src/setup}/steps.js +0 -0
  311. /package/dist/{sources → src/sources}/include.js +0 -0
  312. /package/dist/{sources → src/sources}/provider-factory.js +0 -0
  313. /package/dist/{sources → src/sources}/provider.js +0 -0
  314. /package/dist/{sources → src/sources}/providers/filesystem.js +0 -0
  315. /package/dist/{sources → src/sources}/providers/index.js +0 -0
  316. /package/dist/{sources → src/sources}/providers/install-types.js +0 -0
  317. /package/dist/{sources → src/sources}/providers/npm.js +0 -0
  318. /package/dist/{sources → src/sources}/providers/provider-utils.js +0 -0
  319. /package/dist/{sources → src/sources}/providers/sync-from-ref.js +0 -0
  320. /package/dist/{sources → src/sources}/providers/tar-utils.js +0 -0
  321. /package/dist/{sources → src/sources}/providers/website.js +0 -0
  322. /package/dist/{sources → src/sources}/resolve.js +0 -0
  323. /package/dist/{sources → src/sources}/types.js +0 -0
  324. /package/dist/{templates → src/templates}/wiki-templates.js +0 -0
  325. /package/dist/{version.js → src/version.js} +0 -0
  326. /package/dist/{workflows → src/workflows}/authoring.js +0 -0
  327. /package/dist/{workflows → src/workflows}/cli.js +0 -0
  328. /package/dist/{workflows → src/workflows}/db.js +0 -0
  329. /package/dist/{workflows → src/workflows}/document-cache.js +0 -0
  330. /package/dist/{workflows → src/workflows}/parser.js +0 -0
  331. /package/dist/{workflows → src/workflows}/renderer.js +0 -0
  332. /package/dist/{workflows → src/workflows}/schema.js +0 -0
  333. /package/dist/{workflows → src/workflows}/validator.js +0 -0
@@ -0,0 +1,523 @@
1
+ /**
2
+ * Pure shaping functions that select and trim fields from command result
3
+ * objects according to the active detail level / agent mode.
4
+ *
5
+ * Every function in this module is side-effect free and operates on plain
6
+ * `Record<string, unknown>` shapes, which makes them trivial to unit test.
7
+ */
8
+ const NORMAL_DESCRIPTION_LIMIT = 250;
9
+ export function shapeForCommand(command, result, detail, forAgent = false) {
10
+ switch (command) {
11
+ case "search":
12
+ return shapeSearchOutput(result, detail, forAgent);
13
+ case "registry-search":
14
+ return shapeRegistrySearchOutput(result, detail);
15
+ case "show":
16
+ return shapeShowOutput(result, detail, forAgent);
17
+ // Output shape registration for `akm history` — paired with the textRenderer in text.ts.
18
+ case "history":
19
+ return shapeHistoryOutput(result, detail);
20
+ // Output shape registration for `akm events list` and `akm events tail`
21
+ // (#204). Both share the same envelope; the renderer in text.ts uses
22
+ // distinct command names so it can format streaming differently.
23
+ case "events-list":
24
+ case "events-tail":
25
+ return shapeEventsOutput(result, detail);
26
+ // Output shape registration for `akm proposal {list,show,accept,reject,diff}`
27
+ // (#225). Each verb gets its own arm so the registry stays exhaustive (no
28
+ // silent JSON.stringify fallback). The proposal payload is reshaped per
29
+ // detail level — `brief` omits the full content body, while some proposal
30
+ // shapers still retain normal-level metadata such as review details;
31
+ // `full`/`agent` includes everything.
32
+ case "proposal-list":
33
+ return shapeProposalListOutput(result, detail);
34
+ case "proposal-show":
35
+ return shapeProposalShowOutput(result, detail);
36
+ case "proposal-accept":
37
+ return shapeProposalAcceptOutput(result, detail);
38
+ case "proposal-reject":
39
+ return shapeProposalRejectOutput(result, detail);
40
+ case "proposal-diff":
41
+ return shapeProposalDiffOutput(result, detail);
42
+ // Output shape registration for `akm reflect` and `akm propose` (#226).
43
+ // Both share the proposal-producer envelope shape (success carries a
44
+ // proposal entry; failure carries an AgentFailureReason discriminant).
45
+ case "reflect":
46
+ case "propose":
47
+ return shapeProposalProducerOutput(result, detail);
48
+ // Output shape registration for `akm distill <ref>` (#228). The shape is
49
+ // simple — outcome + ids + optional payload — so `brief` strips the full
50
+ // proposal blob, `normal` keeps the headline fields, and `full` projects
51
+ // everything for downstream automation.
52
+ case "distill":
53
+ return shapeDistillOutput(result, detail);
54
+ // Identity-passthrough commands — registered here so the registry stays
55
+ // exhaustive (v1 spec §9). Each result object is already shaped at the
56
+ // command boundary; the registry just confirms there's no surprise
57
+ // command name slipping through.
58
+ case "add":
59
+ case "clone":
60
+ case "config":
61
+ case "curate":
62
+ case "disable":
63
+ case "enable":
64
+ case "feedback":
65
+ case "import":
66
+ case "index":
67
+ case "info":
68
+ case "init":
69
+ case "list":
70
+ case "registry-add":
71
+ case "registry-build-index":
72
+ case "registry-list":
73
+ case "registry-remove":
74
+ case "remember":
75
+ case "remove":
76
+ case "save":
77
+ case "update":
78
+ case "upgrade":
79
+ case "vault-create":
80
+ case "vault-list":
81
+ case "vault-set":
82
+ case "vault-unset":
83
+ case "wiki-create":
84
+ case "wiki-ingest":
85
+ case "wiki-lint":
86
+ case "wiki-list":
87
+ case "wiki-pages":
88
+ case "wiki-register":
89
+ case "wiki-remove":
90
+ case "wiki-show":
91
+ case "wiki-stash":
92
+ case "workflow-complete":
93
+ case "workflow-create":
94
+ case "workflow-list":
95
+ case "workflow-next":
96
+ case "workflow-resume":
97
+ case "workflow-start":
98
+ case "workflow-status":
99
+ case "workflow-validate":
100
+ return result;
101
+ default:
102
+ // v1 spec §9 (output-shape registry exhaustive): no silent JSON.stringify
103
+ // fallback. A missing case here is a registration bug — fail loudly so
104
+ // the caller (or its tests) sees the missing command name.
105
+ throw new Error(`output shape not registered for command: ${command}`);
106
+ }
107
+ }
108
+ /**
109
+ * Shape the result of `akm reflect` / `akm propose`. On success we surface
110
+ * the queued proposal entry (using the standard proposal-entry shaper so
111
+ * detail levels behave uniformly with `akm proposal show`). On failure we
112
+ * surface the structured failure-reason envelope as-is — the failure
113
+ * surface is small and the reason / error text is always load-bearing.
114
+ */
115
+ export function shapeProposalProducerOutput(result, detail) {
116
+ if (result.ok === false) {
117
+ const base = {
118
+ ok: false,
119
+ reason: result.reason,
120
+ error: result.error,
121
+ ...(result.ref !== undefined ? { ref: result.ref } : {}),
122
+ ...(result.type !== undefined ? { type: result.type } : {}),
123
+ ...(result.name !== undefined ? { name: result.name } : {}),
124
+ ...(result.exitCode !== undefined ? { exitCode: result.exitCode } : {}),
125
+ };
126
+ if (detail === "full") {
127
+ return {
128
+ schemaVersion: result.schemaVersion ?? 1,
129
+ ...base,
130
+ ...(result.stdout !== undefined ? { stdout: result.stdout } : {}),
131
+ ...(result.stderr !== undefined ? { stderr: result.stderr } : {}),
132
+ };
133
+ }
134
+ return base;
135
+ }
136
+ const proposal = result.proposal ?? {};
137
+ const base = {
138
+ ok: true,
139
+ ref: result.ref,
140
+ ...(result.agentProfile !== undefined ? { agentProfile: result.agentProfile } : {}),
141
+ ...(typeof result.durationMs === "number" ? { durationMs: result.durationMs } : {}),
142
+ proposal: shapeProposalEntry(proposal, detail === "brief" ? "normal" : detail),
143
+ };
144
+ if (detail === "full") {
145
+ return { schemaVersion: result.schemaVersion ?? 1, ...base };
146
+ }
147
+ return base;
148
+ }
149
+ export function shapeProposalEntry(entry, detail) {
150
+ if (detail === "brief") {
151
+ return pickFields(entry, ["id", "ref", "status", "source", "createdAt"]);
152
+ }
153
+ if (detail === "normal" || detail === "summary") {
154
+ return pickFields(entry, ["id", "ref", "status", "source", "sourceRun", "createdAt", "updatedAt", "review"]);
155
+ }
156
+ // full / agent: project everything including the payload.
157
+ return pickFields(entry, [
158
+ "id",
159
+ "ref",
160
+ "status",
161
+ "source",
162
+ "sourceRun",
163
+ "createdAt",
164
+ "updatedAt",
165
+ "payload",
166
+ "review",
167
+ ]);
168
+ }
169
+ export function shapeProposalListOutput(result, detail) {
170
+ const proposals = Array.isArray(result.proposals) ? result.proposals : [];
171
+ const shaped = proposals.map((p) => shapeProposalEntry(p, detail));
172
+ const base = {
173
+ totalCount: result.totalCount ?? shaped.length,
174
+ proposals: shaped,
175
+ };
176
+ if (detail === "full") {
177
+ return { schemaVersion: result.schemaVersion ?? 1, ...base };
178
+ }
179
+ return base;
180
+ }
181
+ export function shapeProposalShowOutput(result, detail) {
182
+ const proposal = result.proposal ?? {};
183
+ const validation = result.validation;
184
+ const base = {
185
+ proposal: shapeProposalEntry(proposal, detail === "brief" ? "normal" : detail),
186
+ ...(validation ? { validation } : {}),
187
+ };
188
+ if (detail === "full") {
189
+ return { schemaVersion: result.schemaVersion ?? 1, ...base };
190
+ }
191
+ return base;
192
+ }
193
+ export function shapeProposalAcceptOutput(result, detail) {
194
+ const proposal = result.proposal ?? {};
195
+ const base = {
196
+ ok: result.ok ?? true,
197
+ id: result.id,
198
+ ref: result.ref,
199
+ assetPath: result.assetPath,
200
+ proposal: shapeProposalEntry(proposal, detail === "brief" ? "normal" : detail),
201
+ };
202
+ if (detail === "full") {
203
+ return { schemaVersion: result.schemaVersion ?? 1, ...base };
204
+ }
205
+ return base;
206
+ }
207
+ export function shapeProposalRejectOutput(result, detail) {
208
+ const proposal = result.proposal ?? {};
209
+ const base = {
210
+ ok: result.ok ?? true,
211
+ id: result.id,
212
+ ref: result.ref,
213
+ ...(result.reason !== undefined ? { reason: result.reason } : {}),
214
+ proposal: shapeProposalEntry(proposal, detail === "brief" ? "normal" : detail),
215
+ };
216
+ if (detail === "full") {
217
+ return { schemaVersion: result.schemaVersion ?? 1, ...base };
218
+ }
219
+ return base;
220
+ }
221
+ export function shapeDistillOutput(result, detail) {
222
+ const proposal = result.proposal;
223
+ if (detail === "brief") {
224
+ return pickFields(result, ["ok", "outcome", "inputRef", "lessonRef", "proposalId", "message"]);
225
+ }
226
+ const base = {
227
+ ok: result.ok ?? true,
228
+ outcome: result.outcome,
229
+ inputRef: result.inputRef,
230
+ lessonRef: result.lessonRef,
231
+ ...(result.proposalId !== undefined ? { proposalId: result.proposalId } : {}),
232
+ ...(result.message !== undefined ? { message: result.message } : {}),
233
+ ...(Array.isArray(result.findings) && result.findings.length > 0 ? { findings: result.findings } : {}),
234
+ ...(proposal ? { proposal: shapeProposalEntry(proposal, detail === "summary" ? "normal" : detail) } : {}),
235
+ };
236
+ if (detail === "full") {
237
+ return { schemaVersion: result.schemaVersion ?? 1, ...base };
238
+ }
239
+ return base;
240
+ }
241
+ export function shapeProposalDiffOutput(result, detail) {
242
+ const base = {
243
+ id: result.id,
244
+ ref: result.ref,
245
+ isNew: result.isNew,
246
+ unified: result.unified,
247
+ ...(result.targetPath !== undefined ? { targetPath: result.targetPath } : {}),
248
+ };
249
+ if (detail === "full") {
250
+ return { schemaVersion: result.schemaVersion ?? 1, ...base };
251
+ }
252
+ return base;
253
+ }
254
+ export function shapeEventsOutput(result, detail) {
255
+ const events = Array.isArray(result.events) ? result.events : [];
256
+ const shapedEvents = events.map((event) => shapeEventEntry(event, detail));
257
+ const base = {
258
+ ...(result.ref !== undefined ? { ref: result.ref } : {}),
259
+ ...(result.type !== undefined ? { type: result.type } : {}),
260
+ ...(result.since !== undefined ? { since: result.since } : {}),
261
+ ...(typeof result.sinceOffset === "number" ? { sinceOffset: result.sinceOffset } : {}),
262
+ totalCount: result.totalCount ?? shapedEvents.length,
263
+ events: shapedEvents,
264
+ };
265
+ if (typeof result.nextOffset === "number") {
266
+ base.nextOffset = result.nextOffset;
267
+ }
268
+ if (typeof result.reason === "string") {
269
+ base.reason = result.reason;
270
+ }
271
+ if (detail === "full") {
272
+ return { schemaVersion: result.schemaVersion ?? 1, ...base };
273
+ }
274
+ return base;
275
+ }
276
+ export function shapeEventEntry(entry, detail) {
277
+ if (detail === "brief") {
278
+ return pickFields(entry, ["eventType", "ref", "ts"]);
279
+ }
280
+ if (detail === "normal" || detail === "summary") {
281
+ return pickFields(entry, ["eventType", "ref", "ts"]);
282
+ }
283
+ // full / agent: project everything the reader emits.
284
+ return pickFields(entry, ["id", "schemaVersion", "eventType", "ref", "ts", "metadata"]);
285
+ }
286
+ export function shapeHistoryOutput(result, detail) {
287
+ const entries = Array.isArray(result.entries) ? result.entries : [];
288
+ const shapedEntries = entries.map((entry) => shapeHistoryEntry(entry, detail));
289
+ if (detail === "full") {
290
+ return {
291
+ schemaVersion: result.schemaVersion ?? 1,
292
+ ...(result.ref !== undefined ? { ref: result.ref } : {}),
293
+ ...(result.since !== undefined ? { since: result.since } : {}),
294
+ totalCount: result.totalCount ?? shapedEntries.length,
295
+ entries: shapedEntries,
296
+ // `sources` lists the event sources included in this response.
297
+ // Always contains "usage_events"; also "events.jsonl" when
298
+ // --include-proposals was specified.
299
+ ...(Array.isArray(result.sources) ? { sources: result.sources } : {}),
300
+ ...(Array.isArray(result.warnings) && result.warnings.length > 0 ? { warnings: result.warnings } : {}),
301
+ };
302
+ }
303
+ return {
304
+ ...(result.ref !== undefined ? { ref: result.ref } : {}),
305
+ ...(result.since !== undefined ? { since: result.since } : {}),
306
+ totalCount: result.totalCount ?? shapedEntries.length,
307
+ entries: shapedEntries,
308
+ ...(Array.isArray(result.sources) ? { sources: result.sources } : {}),
309
+ ...(Array.isArray(result.warnings) && result.warnings.length > 0 ? { warnings: result.warnings } : {}),
310
+ };
311
+ }
312
+ export function shapeHistoryEntry(entry, detail) {
313
+ if (detail === "brief") {
314
+ // signal is load-bearing for feedback rows (positive/negative) so we
315
+ // project it even at brief — without it the entry is ambiguous.
316
+ return pickFields(entry, ["eventType", "ref", "signal", "createdAt"]);
317
+ }
318
+ if (detail === "normal" || detail === "summary") {
319
+ return pickFields(entry, ["eventType", "ref", "signal", "query", "createdAt"]);
320
+ }
321
+ // full / agent: return everything the reader emits.
322
+ return pickFields(entry, ["id", "eventType", "ref", "entryId", "query", "signal", "metadata", "createdAt"]);
323
+ }
324
+ export function shapeSearchOutput(result, detail, forAgent = false) {
325
+ const hits = Array.isArray(result.hits) ? result.hits : [];
326
+ const registryHits = Array.isArray(result.registryHits) ? result.registryHits : [];
327
+ const shapedHits = forAgent
328
+ ? hits.map((hit) => shapeSearchHitForAgent(hit))
329
+ : hits.map((hit) => shapeSearchHit(hit, detail));
330
+ const shapedRegistryHits = forAgent
331
+ ? registryHits.map((hit) => shapeSearchHitForAgent(hit))
332
+ : registryHits.map((hit) => shapeSearchHit(hit, detail));
333
+ if (forAgent) {
334
+ return {
335
+ hits: shapedHits,
336
+ ...(shapedRegistryHits.length > 0 ? { registryHits: shapedRegistryHits } : {}),
337
+ ...(result.tip ? { tip: result.tip } : {}),
338
+ };
339
+ }
340
+ if (detail === "full") {
341
+ return {
342
+ schemaVersion: result.schemaVersion,
343
+ stashDir: result.stashDir,
344
+ source: result.source,
345
+ hits: shapedHits,
346
+ ...(shapedRegistryHits.length > 0 ? { registryHits: shapedRegistryHits } : {}),
347
+ ...(result.semanticSearch ? { semanticSearch: result.semanticSearch } : {}),
348
+ ...(result.tip ? { tip: result.tip } : {}),
349
+ ...(result.warnings ? { warnings: result.warnings } : {}),
350
+ ...(result.timing ? { timing: result.timing } : {}),
351
+ };
352
+ }
353
+ return {
354
+ hits: shapedHits,
355
+ ...(shapedRegistryHits.length > 0 ? { registryHits: shapedRegistryHits } : {}),
356
+ ...(Array.isArray(result.warnings) && result.warnings.length > 0 ? { warnings: result.warnings } : {}),
357
+ ...(result.tip ? { tip: result.tip } : {}),
358
+ };
359
+ }
360
+ export function shapeRegistrySearchOutput(result, detail) {
361
+ const hits = Array.isArray(result.hits) ? result.hits : [];
362
+ const assetHits = Array.isArray(result.assetHits) ? result.assetHits : [];
363
+ // Shape stash hits as registry type
364
+ const shapedKitHits = hits.map((hit) => shapeSearchHit({ ...hit, type: "registry" }, detail));
365
+ // Shape asset hits by detail level
366
+ const shapedAssetHits = assetHits.map((hit) => shapeAssetHit(hit, detail));
367
+ const shaped = {
368
+ hits: shapedKitHits,
369
+ ...(shapedAssetHits.length > 0 ? { assetHits: shapedAssetHits } : {}),
370
+ ...(Array.isArray(result.warnings) && result.warnings.length > 0 ? { warnings: result.warnings } : {}),
371
+ };
372
+ if (detail === "full") {
373
+ shaped.query = result.query;
374
+ }
375
+ return shaped;
376
+ }
377
+ export function shapeAssetHit(hit, detail) {
378
+ if (detail === "brief")
379
+ return pickFields(hit, ["assetName", "assetType", "action", "estimatedTokens"]);
380
+ if (detail === "normal") {
381
+ return capDescription(pickFields(hit, ["assetName", "assetType", "description", "stash", "action", "estimatedTokens"]), NORMAL_DESCRIPTION_LIMIT);
382
+ }
383
+ return hit;
384
+ }
385
+ export function shapeSearchHit(hit, detail) {
386
+ if (hit.type === "registry") {
387
+ if (detail === "brief") {
388
+ // RegistrySearchHit uses `title` (not `name`); always project installRef
389
+ // and score so callers can use the result without --detail full (QA #28).
390
+ const out = pickFields(hit, ["title", "name", "installRef", "score"]);
391
+ // Normalise: if only title exists, expose it as `name` for consistency
392
+ if (out.title && !out.name)
393
+ out.name = out.title;
394
+ return out;
395
+ }
396
+ if (detail === "normal") {
397
+ // `curated` was removed in v1 (spec §4.2). Renderers project optional
398
+ // hit-level `warnings` instead so providers can surface non-fatal issues.
399
+ const out = capDescription(pickFields(hit, ["title", "name", "description", "action", "installRef", "score", "warnings"]), NORMAL_DESCRIPTION_LIMIT);
400
+ if (out.title && !out.name)
401
+ out.name = out.title;
402
+ return out;
403
+ }
404
+ return hit;
405
+ }
406
+ // Stash hit (local or remote)
407
+ // `ref` is included at `brief` so agents can run `akm show <ref>` without
408
+ // needing --detail full or --for-agent (REC-03).
409
+ if (detail === "brief")
410
+ return pickFields(hit, ["type", "name", "ref", "action", "estimatedTokens"]);
411
+ if (detail === "normal") {
412
+ // `warnings` is projected at `normal` so non-fatal hit-level issues are
413
+ // visible without forcing callers up to `--detail full`. Optional
414
+ // `quality` (v1 spec §4.2) is also surfaced when present so callers
415
+ // can see why a `proposed` entry showed up under `--include-proposed`.
416
+ return capDescription(pickFields(hit, ["type", "name", "description", "action", "score", "estimatedTokens", "warnings", "quality"]), NORMAL_DESCRIPTION_LIMIT);
417
+ }
418
+ return hit;
419
+ }
420
+ /** Agent-optimized search hit: only fields an LLM agent needs to decide and act */
421
+ export function shapeSearchHitForAgent(hit) {
422
+ const picked = pickFields(hit, ["name", "ref", "type", "description", "action", "score", "estimatedTokens"]);
423
+ return capDescription(picked, NORMAL_DESCRIPTION_LIMIT);
424
+ }
425
+ export function capDescription(hit, limit) {
426
+ if (typeof hit.description !== "string")
427
+ return hit;
428
+ return { ...hit, description: truncateDescription(hit.description, limit) };
429
+ }
430
+ export function truncateDescription(description, limit) {
431
+ const normalized = description.replace(/\s+/g, " ").trim();
432
+ if (normalized.length <= limit)
433
+ return normalized;
434
+ const truncated = normalized.slice(0, limit - 1);
435
+ const lastSpace = truncated.lastIndexOf(" ");
436
+ const safe = lastSpace >= Math.floor(limit * 0.6) ? truncated.slice(0, lastSpace) : truncated;
437
+ return `${safe.trimEnd()}...`;
438
+ }
439
+ export function shapeShowOutput(result, detail, forAgent = false) {
440
+ if (forAgent) {
441
+ return pickFields(result, [
442
+ "type",
443
+ "name",
444
+ "description",
445
+ "action",
446
+ "content",
447
+ "template",
448
+ "prompt",
449
+ "run",
450
+ "setup",
451
+ "cwd",
452
+ "toolPolicy",
453
+ "modelHint",
454
+ "agent",
455
+ "parameters",
456
+ "workflowTitle",
457
+ "workflowParameters",
458
+ "steps",
459
+ "keys",
460
+ "comments",
461
+ ]);
462
+ }
463
+ if (detail === "summary") {
464
+ return pickFields(result, [
465
+ "type",
466
+ "name",
467
+ "description",
468
+ "tags",
469
+ "parameters",
470
+ "workflowTitle",
471
+ "action",
472
+ "run",
473
+ "origin",
474
+ "keys",
475
+ "comments",
476
+ ]);
477
+ }
478
+ const base = pickFields(result, [
479
+ "type",
480
+ "name",
481
+ "origin",
482
+ "action",
483
+ "description",
484
+ "tags",
485
+ "content",
486
+ "template",
487
+ "prompt",
488
+ "toolPolicy",
489
+ "modelHint",
490
+ "agent",
491
+ "parameters",
492
+ "workflowTitle",
493
+ "workflowParameters",
494
+ "steps",
495
+ "run",
496
+ "setup",
497
+ "cwd",
498
+ "keys",
499
+ "comments",
500
+ // path and editable are always projected so JSON consumers can locate and
501
+ // edit the asset without needing --detail full (QA #7).
502
+ "path",
503
+ "editable",
504
+ ]);
505
+ if (detail !== "full") {
506
+ return base;
507
+ }
508
+ return {
509
+ schemaVersion: 1,
510
+ ...base,
511
+ ...pickFields(result, ["editHint"]),
512
+ };
513
+ }
514
+ export function pickFields(source, fields) {
515
+ const result = {};
516
+ for (const field of fields) {
517
+ if (source[field] !== undefined) {
518
+ result[field] = source[field];
519
+ }
520
+ }
521
+ return result;
522
+ }
523
+ export { NORMAL_DESCRIPTION_LIMIT };