akm-cli 0.9.0-rc.8 → 0.9.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 (450) hide show
  1. package/CHANGELOG.md +1063 -44
  2. package/README.md +51 -25
  3. package/SECURITY.md +14 -1
  4. package/STABILITY.md +497 -0
  5. package/dist/akm +148 -35
  6. package/dist/{akm-migrate-storage → akm-migrate} +6 -9
  7. package/dist/assets/hints/cli-hints-full.md +223 -95
  8. package/dist/assets/hints/cli-hints-short.md +85 -22
  9. package/dist/assets/improve-strategies/default.json +1 -1
  10. package/dist/assets/improve-strategies/reflect-distill.json +1 -1
  11. package/dist/assets/prompts/memory-infer-user.md +2 -3
  12. package/dist/assets/stash-skeleton/README.md +6 -5
  13. package/dist/assets/stash-skeleton/facts/conventions/assets/agent.md +2 -0
  14. package/dist/assets/stash-skeleton/facts/conventions/assets/command.md +2 -0
  15. package/dist/assets/stash-skeleton/facts/conventions/assets/fact.md +2 -0
  16. package/dist/assets/stash-skeleton/facts/conventions/assets/knowledge.md +2 -0
  17. package/dist/assets/stash-skeleton/facts/conventions/assets/lesson.md +2 -0
  18. package/dist/assets/stash-skeleton/facts/conventions/assets/memory.md +2 -0
  19. package/dist/assets/stash-skeleton/facts/conventions/assets/script.md +2 -0
  20. package/dist/assets/stash-skeleton/facts/conventions/assets/skill.md +2 -0
  21. package/dist/assets/stash-skeleton/facts/conventions/assets/workflow.md +2 -0
  22. package/dist/assets/stash-skeleton/facts/conventions/backlinks.md +2 -0
  23. package/dist/assets/stash-skeleton/facts/conventions/domains.md +2 -0
  24. package/dist/assets/stash-skeleton/facts/conventions/organization.md +20 -9
  25. package/dist/assets/tasks/core/extract.yml +1 -1
  26. package/dist/assets/tasks/core/version-check.yml +1 -1
  27. package/dist/assets/tasks/improve/akm-graph-refresh-weekly.yml +5 -0
  28. package/dist/assets/tasks/improve/akm-improve-catchup.yml +8 -0
  29. package/dist/assets/tasks/improve/akm-improve-consolidate.yml +5 -0
  30. package/dist/assets/tasks/improve/akm-improve-frequent.yml +5 -0
  31. package/dist/assets/tasks/improve/akm-improve-nightly.yml +5 -0
  32. package/dist/assets/templates/html/health.html +1 -3
  33. package/dist/assets/workflows/workflow-template.md +32 -15
  34. package/dist/cli/invocation.js +40 -15
  35. package/dist/cli/parse-args.js +0 -22
  36. package/dist/cli/retired-commands.js +121 -0
  37. package/dist/cli/shared.js +154 -22
  38. package/dist/cli/unknown-flags.js +236 -0
  39. package/dist/cli-node.mjs +2 -1
  40. package/dist/cli.js +696 -258
  41. package/dist/commands/agent/agent-dispatch.js +14 -3
  42. package/dist/commands/agent/contribute-cli.js +73 -88
  43. package/dist/commands/completions.js +79 -22
  44. package/dist/commands/config-cli.js +17 -150
  45. package/dist/commands/env/env-cli.js +59 -143
  46. package/dist/commands/env/env.js +12 -163
  47. package/dist/commands/env/marker-path.js +6 -0
  48. package/dist/commands/env/secret-cli.js +36 -66
  49. package/dist/commands/env/secret.js +24 -57
  50. package/dist/commands/feedback-cli.js +141 -87
  51. package/dist/commands/health/accept-rate.js +58 -0
  52. package/dist/commands/health/advisories.js +3 -4
  53. package/dist/commands/health/checks.js +85 -23
  54. package/dist/commands/health/html-report.js +7 -10
  55. package/dist/commands/health/improve-metrics.js +25 -83
  56. package/dist/commands/health/md-report.js +5 -9
  57. package/dist/commands/health/metrics.js +62 -20
  58. package/dist/commands/health/renderers.js +47 -0
  59. package/dist/commands/health/report-view-model.js +4 -5
  60. package/dist/commands/health/stash-exposure.js +1 -1
  61. package/dist/commands/health/surfaces.js +3 -48
  62. package/dist/commands/health/task-runs.js +3 -67
  63. package/dist/commands/health/types-improve.js +7 -0
  64. package/dist/commands/health.js +99 -28
  65. package/dist/commands/improve/anti-collapse.js +2 -2
  66. package/dist/commands/improve/autonomy-gate.js +68 -0
  67. package/dist/commands/improve/collapse-detector.js +41 -40
  68. package/dist/commands/improve/consolidate/eligibility.js +1 -23
  69. package/dist/commands/improve/consolidate/merge.js +4 -0
  70. package/dist/commands/improve/consolidate.js +140 -1000
  71. package/dist/commands/improve/distill/promote-memory.js +12 -12
  72. package/dist/commands/improve/distill/quality-gate.js +6 -6
  73. package/dist/commands/improve/distill.js +58 -69
  74. package/dist/commands/improve/eligibility.js +105 -57
  75. package/dist/commands/improve/extract-cli.js +14 -133
  76. package/dist/commands/improve/improve-cli.js +98 -114
  77. package/dist/commands/improve/improve-result-file.js +1 -28
  78. package/dist/commands/improve/improve-strategies.js +8 -5
  79. package/dist/commands/improve/improve.js +128 -91
  80. package/dist/commands/improve/loop-stages.js +182 -20
  81. package/dist/commands/improve/memory/derived-ref.js +45 -43
  82. package/dist/commands/improve/memory/memory-belief.js +1 -1
  83. package/dist/commands/improve/memory/memory-contradiction-detect.js +4 -12
  84. package/dist/commands/improve/memory/memory-improve.js +6 -5
  85. package/dist/commands/improve/outcome-loop.js +22 -65
  86. package/dist/commands/improve/preparation.js +114 -123
  87. package/dist/commands/improve/proactive-maintenance.js +2 -5
  88. package/dist/commands/improve/reflect.js +56 -160
  89. package/dist/commands/improve/salience.js +11 -122
  90. package/dist/commands/improve/source-identity.js +10 -38
  91. package/dist/commands/lint/base-linter.js +20 -124
  92. package/dist/commands/lint/env-key-rules.js +31 -47
  93. package/dist/commands/lint/index.js +249 -43
  94. package/dist/commands/{events.js → log.js} +33 -38
  95. package/dist/commands/migrate-cli.js +92 -12
  96. package/dist/commands/migration-tool.js +46 -0
  97. package/dist/commands/observability-cli.js +70 -209
  98. package/dist/commands/proposal/drain.js +101 -29
  99. package/dist/commands/proposal/proposal-cli.js +76 -48
  100. package/dist/commands/proposal/proposal.js +54 -18
  101. package/dist/commands/proposal/propose-cli.js +88 -0
  102. package/dist/commands/proposal/propose.js +23 -15
  103. package/dist/commands/proposal/repository.js +701 -278
  104. package/dist/commands/proposal/validators/proposal-quality-validators.js +2 -8
  105. package/dist/commands/proposal/validators/proposal-validators.js +55 -7
  106. package/dist/commands/proposal/validators/proposals.js +4 -7
  107. package/dist/commands/read/curate.js +34 -53
  108. package/dist/commands/read/knowledge.js +150 -95
  109. package/dist/commands/read/registry-search.js +2 -2
  110. package/dist/commands/read/remember-cli.js +42 -15
  111. package/dist/commands/read/search-cli.js +180 -78
  112. package/dist/commands/read/search.js +58 -43
  113. package/dist/commands/read/show.js +197 -141
  114. package/dist/commands/registry-cli.js +12 -51
  115. package/dist/commands/remember.js +14 -57
  116. package/dist/commands/sources/add-cli.js +100 -31
  117. package/dist/commands/sources/bundle-cli.js +166 -0
  118. package/dist/commands/sources/bundle-config-ops.js +7 -2
  119. package/dist/commands/sources/info.js +18 -5
  120. package/dist/commands/sources/init.js +12 -12
  121. package/dist/commands/sources/installed-stashes.js +382 -98
  122. package/dist/commands/sources/schema-repair.js +3 -2
  123. package/dist/commands/sources/self-update.js +131 -38
  124. package/dist/commands/sources/source-add.js +72 -17
  125. package/dist/commands/sources/source-clone.js +129 -45
  126. package/dist/commands/sources/source-manage.js +43 -23
  127. package/dist/commands/sources/sources-cli.js +57 -208
  128. package/dist/commands/sources/stash-cli.js +46 -53
  129. package/dist/commands/tasks/tasks-cli.js +91 -97
  130. package/dist/commands/tasks/tasks.js +276 -421
  131. package/dist/commands/workflow-cli.js +175 -450
  132. package/dist/core/adapter/adapters/akm-adapter.js +47 -28
  133. package/dist/core/adapter/adapters/akm-lint.js +42 -27
  134. package/dist/core/adapter/adapters/akm-metadata.js +15 -44
  135. package/dist/core/adapter/adapters/akm-task-adapter.js +15 -13
  136. package/dist/core/adapter/adapters/akm-workflow-adapter.js +55 -71
  137. package/dist/core/adapter/adapters/dotenv-adapter.js +1 -1
  138. package/dist/core/adapter/adapters/generic-files-adapter.js +2 -0
  139. package/dist/core/adapter/adapters/index.js +6 -6
  140. package/dist/core/adapter/adapters/llm-wiki-adapter.js +14 -8
  141. package/dist/core/adapter/adapters/okf-adapter.js +187 -19
  142. package/dist/core/adapter/adapters/shared.js +3 -19
  143. package/dist/core/adapter/adapters/tool-dir-shared.js +8 -3
  144. package/dist/core/adapter/adapters/website-snapshot-adapter.js +1 -0
  145. package/dist/core/adapter/detect-adapter.js +17 -0
  146. package/dist/core/adapter/recognize-match.js +6 -4
  147. package/dist/core/adapter/validate-context.js +214 -0
  148. package/dist/core/asset/akm-markdown.js +63 -0
  149. package/dist/core/asset/asset-placement.js +20 -6
  150. package/dist/core/asset/asset-ref.js +11 -9
  151. package/dist/core/asset/frontmatter-lint.js +30 -0
  152. package/dist/core/asset/frontmatter.js +37 -9
  153. package/dist/core/asset/markdown.js +40 -51
  154. package/dist/core/asset/resolve-ref.js +89 -18
  155. package/dist/core/asset/stash-meta.js +1 -1
  156. package/dist/core/bundle-id.js +51 -0
  157. package/dist/core/common.js +152 -38
  158. package/dist/core/config/config-io.js +12 -1
  159. package/dist/core/config/config-schema.js +35 -8
  160. package/dist/core/config/config-sources.js +55 -11
  161. package/dist/core/config/config-walker.js +25 -9
  162. package/dist/core/config/config.js +9 -48
  163. package/dist/core/config/experimental.js +21 -0
  164. package/dist/core/config/schema/embedding.js +5 -1
  165. package/dist/core/config/schema/experimental.js +30 -0
  166. package/dist/core/config/schema/improve-processes.js +0 -6
  167. package/dist/core/config/schema/improve.js +21 -3
  168. package/dist/core/config/schema/index-config.js +8 -15
  169. package/dist/core/config/schema/output.js +4 -1
  170. package/dist/core/config/schema/setup.js +9 -18
  171. package/dist/core/config/schema/sources-bundles.js +49 -33
  172. package/dist/core/config/schema/workflow.js +3 -3
  173. package/dist/core/env-secret-ref.js +76 -46
  174. package/dist/core/errors.js +18 -12
  175. package/dist/core/events.js +46 -128
  176. package/dist/core/file-change.js +6 -5
  177. package/dist/core/fs-txn.js +83 -7
  178. package/dist/core/git-message.js +2 -2
  179. package/dist/core/improve-result.js +1 -100
  180. package/dist/core/lesson-lint.js +1 -17
  181. package/dist/core/logs-db.js +2 -1
  182. package/dist/core/migration-operation.js +16 -0
  183. package/dist/core/mutation-target.js +78 -0
  184. package/dist/core/parse.js +4 -1
  185. package/dist/core/paths.js +17 -20
  186. package/dist/core/recognition-util.js +12 -14
  187. package/dist/core/redaction.js +34 -0
  188. package/dist/core/standards/resolve-standards-context.js +2 -14
  189. package/dist/core/standards/resolve-stash-standards.js +2 -2
  190. package/dist/core/standards/resolve-type-conventions.js +2 -2
  191. package/dist/core/state/migrations.js +41 -18
  192. package/dist/core/state-db.js +5 -14
  193. package/dist/core/structured.js +1 -1
  194. package/dist/core/subprocess.js +6 -4
  195. package/dist/core/text-truncation.js +9 -5
  196. package/dist/core/type-presentation.js +3 -3
  197. package/dist/core/warn.js +0 -3
  198. package/dist/core/write-source.js +771 -95
  199. package/dist/indexer/bundle-identity-guard.js +3 -2
  200. package/dist/indexer/db/graph-db.js +0 -24
  201. package/dist/indexer/ensure-index.js +1 -0
  202. package/dist/indexer/graph/graph-boost.js +9 -34
  203. package/dist/indexer/graph/graph-extraction.js +8 -5
  204. package/dist/indexer/index-writer-lock.js +53 -17
  205. package/dist/indexer/index-written-assets.js +16 -22
  206. package/dist/indexer/indexer.js +497 -239
  207. package/dist/indexer/installations.js +14 -96
  208. package/dist/indexer/passes/dir-staleness.js +16 -9
  209. package/dist/indexer/passes/memory-inference.js +11 -9
  210. package/dist/indexer/passes/metadata.js +113 -47
  211. package/dist/indexer/scan/doc-to-entry.js +38 -1
  212. package/dist/indexer/scan/drain-dir.js +13 -23
  213. package/dist/indexer/search/db-search.js +99 -54
  214. package/dist/indexer/search/fts-query.js +47 -24
  215. package/dist/indexer/search/ranking-contributors.js +42 -20
  216. package/dist/indexer/search/ranking.js +18 -99
  217. package/dist/indexer/search/search-fields.js +7 -2
  218. package/dist/indexer/search/search-source.js +82 -93
  219. package/dist/indexer/usage/usage-events.js +0 -89
  220. package/dist/indexer/walk/file-context.js +2 -1
  221. package/dist/indexer/walk/matchers.js +30 -43
  222. package/dist/indexer/walk/path-resolver.js +7 -2
  223. package/dist/indexer/walk/walker.js +38 -12
  224. package/dist/integrations/agent/builders.js +0 -6
  225. package/dist/integrations/agent/config.js +2 -2
  226. package/dist/integrations/agent/detect.js +49 -19
  227. package/dist/integrations/agent/engine-fallback.js +76 -0
  228. package/dist/integrations/agent/profiles.js +14 -0
  229. package/dist/integrations/agent/prompts.js +12 -8
  230. package/dist/integrations/agent/runner-dispatch.js +4 -2
  231. package/dist/integrations/agent/runner.js +0 -1
  232. package/dist/integrations/agent/spawn.js +5 -6
  233. package/dist/integrations/github.js +1 -1
  234. package/dist/integrations/harnesses/aider/agent-builder.js +6 -4
  235. package/dist/integrations/harnesses/amazonq/agent-builder.js +7 -4
  236. package/dist/integrations/harnesses/claude/session-log.js +0 -10
  237. package/dist/integrations/harnesses/codex/agent-builder.js +5 -2
  238. package/dist/integrations/harnesses/copilot/agent-builder.js +5 -3
  239. package/dist/integrations/harnesses/gemini/agent-builder.js +5 -3
  240. package/dist/integrations/harnesses/index.js +3 -7
  241. package/dist/integrations/harnesses/opencode/agent-builder.js +21 -2
  242. package/dist/integrations/harnesses/opencode/session-log.js +0 -15
  243. package/dist/integrations/harnesses/opencode-sdk/sdk-runner.js +13 -4
  244. package/dist/integrations/harnesses/openhands/agent-builder.js +9 -6
  245. package/dist/integrations/harnesses/pi/agent-builder.js +6 -4
  246. package/dist/integrations/lockfile.js +101 -6
  247. package/dist/integrations/session-logs/index.js +3 -28
  248. package/dist/llm/client.js +136 -100
  249. package/dist/llm/embedders/remote.js +13 -5
  250. package/dist/llm/feature-gate.js +4 -12
  251. package/dist/llm/graph-extract.js +5 -11
  252. package/dist/llm/memory-infer.js +144 -1
  253. package/dist/llm/metadata-enhance.js +5 -7
  254. package/dist/llm/structured-call.js +1 -1
  255. package/dist/llm/usage-persist.js +26 -5
  256. package/dist/llm/usage-telemetry.js +25 -2
  257. package/dist/output/cli-hints.js +1 -2
  258. package/dist/output/context.js +22 -7
  259. package/dist/output/format-exempt.js +80 -0
  260. package/dist/output/generic-render.js +259 -0
  261. package/dist/output/render-registry.js +57 -0
  262. package/dist/output/renderers.js +14 -36
  263. package/dist/output/shapes/curate.js +10 -1
  264. package/dist/output/shapes/events.js +12 -7
  265. package/dist/output/shapes/helpers.js +56 -83
  266. package/dist/output/shapes/migrate.js +8 -0
  267. package/dist/output/shapes/passthrough.js +7 -41
  268. package/dist/output/shapes/proposal/producer.js +15 -7
  269. package/dist/output/shapes.js +2 -9
  270. package/dist/output/text/{init.js → bundle-create.js} +3 -1
  271. package/dist/output/text/bundle-show.js +7 -0
  272. package/dist/output/text/command-format.js +164 -96
  273. package/dist/output/text/env.js +1 -3
  274. package/dist/output/text/events.js +8 -7
  275. package/dist/output/text/health-format.js +103 -0
  276. package/dist/output/text/health.js +7 -0
  277. package/dist/output/text/helpers.js +10 -8
  278. package/dist/output/text/lint-format.js +43 -0
  279. package/dist/output/text/{save.js → lint.js} +2 -2
  280. package/dist/output/text/migrate.js +88 -0
  281. package/dist/output/text/proposal/producer.js +4 -2
  282. package/dist/output/text/proposal-format.js +44 -72
  283. package/dist/output/text/registry-commands.js +1 -2
  284. package/dist/output/text/show-directives.js +15 -7
  285. package/dist/output/text/status-list.js +32 -0
  286. package/dist/output/text/sync.js +5 -0
  287. package/dist/output/text/workflow-format.js +24 -203
  288. package/dist/output/text/workflow.js +1 -7
  289. package/dist/output/text.js +16 -17
  290. package/dist/registry/factory.js +4 -6
  291. package/dist/registry/origin-resolve.js +16 -27
  292. package/dist/registry/providers/skills-sh.js +3 -3
  293. package/dist/registry/providers/static-index.js +13 -23
  294. package/dist/registry/resolve.js +42 -7
  295. package/dist/registry/semver.js +34 -84
  296. package/dist/runtime.js +2 -23
  297. package/dist/scripts/akm-migrate-node.js +60290 -0
  298. package/dist/scripts/akm-migrate.js +59628 -0
  299. package/dist/setup/detect.js +42 -15
  300. package/dist/setup/registry-stash-loader.js +2 -2
  301. package/dist/setup/setup.js +236 -136
  302. package/dist/setup/steps/connection.js +7 -9
  303. package/dist/setup/steps/platforms.js +9 -9
  304. package/dist/setup/steps/semantic.js +15 -3
  305. package/dist/setup/steps/sources.js +12 -13
  306. package/dist/setup/steps/stashdir.js +2 -3
  307. package/dist/setup/steps/tasks.js +237 -120
  308. package/dist/sources/freshness.js +1 -1
  309. package/dist/sources/provider-factory.js +11 -17
  310. package/dist/sources/providers/filesystem.js +2 -3
  311. package/dist/sources/providers/git-install.js +278 -34
  312. package/dist/sources/providers/git-provider.js +25 -23
  313. package/dist/sources/providers/git-stash.js +395 -106
  314. package/dist/sources/providers/git.js +2 -2
  315. package/dist/sources/providers/npm.js +16 -19
  316. package/dist/sources/providers/provider-utils.js +7 -4
  317. package/dist/sources/providers/sync-from-ref.js +3 -9
  318. package/dist/sources/providers/website.js +6 -1
  319. package/dist/sources/resolve.js +6 -5
  320. package/dist/sources/snapshot-fetchers/bluesky.js +146 -0
  321. package/dist/sources/snapshot-fetchers/content-extract.js +566 -0
  322. package/dist/sources/snapshot-fetchers/fetcher-util.js +41 -0
  323. package/dist/sources/snapshot-fetchers/github.js +100 -0
  324. package/dist/sources/snapshot-fetchers/host-guard.js +291 -0
  325. package/dist/sources/snapshot-fetchers/registry.js +17 -1
  326. package/dist/sources/snapshot-fetchers/robots.js +348 -0
  327. package/dist/sources/snapshot-fetchers/rss.js +282 -0
  328. package/dist/sources/snapshot-fetchers/secret-seam.js +42 -0
  329. package/dist/sources/snapshot-fetchers/website-ingest.js +566 -268
  330. package/dist/sources/snapshot-fetchers/x.js +910 -0
  331. package/dist/storage/database.js +7 -0
  332. package/dist/storage/engines/sqlite-migrations.js +23 -111
  333. package/dist/storage/managed-db.js +2 -2
  334. package/dist/storage/repositories/canaries-repository.js +1 -1
  335. package/dist/storage/repositories/events-repository.js +27 -11
  336. package/dist/storage/repositories/improve-runs-repository.js +6 -12
  337. package/dist/storage/repositories/index-connection.js +17 -6
  338. package/dist/storage/repositories/index-entries-repository.js +151 -240
  339. package/dist/storage/repositories/index-entry-mapper.js +15 -11
  340. package/dist/storage/repositories/index-fts-repository.js +5 -2
  341. package/dist/storage/repositories/index-llm-cache-repository.js +0 -1
  342. package/dist/storage/repositories/index-meta-repository.js +2 -3
  343. package/dist/storage/repositories/index-schema.js +10 -25
  344. package/dist/storage/repositories/index-utility-repository.js +15 -28
  345. package/dist/storage/repositories/index-vec-repository.js +6 -1
  346. package/dist/storage/repositories/outcome-repository.js +119 -0
  347. package/dist/storage/repositories/proposals-repository.js +296 -59
  348. package/dist/storage/repositories/registry-cache.js +19 -0
  349. package/dist/storage/repositories/salience-repository.js +172 -0
  350. package/dist/storage/repositories/task-history-repository.js +15 -13
  351. package/dist/storage/repositories/workflow-runs-repository.js +52 -40
  352. package/dist/tasks/backends/cron.js +105 -15
  353. package/dist/tasks/backends/index.js +1 -1
  354. package/dist/tasks/backends/launchd.js +85 -38
  355. package/dist/tasks/backends/schtasks.js +135 -15
  356. package/dist/tasks/embedded.js +56 -40
  357. package/dist/tasks/parser.js +7 -157
  358. package/dist/tasks/resolve-akm-bin.js +137 -59
  359. package/dist/tasks/runner.js +79 -42
  360. package/dist/tasks/scheduler-invocation.js +220 -10
  361. package/dist/tasks/schema.js +24 -1
  362. package/dist/tasks/task-id.js +1 -3
  363. package/dist/tasks/validator.js +20 -6
  364. package/dist/workflows/authoring/authoring.js +94 -143
  365. package/dist/workflows/authoring/scope-key.js +1 -1
  366. package/dist/workflows/exec/frozen-judge.js +28 -2
  367. package/dist/workflows/exec/native-executor.js +77 -57
  368. package/dist/workflows/exec/param-secrets.js +9 -9
  369. package/dist/workflows/exec/run-workflow.js +133 -79
  370. package/dist/workflows/exec/step-work.js +219 -346
  371. package/dist/{migrate-storage-node.mjs → workflows/exec/unit-dispatch.js} +1 -5
  372. package/dist/workflows/ir/compile.js +141 -270
  373. package/dist/workflows/ir/freeze.js +40 -30
  374. package/dist/workflows/ir/params.js +135 -11
  375. package/dist/workflows/ir/plan-hash.js +1 -1
  376. package/dist/workflows/ir/schema.js +25 -26
  377. package/dist/workflows/parser.js +872 -307
  378. package/dist/workflows/program/expressions.js +20 -208
  379. package/dist/workflows/program/schema.js +7 -10
  380. package/dist/workflows/renderer.js +95 -68
  381. package/dist/workflows/resource-limits.js +2 -0
  382. package/dist/workflows/runtime/checkin.js +3 -3
  383. package/dist/workflows/runtime/plan-classifier.js +16 -75
  384. package/dist/workflows/runtime/runs.js +186 -127
  385. package/dist/workflows/runtime/unit-checkin.js +1 -1
  386. package/dist/workflows/runtime/unit-phases.js +2 -2
  387. package/dist/workflows/runtime/workflow-asset-loader.js +232 -83
  388. package/dist/workflows/schema.js +1 -11
  389. package/dist/workflows/validate-summary.js +30 -36
  390. package/dist/workflows/validator.js +21 -62
  391. package/docs/README.md +68 -0
  392. package/docs/migration/README.md +8 -0
  393. package/docs/migration/release-notes/0.7.0.md +11 -11
  394. package/docs/migration/release-notes/0.9.0.md +208 -27
  395. package/docs/migration/v0.7-to-v0.8.md +46 -47
  396. package/docs/migration/v0.8-to-v0.9.md +564 -208
  397. package/docs/migration/v0.9.0-troubleshooting.md +561 -0
  398. package/docs/reference/README.md +12 -0
  399. package/docs/reference/cli.md +2253 -0
  400. package/docs/reference/configuration.md +358 -0
  401. package/docs/reference/data-and-telemetry.md +105 -42
  402. package/docs/reference/workflows.md +647 -0
  403. package/package.json +22 -11
  404. package/schemas/akm-asset-envelope.json +93 -0
  405. package/schemas/akm-config.json +81 -128
  406. package/schemas/akm-workflow.json +74 -73
  407. package/dist/assets/tasks/core/backup.yml +0 -5
  408. package/dist/assets/tasks/graph-refresh-weekly.yml +0 -10
  409. package/dist/cli/config-migrate.js +0 -1806
  410. package/dist/cli/config-validate.js +0 -41
  411. package/dist/commands/backup-cli.js +0 -56
  412. package/dist/commands/bundle/bundle-cli.js +0 -68
  413. package/dist/commands/bundle/bundle.js +0 -219
  414. package/dist/commands/graph/graph-cli.js +0 -124
  415. package/dist/commands/graph/graph.js +0 -489
  416. package/dist/commands/improve/extract-watch.js +0 -140
  417. package/dist/commands/mv-cli.js +0 -1221
  418. package/dist/commands/sources/history.js +0 -201
  419. package/dist/commands/tasks/default-tasks.js +0 -186
  420. package/dist/core/migration-backup.js +0 -1234
  421. package/dist/indexer/usage/unmigrated-vaults-guard.js +0 -95
  422. package/dist/llm/memory-infer-impl.js +0 -138
  423. package/dist/migrate/legacy/config-source-migration.js +0 -223
  424. package/dist/migrate/legacy/content-migration.js +0 -305
  425. package/dist/migrate/legacy/legacy-layout.js +0 -779
  426. package/dist/migrate/legacy/legacy-paths.js +0 -25
  427. package/dist/migrate/legacy/legacy-stash-json.js +0 -72
  428. package/dist/migrate/legacy/proposal-fs-import.js +0 -168
  429. package/dist/migrate/legacy/task-target-ref-migration.js +0 -272
  430. package/dist/migrate/legacy/three-db-cutover.js +0 -841
  431. package/dist/migrate/legacy/workflow-migrations-bodies.js +0 -52
  432. package/dist/migrate/legacy/workflow-migrations-frozen.js +0 -21
  433. package/dist/migrate/legacy-ref-grammar.js +0 -214
  434. package/dist/output/shapes/distill.js +0 -14
  435. package/dist/output/shapes/history.js +0 -11
  436. package/dist/output/text/distill.js +0 -6
  437. package/dist/output/text/enable-disable.js +0 -8
  438. package/dist/output/text/history.js +0 -6
  439. package/dist/registry/build-index.js +0 -382
  440. package/dist/schemas/akm-config.json +0 -4704
  441. package/dist/schemas/akm-task.json +0 -87
  442. package/dist/schemas/akm-workflow.json +0 -372
  443. package/dist/scripts/migrate-storage.js +0 -3816
  444. package/dist/workflows/authoring/workflow-program-template.yaml +0 -31
  445. package/dist/workflows/cli.js +0 -53
  446. package/dist/workflows/exec/brief.js +0 -481
  447. package/dist/workflows/exec/report.js +0 -1460
  448. package/dist/workflows/exec/watch.js +0 -116
  449. package/dist/workflows/program/parser.js +0 -813
  450. package/dist/workflows/program/project.js +0 -104
@@ -8,7 +8,6 @@
8
8
  * main CLI file focused on command definitions and routing.
9
9
  */
10
10
  import { UsageError } from "../core/errors.js";
11
- import { warn } from "../core/warn.js";
12
11
  // findCittyTopLevelCommand(Index) + CittyArg(s)DefinitionForScan moved to
13
12
  // ./invocation (chunk-9 WI-9.9 argv-normalization fold — that cluster had no
14
13
  // internal imports, so it relocated cleanly); re-exported here so existing
@@ -73,27 +72,6 @@ export function parseNonNegativeIntFlag(raw, flagName) {
73
72
  }
74
73
  return parseInt(trimmed, 10);
75
74
  }
76
- // ── Auto-accept flag parsing (deprecated) ───────────────────────────────────
77
- /**
78
- * DEPRECATED (0.9.0): `akm improve --auto-accept` is accepted but ignored.
79
- *
80
- * The confidence gate the flag configured was deleted in 0.9.0 — proposals
81
- * now queue for review (`akm proposal` / the drain engine) instead of being
82
- * auto-promoted by threshold. The flag warns-and-ignores for one minor
83
- * because installed crontabs embed the old command line; a hard parse error
84
- * would make scheduled background runs fail invisibly after upgrade. Hard
85
- * removal in 0.10.
86
- *
87
- * - `undefined` (flag absent) → silent no-op.
88
- * - Any present value (bare flag, `safe`, `false`, a number, garbage) →
89
- * one deprecation warning on stderr; never throws.
90
- */
91
- export function parseAutoAcceptFlag(raw) {
92
- if (raw === undefined)
93
- return;
94
- warn("[improve] --auto-accept is deprecated and ignored (the 0.9.0 confidence gate was removed; " +
95
- "proposals queue for review via `akm proposal` or the drain engine). The flag will be removed in 0.10.");
96
- }
97
75
  // ── String flag parsing ──────────────────────────────────────────────────────
98
76
  /**
99
77
  * Extract a string value from a parsed citty argument object by key.
@@ -0,0 +1,121 @@
1
+ // This Source Code Form is subject to the terms of the Mozilla Public
2
+ // License, v. 2.0. If a copy of the MPL was not distributed with this
3
+ // file, You can obtain one at https://mozilla.org/MPL/2.0/.
4
+ /**
5
+ * Replacement hints for command spellings retired by the 0.9 CLI overhaul
6
+ * (hard break — no aliases). Consulted by the unknown-command error path
7
+ * BEFORE the edit-distance did-you-mean: distance-based suggestions are
8
+ * actively misleading for retired spellings (`init` → "did you mean
9
+ * `info`?", `update` → "did you mean `upgrade`?" — the latter replaces the
10
+ * BINARY, not the sources), and an agent following them gets steered into
11
+ * the wrong command instead of the renamed one.
12
+ *
13
+ * Keys are either a bare retired top-level token (`"init"`) or a
14
+ * group-scoped `"<group> <sub>"` pair (`"env set"`). Keep entries one
15
+ * sentence; the migration pointer is appended by the caller.
16
+ */
17
+ const RETIRED_COMMAND_HINTS = {
18
+ // Top-level verbs absorbed by the `bundle` group.
19
+ init: "`akm init` moved in 0.9 — use `akm bundle create`.",
20
+ add: "`akm add` moved in 0.9 — use `akm bundle add <source>`.",
21
+ list: "`akm list` moved in 0.9 — use `akm bundle list`.",
22
+ remove: "`akm remove` moved in 0.9 — use `akm bundle remove <source>`.",
23
+ update: "`akm update` moved in 0.9 — use `akm bundle update` (to update akm itself, use `akm upgrade`).",
24
+ // Group renamed to the singular.
25
+ tasks: "the `tasks` group was renamed in 0.9 — use `akm task <subcommand>`.",
26
+ // Verbs absorbed by the `proposal` group.
27
+ extract: "`akm extract` moved in 0.9 — use `akm proposal extract`.",
28
+ propose: "`akm propose` moved in 0.9 — use `akm proposal new`.",
29
+ proposals: "`akm proposals` moved in 0.9 — use `akm proposal list`.",
30
+ accept: "`akm accept` moved in 0.9 — use `akm proposal accept <id>`.",
31
+ reject: '`akm reject` moved in 0.9 — use `akm proposal reject <id> --reason "..."`.',
32
+ diff: "`akm diff` moved in 0.9 — use `akm proposal diff <id>`.",
33
+ revert: "`akm revert` moved in 0.9 — use `akm proposal revert <id>`.",
34
+ reflect: "`akm reflect` was folded into 0.9 — use `akm improve <ref>`.",
35
+ distill: "`akm distill` was folded into 0.9 — use `akm improve <ref>`.",
36
+ // Renamed persistence and observability verbs.
37
+ save: "`akm save` moved in 0.9 — use `akm sync`.",
38
+ events: "`akm events` moved in 0.9 — use `akm log`.",
39
+ // Removed observability surfaces.
40
+ history: "`akm history` was removed in 0.9 — use `akm log --ref <ref>` for an asset's event trail.",
41
+ graph: "`akm graph` was removed in 0.9 — graph counts appear in `akm health`; refresh extraction with `akm improve --strategy graph-refresh`.",
42
+ lessons: "`akm lessons` was removed in 0.9 — lesson strength is indexed; use `akm search --type lesson`.",
43
+ lesson: "`akm lesson` was removed in 0.9 — lesson strength is indexed; use `akm search --type lesson`.",
44
+ // Relocated guidance / removed asset verbs.
45
+ mv: "`akm mv` was removed in 0.9 — move the file, then run `akm index` and `akm lint` (to carry ranking signal: `bun scripts/rekey-asset-ref.ts <old-ref> <new-ref>`).",
46
+ // Pre-0.9 removals agents still trip over.
47
+ wiki: "the `akm wiki` family was removed in 0.9 — wikis are ordinary knowledge assets; ingest with `akm import <url> --path <subdir>`.",
48
+ backup: "`akm backup` was removed in 0.9 — backups belong to the standalone `akm-migrate backup` tool.",
49
+ vault: "the `akm vault ...` family was removed in 0.9 — use `akm env list`/`akm env create` for a whole `.env` group, or `akm secret set <name>` for a single sensitive value.",
50
+ // Group-scoped retirements.
51
+ "env set": "`akm env set` was removed in 0.9 — edit the `.env` file directly; akm loads it as-is.",
52
+ "env unset": "`akm env unset` was removed in 0.9 — edit the `.env` file directly; akm loads it as-is.",
53
+ "registry search": "`akm registry search` was folded into `akm search --from registry` in 0.9.",
54
+ "registry build-index": "`akm registry build-index` moved in 0.9 — maintainers run `bun scripts/build-registry-index.ts`.",
55
+ "workflow template": "`akm workflow template` was folded into `akm workflow create --print` in 0.9.",
56
+ "workflow validate": "`akm workflow validate` was folded into `akm lint --type workflows` in 0.9 (add `--fail-on-flagged` for CI gates).",
57
+ "workflow watch": "`akm workflow watch` was removed in 0.9 — use `akm log --run <run-id>`.",
58
+ "workflow start": "`akm workflow start` was removed in 0.9 — use `akm workflow run <ref>`.",
59
+ "workflow next": "`akm workflow next` was removed in 0.9 — use `akm workflow status <target>` to inspect or `akm workflow run <target>` to execute.",
60
+ "workflow complete": "`akm workflow complete` was removed in 0.9 — `akm workflow run <target>` completes steps automatically; use `akm workflow status <target>` to inspect.",
61
+ "workflow brief": "`akm workflow brief` was removed — the external-driver protocol is gone; `akm workflow run <target>` executes the run and `akm workflow status <target>` inspects it.",
62
+ "workflow report": "`akm workflow report` was removed — the external-driver protocol is gone; `akm workflow run <target>` dispatches and records units itself.",
63
+ "config show": "`akm config show` was removed in 0.9 — use `akm config list`.",
64
+ "config validate": "`akm config validate` was removed in 0.9 — the config file is validated on every load.",
65
+ "task enable": "`akm task enable` was removed in 0.9 — set `enabled: true` in the task YAML, then `akm task sync`.",
66
+ "task disable": "`akm task disable` was removed in 0.9 — set `enabled: false` in the task YAML, then `akm task sync`.",
67
+ "task init": "`akm task init` was removed in 0.9 — `akm setup` seeds the default schedules.",
68
+ "task list": "there is no `task list` — task files are indexed assets; use `akm search --type task`.",
69
+ "task show": "there is no `task show` — task files are indexed assets; use `akm show <ref>`.",
70
+ "task remove": "there is no `task remove` — delete the task YAML, then run `akm task sync` to unbind it.",
71
+ // `improve canary` is NOT here: `akm improve` is a leaf command (a
72
+ // positional `ref`, not a subcommand group), so "canary" never reaches the
73
+ // unknown-command path this table serves — `improve-cli.ts` already
74
+ // self-diagnoses it with a more specific, correct message before this
75
+ // table would ever be consulted.
76
+ "log tail": "`akm log tail` was removed in 0.9 — poll `akm log --since @offset:<id>` (the durable cursor).",
77
+ "log list": "`akm log list` was flattened in 0.9 — bare `akm log` is the same surface.",
78
+ };
79
+ const MIGRATION_POINTER = "Full rename table: `akm help migrate 0.9.0`.";
80
+ /**
81
+ * Replacement hint for a retired spelling, or undefined when the attempted
82
+ * token isn't a known retirement. `parentPath` is the group path already
83
+ * resolved before the unknown token (empty at root), so `env set` and a
84
+ * hypothetical top-level `set` can't collide.
85
+ */
86
+ export function retiredCommandHint(parentPath, attempted) {
87
+ const key = parentPath.length === 0 ? attempted : `${parentPath[parentPath.length - 1]} ${attempted}`;
88
+ const entry = RETIRED_COMMAND_HINTS[key];
89
+ return entry === undefined ? undefined : `${entry} ${MIGRATION_POINTER}`;
90
+ }
91
+ /**
92
+ * Same idea as {@link RETIRED_COMMAND_HINTS}, but for FLAGS the 0.9 overhaul
93
+ * removed outright rather than commands. Consulted by
94
+ * `src/cli/unknown-flags.ts` BEFORE its own edit-distance did-you-mean, for
95
+ * the same reason: a distance-based suggestion on a retired flag can point at
96
+ * an unrelated survivor rather than the real replacement procedure.
97
+ *
98
+ * Keys are the FULL resolved command path joined with spaces, plus the flag
99
+ * exactly as the unknown-flag scanner reports it (leading dashes, long form
100
+ * only — `--background`, not `-b`): `"<cmd> [sub...] --flag"`. The command
101
+ * path is whatever `unknown-flags.ts`'s `KnownArgs.path` resolved (e.g.
102
+ * `["proposal", "extract"]` for the flag's CURRENT location, not any retired
103
+ * top-level spelling — that command-level retirement is already handled by
104
+ * {@link retiredCommandHint} before flag scanning ever runs).
105
+ */
106
+ const RETIRED_FLAG_HINTS = {
107
+ "index --background": "`--background` was removed in 0.9 — the flag never actually backgrounded; use `--quiet`.",
108
+ "setup --detect-only": "`--detect-only` was removed in 0.9 — environment detection runs inside `akm setup`; `akm info` reports the configured capabilities.",
109
+ "setup --reset-recommended": "`--reset-recommended` was removed in 0.9 — `akm setup` now offers to apply recommended defaults interactively.",
110
+ "proposal extract --watch": "`--watch` was removed in 0.9 — schedule `akm proposal extract --auto` as a task instead.",
111
+ "proposal extract --debounce-ms": "`--debounce-ms` was removed in 0.9 — schedule `akm proposal extract --auto` as a task instead.",
112
+ };
113
+ /**
114
+ * Replacement hint for a retired flag on its current command path, or
115
+ * undefined when the attempted spelling isn't a known retirement.
116
+ */
117
+ export function retiredFlagHint(path, attempted) {
118
+ const key = `${path.join(" ")} ${attempted}`;
119
+ const entry = RETIRED_FLAG_HINTS[key];
120
+ return entry === undefined ? undefined : `${entry} ${MIGRATION_POINTER}`;
121
+ }
@@ -12,7 +12,9 @@ import { stringify as yamlStringify } from "yaml";
12
12
  import { assertNever } from "../core/assert.js";
13
13
  import { AkmError, UsageError } from "../core/errors.js";
14
14
  import { getOutputMode } from "../output/context.js";
15
+ import { renderGenericHtml, renderGenericMarkdown, renderGenericText } from "../output/generic-render.js";
15
16
  import { deliverRendered } from "../output/html-render.js";
17
+ import { getHtmlRendererHandler, getMdRendererHandler } from "../output/render-registry.js";
16
18
  import { shapeForCommand } from "../output/shapes.js";
17
19
  import { formatPlain, outputJsonl } from "../output/text.js";
18
20
  import { parseAllFlagValues } from "./invocation.js";
@@ -73,8 +75,26 @@ function extractHint(error) {
73
75
  return undefined;
74
76
  }
75
77
  /**
76
- * Serialize an error to the standard JSON envelope and exit.
77
- * Used in both the startup try/catch and `runWithJsonErrors`.
78
+ * Serialize an error to the standard JSON envelope and record the mapped
79
+ * exit code. Used in both the startup try/catch and `runWithJsonErrors`.
80
+ *
81
+ * R-067: this used to call `process.exit(exitCode)` directly, which
82
+ * terminates the process synchronously and skips every pending `finally`
83
+ * block up the call stack — including `src/cli.ts`'s own
84
+ * `disposeDispatchResources()` cleanup and citty's per-command `cleanup`
85
+ * hooks. `process.exitCode = exitCode; return;` is equivalent for every
86
+ * caller here: Node/Bun exits with that code once the event loop drains
87
+ * naturally, but cleanup on the way there still runs.
88
+ * `src/commands/improve/extract-cli.ts` already uses this exact pattern for
89
+ * its own non-throw failure signal.
90
+ *
91
+ * Because this no longer throws or exits, it no longer terminates control
92
+ * flow on its own — every call site MUST treat it like a normal return and
93
+ * stop doing further work itself (an explicit `return;` right after the
94
+ * call, same as any other caller of a fallible function). `runWithJsonErrors`
95
+ * below satisfies this for free (this call is its catch block's last
96
+ * statement); `src/cli.ts`'s three direct call sites add the `return;`
97
+ * explicitly.
78
98
  */
79
99
  export function emitJsonError(error) {
80
100
  const message = error instanceof Error ? error.message : String(error);
@@ -84,7 +104,7 @@ export function emitJsonError(error) {
84
104
  // internal errors have none.
85
105
  const code = error instanceof AkmError ? error.code : undefined;
86
106
  console.error(JSON.stringify({ ok: false, error: message, ...(code ? { code } : {}), hint }, null, 2));
87
- process.exit(exitCode);
107
+ process.exitCode = exitCode;
88
108
  }
89
109
  /**
90
110
  * Run an async function and route any thrown error through the standard JSON
@@ -98,25 +118,126 @@ export async function runWithJsonErrors(fn) {
98
118
  emitJsonError(error);
99
119
  }
100
120
  }
121
+ /**
122
+ * The global output flags, redeclared on every leaf command.
123
+ *
124
+ * citty parses each command level against only that command's own args, so a
125
+ * flag declared on the root command is UNKNOWN at the leaf — and an unknown
126
+ * flag does not consume its space-separated value, which then falls through as
127
+ * a positional. `akm sync --format json` once synced a bundle named "json",
128
+ * and `akm env unset env:x KEY --format json` once tried to unset a key named
129
+ * "json"; both grew bespoke argv-inspection workarounds. Declaring the flags
130
+ * at the leaf lets the parser consume the value, which is the root-cause fix.
131
+ *
132
+ * These declarations exist for PARSING only. The output mode is still read
133
+ * exactly once, from the invocation singleton at startup — no command body may
134
+ * read these args (that is the same one-parse rule `cli/invocation.ts`
135
+ * documents).
136
+ *
137
+ * These are also the canonical descriptions for the root command's own args
138
+ * (`main.args` in src/cli.ts) — the root spreads this same object rather than
139
+ * redeclaring the text, so root help and leaf help can never drift apart.
140
+ * `format`/`detail` need per-site `default` overrides (root has one, leaves
141
+ * don't — see the one-parse rule above), so those two keys get shallow
142
+ * overrides at the root; the description text itself is never duplicated.
143
+ */
144
+ export const GLOBAL_OUTPUT_ARGS = {
145
+ format: { type: "string", description: "Output format: json|jsonl|yaml|text|md|html (global flag)" },
146
+ detail: {
147
+ type: "string",
148
+ description: "Detail level (verbosity): brief|normal|full (global flag).",
149
+ },
150
+ // R-050(c): single-sourced with the root command's own `--shape` help
151
+ // (`main.args.shape` in src/cli.ts, which spreads this object) so the
152
+ // caveat is visible from every leaf's own `--help`, not only the top-level
153
+ // one. `summary` outside `show` is a hard usage error (exit 2,
154
+ // INVALID_SHAPE_VALUE), enforced at startup in src/cli.ts before any
155
+ // command body runs.
156
+ shape: {
157
+ type: "string",
158
+ description: "Output projection: human|agent|summary (global flag). 'agent' trims to agent-essential fields; " +
159
+ "'summary' is only valid on 'akm show' (a usage error, exit 2, everywhere else). Default: human.",
160
+ },
161
+ output: {
162
+ type: "string",
163
+ description: "Write rendered output to a file instead of stdout (all formats except jsonl) (global flag)",
164
+ },
165
+ // S11: surfaced at every leaf (not just the root) so `akm <command> --help`
166
+ // documents them too — they already apply globally, parsed from raw argv
167
+ // by `applyEarlyStderrFlags` in src/cli.ts before citty ever sees them, so
168
+ // declaring them here is documentation, not new parsing behavior. A
169
+ // command with its own same-named arg (e.g. `env path --quiet`) wins the
170
+ // merge in `defineJsonCommand` as usual.
171
+ quiet: {
172
+ type: "boolean",
173
+ alias: "q",
174
+ description: "Suppress non-essential stderr output (banners, spinners, progress info) (global flag). " +
175
+ "Safety-critical output is never suppressed: errors, destructive-action confirmation prompts, " +
176
+ "and auto-migration banners always appear regardless of --quiet.",
177
+ default: false,
178
+ },
179
+ verbose: {
180
+ type: "boolean",
181
+ description: "Print per-spec diagnostics to stderr (global flag; also honours AKM_VERBOSE env var).",
182
+ default: false,
183
+ },
184
+ };
101
185
  /**
102
186
  * Define a citty command whose `run` body is automatically wrapped in
103
187
  * `runWithJsonErrors`, so the handler emits a byte-identical JSON error
104
188
  * envelope (stdout/stderr/exit-code) on throw without the boilerplate. A
105
189
  * command without a `run` (a pure subcommand group) is passed through
106
190
  * unchanged.
191
+ *
192
+ * Every command defined here also accepts the {@link GLOBAL_OUTPUT_ARGS} so
193
+ * their values are parsed rather than mis-captured as positionals; a command
194
+ * declaring its own arg of the same name wins (e.g. `env path` has its own
195
+ * `quiet`).
107
196
  */
108
197
  export function defineJsonCommand(def) {
109
198
  const { run, ...rest } = def;
199
+ const withGlobals = { ...rest, args: { ...GLOBAL_OUTPUT_ARGS, ...rest.args } };
110
200
  if (!run)
111
- return defineCommand({ ...rest });
201
+ return defineCommand(withGlobals);
112
202
  return defineCommand({
113
- ...rest,
203
+ ...withGlobals,
114
204
  run: (context) => runWithJsonErrors(() => run(context)),
115
205
  });
116
206
  }
207
+ /**
208
+ * Canonical bare-group behavior (0.9.0 breaking change, owner ruling 12).
209
+ *
210
+ * Before 0.9.0 the twelve `akm <group>` command groups did three different
211
+ * things when invoked with no subcommand: some printed help and exited 1,
212
+ * some ran an implicit default action and exited 0 (e.g. bare `akm graph`
213
+ * silently rendering `graph summary`), and one already raised a structured
214
+ * usage error and exited 2. None of that is discoverable from the exit code
215
+ * alone, and a script that greps stdout for a specific default action broke
216
+ * silently the moment someone reordered subcommands.
217
+ *
218
+ * The canonical choice, applied uniformly: a bare group invocation is a
219
+ * USAGE ERROR — exit 2, the same structured JSON envelope every other usage
220
+ * mistake in this CLI produces (not citty's raw help banner, and not a
221
+ * silent default action). This matches STABILITY.md's documented exit-code
222
+ * table (2 = usage) and the exit code the CLI already used for "unknown
223
+ * command" / "missing required argument" as of the companion 0.9.0 fix.
224
+ *
225
+ * `defaultRun` is now OPTIONAL for exactly this reason: omitting it opts a
226
+ * group into the shared, canonical error below. Passing an explicit
227
+ * `defaultRun` is a deliberate opt-out and should not be added to new groups
228
+ * without a documented reason — see CHANGELOG for the migration note.
229
+ */
230
+ function bareGroupUsageError(meta, subcommandSet) {
231
+ const name = typeof meta === "object" && meta !== null && "name" in meta && typeof meta.name === "string"
232
+ ? meta.name
233
+ : undefined;
234
+ const usage = name ? `\`akm ${name}\`` : "This command";
235
+ const subcommands = [...subcommandSet].sort().join(", ");
236
+ throw new UsageError(`${usage} requires a subcommand. Available: ${subcommands}.`, "MISSING_REQUIRED_ARGUMENT", `Run \`akm ${name ?? "<command>"} --help\` to see usage for each subcommand.`);
237
+ }
117
238
  /**
118
239
  * Define a citty subcommand-group command (env, secret, proposal, tasks, wiki,
119
- * graph, …) that shares one wiring shape: a `subCommands` map, a routing set
240
+ * …) that shares one wiring shape: a `subCommands` map, a routing set
120
241
  * DERIVED from that map's keys (so the set can never silently desync from the
121
242
  * registered subcommands), and a default body that fires ONLY for the bare
122
243
  * group invocation — citty still runs the group body after dispatching a
@@ -130,6 +251,7 @@ export function defineJsonCommand(def) {
130
251
  */
131
252
  export function defineGroupCommand(def) {
132
253
  const subcommandSet = new Set(Object.keys(def.subCommands));
254
+ const defaultRun = def.defaultRun ?? (() => bareGroupUsageError(def.meta, subcommandSet));
133
255
  return defineCommand({
134
256
  meta: def.meta,
135
257
  ...(def.args ? { args: def.args } : {}),
@@ -137,7 +259,7 @@ export function defineGroupCommand(def) {
137
259
  run: (context) => runWithJsonErrors(() => {
138
260
  if (hasSubcommand(context.args, subcommandSet))
139
261
  return;
140
- return def.defaultRun(context);
262
+ return defaultRun(context);
141
263
  }),
142
264
  });
143
265
  }
@@ -162,25 +284,35 @@ export function output(command, result) {
162
284
  deliverRendered(yamlStringify(shaped), mode.outputPath);
163
285
  return;
164
286
  case "text": {
287
+ // D7 — registry first, generic rendering of the shaped envelope second.
288
+ // Mirrors the md/html fallback immediately below: a command with no
289
+ // registered text formatter used to fall through to
290
+ // `JSON.stringify(shaped, null, 2)`, i.e. silently hand back JSON while
291
+ // claiming `--format text` — the same "wrong format wearing the right
292
+ // flag" bug D7 already closed for md/html. `renderGenericText` (a
293
+ // DISTINCT function from `renderGenericMarkdown` — see its doc comment
294
+ // in src/output/generic-render.ts for why reusing the md renderer here
295
+ // was itself a version of the same bug) renders flat `key=value` text
296
+ // matching the house style already established by registered text
297
+ // formatters like `config list`.
165
298
  const plain = formatPlain(command, shaped, mode.detail);
166
- deliverRendered(plain ?? JSON.stringify(shaped, null, 2), mode.outputPath);
299
+ deliverRendered(plain ?? renderGenericText(command, shaped), mode.outputPath);
167
300
  return;
168
301
  }
169
- case "md":
170
- // `--format md` is currently only consumed by `akm health` for the
171
- // per-run / window-compare table renderings. Commands that don't
172
- // implement an md renderer fall back to the JSON envelope so
173
- // pipelines never get an empty stdout.
174
- deliverRendered(JSON.stringify(shaped, null, 2), mode.outputPath);
302
+ case "md": {
303
+ // D7 registry first, generic rendering of the shaped envelope second.
304
+ // No command emits JSON under `--format md` any more: silently handing
305
+ // back the wrong format was the worst of the three behaviours this
306
+ // replaced.
307
+ const rendered = getMdRendererHandler(command)?.(shaped, mode.detail);
308
+ deliverRendered(rendered ?? renderGenericMarkdown(command, shaped), mode.outputPath);
309
+ return;
310
+ }
311
+ case "html": {
312
+ const rendered = getHtmlRendererHandler(command)?.(shaped, mode.detail);
313
+ deliverRendered(rendered ?? renderGenericHtml(command, shaped), mode.outputPath);
175
314
  return;
176
- case "html":
177
- // `akm health` intercepts `mode.format === "html"` before reaching
178
- // output() (cli.ts, same as the `md` intercept) and renders its own
179
- // bespoke template. Every other command has no HTML surface — the
180
- // generic JSON-in-<pre> fallback template was removed (chunk-9 WI-9.4c
181
- // / Decision 4); `html` stays a valid --format value (OUTPUT_FORMATS),
182
- // it just only resolves for health.
183
- throw new UsageError("html output is only available for `akm health`", "INVALID_FLAG_VALUE");
315
+ }
184
316
  }
185
317
  }
186
318
  // parseAllFlagValues moved to ./invocation (chunk-9 WI-9.9 argv-normalization
@@ -0,0 +1,236 @@
1
+ // This Source Code Form is subject to the terms of the Mozilla Public
2
+ // License, v. 2.0. If a copy of the MPL was not distributed with this
3
+ // file, You can obtain one at https://mozilla.org/MPL/2.0/.
4
+ /**
5
+ * Reject flags the resolved command does not declare.
6
+ *
7
+ * citty (0.2.x) parses argv with `node:util`'s parseArgs in non-strict mode
8
+ * (`strict: false`), so an undeclared flag is collected into the parsed object
9
+ * and silently ignored by the handler. Nothing
10
+ * downstream noticed, so `akm lint --fail-on-flaged` (one transposed letter in
11
+ * the flag STABILITY.md documents as a CI contract) parsed fine, exited 0, and
12
+ * the gate it was meant to enforce never fired. Same for `--limt 3`, `--jsn`,
13
+ * and every other typo — the command ran with the default instead, and the user
14
+ * had no signal.
15
+ *
16
+ * This walks the same subcommand path citty resolves (via the shared scan
17
+ * helpers in `./invocation`), unions the arg definitions declared along it,
18
+ * and fails a flag that matches nothing. The union (rather than the leaf's
19
+ * args alone) is deliberate: parent-level flags may legally appear before the
20
+ * subcommand token, and a false positive here would reject a VALID invocation
21
+ * — much worse than the silence it replaces. In the same spirit, everything
22
+ * after a literal `--` is passthrough, a declared value flag's value is never
23
+ * scanned as a flag, `--no-<name>` resolves against `<name>`, and a bare `-`
24
+ * (stdin convention) and negative numbers are left alone. A subcommand invoked
25
+ * by a `meta.name` alias rather than its key takes the stand-down path (no
26
+ * validation) — conservative by design.
27
+ */
28
+ import { UsageError } from "../core/errors.js";
29
+ import { cittyComparableName, findCittyTopLevelCommandIndex, toAliasArray, } from "./invocation.js";
30
+ import { retiredFlagHint } from "./retired-commands.js";
31
+ /** Flags citty implements itself, which no command declares. */
32
+ const IMPLICIT_FLAGS = ["help", "h", "version", "v"];
33
+ /**
34
+ * Retired flags whose commands still diagnose them THEMSELVES, with a message
35
+ * that names the replacement ("`--scope` was removed, use `--filter`",
36
+ * "`--source` was renamed to `--generator`"). A generic "unknown flag" would
37
+ * preempt the better diagnosis, so these are passed through — but ONLY on the
38
+ * command path that owns the diagnostic, keyed by the resolved path. On every
39
+ * other command the same spelling is a genuine typo and still fails fast
40
+ * A retired flag is rejected everywhere else, where silently dropping it could
41
+ * run a real mutation.
42
+ *
43
+ * Shrink-only: when a command drops its bespoke diagnostic, drop the entry and
44
+ * the generic error takes over.
45
+ */
46
+ const SELF_DIAGNOSED_FLAGS = new Map(Object.entries({
47
+ show: ["akmView", "scope"], // removed view grammar; --scope points at --filter
48
+ index: ["enrich", "re-enrich"], // removed index-time enrichment flags
49
+ "proposal accept": ["source"], // renamed to --generator
50
+ "proposal reject": ["source"], // renamed to --generator
51
+ "proposal drain": ["profile"], // retired, points at --strategy
52
+ search: ["source"], // renamed to --from
53
+ curate: ["source"], // renamed to --from
54
+ remember: ["target"], // renamed to --bundle
55
+ clone: ["target"], // renamed to --bundle
56
+ improve: ["auto-accept", "target"], // retired in 0.9.0 / renamed to --bundle
57
+ "task add": ["target"], // renamed to --bundle
58
+ "task run": ["target"], // renamed to --bundle
59
+ "task history": ["target"], // renamed to --bundle
60
+ "task sync": ["target"], // renamed to --bundle
61
+ }).map(([path, flags]) => [path, new Set(flags.map(cittyComparableName))]));
62
+ /**
63
+ * Union the arg definitions declared along the resolved command path. The
64
+ * subcommand walk delegates to {@link findCittyTopLevelCommandIndex} — the
65
+ * same scan `src/cli.ts` resolves commands with — so both agree on which
66
+ * token is the subcommand name.
67
+ */
68
+ function collectKnownArgs(root, rawArgs) {
69
+ const names = new Set(IMPLICIT_FLAGS.map(cittyComparableName));
70
+ const valueFlags = new Set();
71
+ const booleanFlags = new Set();
72
+ const displayNames = [];
73
+ const path = [];
74
+ let cmd = root;
75
+ let args = rawArgs;
76
+ for (;;) {
77
+ for (const [key, def] of Object.entries(cmd.args ?? {})) {
78
+ // Positionals are not flags; including them would accept `--<positional>`.
79
+ if (def.type === "positional")
80
+ continue;
81
+ const comparable = cittyComparableName(key);
82
+ // Shared args (GLOBAL_OUTPUT_ARGS) recur at every level; suggest each once.
83
+ if (!names.has(comparable)) {
84
+ names.add(comparable);
85
+ displayNames.push(`--${key}`);
86
+ }
87
+ if (def.type === "string" || def.type === "enum")
88
+ valueFlags.add(comparable);
89
+ if (def.type === "boolean")
90
+ booleanFlags.add(comparable);
91
+ for (const alias of toAliasArray(def.alias)) {
92
+ names.add(cittyComparableName(alias));
93
+ if (def.type === "string" || def.type === "enum")
94
+ valueFlags.add(cittyComparableName(alias));
95
+ if (def.type === "boolean")
96
+ booleanFlags.add(cittyComparableName(alias));
97
+ }
98
+ }
99
+ const subCommands = cmd.subCommands;
100
+ if (!subCommands || Object.keys(subCommands).length === 0)
101
+ break;
102
+ const idx = findCittyTopLevelCommandIndex(args, (cmd.args ?? {}));
103
+ const token = idx >= 0 ? args[idx] : undefined;
104
+ // A group with no subcommand token: citty reports "no command specified".
105
+ if (token === undefined)
106
+ return { names, valueFlags, booleanFlags, displayNames, path, resolved: false };
107
+ const sub = subCommands[token];
108
+ // An unrecognized token: citty reports the unknown command, which is the
109
+ // real problem — its flags are beside the point.
110
+ if (!sub)
111
+ return { names, valueFlags, booleanFlags, displayNames, path, resolved: false };
112
+ path.push(token);
113
+ cmd = sub;
114
+ args = args.slice(idx + 1);
115
+ }
116
+ return { names, valueFlags, booleanFlags, displayNames, path, resolved: true };
117
+ }
118
+ /** Single-row-at-a-time edit-distance DP (inputs are short flag/command names). */
119
+ function editDistance(a, b) {
120
+ let previous = Array.from({ length: b.length + 1 }, (_, j) => j);
121
+ for (let i = 1; i <= a.length; i += 1) {
122
+ const current = [i];
123
+ for (let j = 1; j <= b.length; j += 1) {
124
+ const cost = a[i - 1] === b[j - 1] ? 0 : 1;
125
+ current.push(Math.min((previous[j] ?? 0) + 1, (current[j - 1] ?? 0) + 1, (previous[j - 1] ?? 0) + cost));
126
+ }
127
+ previous = current;
128
+ }
129
+ return previous[b.length] ?? 0;
130
+ }
131
+ /**
132
+ * Closest candidate within `threshold` edit distance, or undefined when
133
+ * nothing is close enough to be worth suggesting. Shared by the unknown-flag
134
+ * and unknown-command (src/cli.ts) did-you-mean paths, which pick different
135
+ * thresholds.
136
+ */
137
+ export function closestMatch(attempted, candidates, threshold) {
138
+ let best;
139
+ let bestDistance = Number.POSITIVE_INFINITY;
140
+ for (const candidate of candidates) {
141
+ const distance = editDistance(attempted, candidate);
142
+ if (distance < bestDistance) {
143
+ bestDistance = distance;
144
+ best = candidate;
145
+ }
146
+ }
147
+ return best !== undefined && bestDistance <= threshold ? best : undefined;
148
+ }
149
+ /**
150
+ * The one unknown-flag rejection, shared by the short- and long-flag scans so
151
+ * the user-facing error contract cannot drift between them. No explicit hint
152
+ * when there is no suggestion — UNKNOWN_FLAG's canned hint (core/errors.ts)
153
+ * already says to run the command with --help.
154
+ *
155
+ * @param shown The flag as the user typed it (dashes, no `=value`).
156
+ * @param attempted The spelling to edit-distance against `--long` candidates.
157
+ */
158
+ function throwUnknownFlag(shown, attempted, known) {
159
+ // Flags the 0.9 overhaul removed outright get their retirement note, not a
160
+ // did-you-mean — same reasoning as `retiredCommandHint` in src/cli.ts:
161
+ // edit distance can point at an unrelated survivor rather than the real
162
+ // replacement procedure (e.g. `index --background` is closer to no other
163
+ // `index` flag than it is to any useful suggestion).
164
+ const retired = retiredFlagHint(known.path, attempted);
165
+ if (retired) {
166
+ throw new UsageError(`Unknown flag "${shown}".`, "UNKNOWN_FLAG", retired);
167
+ }
168
+ const threshold = Math.max(2, Math.ceil(attempted.length / 3));
169
+ const suggestion = closestMatch(attempted, known.displayNames, threshold);
170
+ throw new UsageError(`Unknown flag "${shown}".`, "UNKNOWN_FLAG", suggestion
171
+ ? `Did you mean \`${suggestion}\`? Run the command with \`--help\` to see its accepted flags.`
172
+ : undefined);
173
+ }
174
+ /**
175
+ * Throw a {@link UsageError} naming the first flag the resolved command does
176
+ * not declare. Returns silently when every flag is known.
177
+ */
178
+ export function assertKnownFlags(root, rawArgs) {
179
+ const passthroughAt = rawArgs.indexOf("--");
180
+ const ownArgs = passthroughAt === -1 ? rawArgs : rawArgs.slice(0, passthroughAt);
181
+ const known = collectKnownArgs(root, rawArgs);
182
+ if (!known.resolved)
183
+ return;
184
+ const dynamicWorkflowParams = known.path.join(" ") === "workflow run";
185
+ const selfDiagnosed = SELF_DIAGNOSED_FLAGS.get(known.path.join(" "));
186
+ for (let i = 0; i < ownArgs.length; i += 1) {
187
+ const token = ownArgs[i];
188
+ // Not a flag: positional, a bare `-` (stdin), or a negative number.
189
+ if (!token.startsWith("-") || token === "-" || /^-\d/.test(token))
190
+ continue;
191
+ // Node's util.parseArgs, which citty delegates to, treats one-dash tokens
192
+ // as bundled short flags. Boolean aliases may be combined (`-qy`), while a
193
+ // string alias consumes the remainder (`-mhello`) or the following token.
194
+ // It never treats `-auto-fix` as the long `auto-fix` option.
195
+ if (!token.startsWith("--")) {
196
+ const shortFlags = token.slice(1);
197
+ for (let offset = 0; offset < shortFlags.length; offset += 1) {
198
+ const rawName = shortFlags[offset];
199
+ const candidate = cittyComparableName(rawName);
200
+ if (!known.names.has(candidate))
201
+ throwUnknownFlag(token, `-${rawName}`, known);
202
+ if (known.valueFlags.has(candidate)) {
203
+ if (offset === shortFlags.length - 1)
204
+ i += 1;
205
+ break;
206
+ }
207
+ }
208
+ continue;
209
+ }
210
+ const withoutDashes = token.replace(/^-{1,2}/, "");
211
+ const [rawName = ""] = withoutDashes.split("=", 1);
212
+ const hasInlineValue = withoutDashes.includes("=");
213
+ // `--no-foo` is citty's negation of the BOOLEAN `--foo`. Resolving it
214
+ // against a value flag would accept `--no-limit`, which citty's own `--no-`
215
+ // preprocessing force-sets to `limit: false` (no type check, before
216
+ // parseArgs runs) — a boolean reaching a string parser, i.e. an internal
217
+ // error (exit 70) instead of the usage error (exit 2) this is here to give.
218
+ const negated = rawName.startsWith("no-") && known.booleanFlags.has(cittyComparableName(rawName.slice(3)))
219
+ ? rawName.slice(3)
220
+ : undefined;
221
+ const candidates = [cittyComparableName(rawName), ...(negated ? [cittyComparableName(negated)] : [])];
222
+ if (selfDiagnosed !== undefined && candidates.some((name) => selfDiagnosed.has(name)))
223
+ continue;
224
+ if (!candidates.some((name) => known.names.has(name))) {
225
+ // `workflow run` owns one deliberately dynamic namespace: long options
226
+ // become exact-name workflow parameters and are checked against the
227
+ // frozen plan before a run is inserted. Short flags remain strict.
228
+ if (dynamicWorkflowParams)
229
+ continue;
230
+ throwUnknownFlag(token.split("=")[0], `--${rawName}`, known);
231
+ }
232
+ // Skip a declared value flag's value so `--reason "--x"` is not scanned.
233
+ if (!hasInlineValue && candidates.some((name) => known.valueFlags.has(name)))
234
+ i += 1;
235
+ }
236
+ }
package/dist/cli-node.mjs CHANGED
@@ -20,7 +20,8 @@ import { register } from "node:module";
20
20
  register("./text-import-hook.mjs", import.meta.url);
21
21
 
22
22
  // cli.js gates its startup block on `import.meta.main`, which is false when we
23
- // `import()` it here. Opt in explicitly so the CLI actually runs `runMain`.
23
+ // `import()` it here. Opt in explicitly so the CLI actually runs its startup
24
+ // block (dispatch, `runCli`).
24
25
  process.env.AKM_NODE_ENTRY = "1";
25
26
 
26
27
  await import("./cli.js");