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,12 @@
8
8
  * migrated to `defineJsonCommand`, which wraps the body in `runWithJsonErrors`
9
9
  * and emits the same JSON envelope (stdout/stderr/exit-code) as the inline
10
10
  * `runWithJsonErrors` form it replaces.
11
+ *
12
+ * 0.9 CLI overhaul (S8): the former top-level `extract` and `propose`
13
+ * commands are absorbed here as `extract` and `new` — no top-level
14
+ * registration remains for either spelling.
11
15
  */
16
+ import { getParsedInvocation } from "../../cli/invocation.js";
12
17
  import { parsePositiveIntFlag } from "../../cli/parse-args.js";
13
18
  import { defineGroupCommand, defineJsonCommand, output } from "../../cli/shared.js";
14
19
  import { resolveStashDir } from "../../core/common.js";
@@ -17,10 +22,26 @@ import { UsageError } from "../../core/errors.js";
17
22
  import { resolveTriageJudgmentRunner } from "../../integrations/agent/runner.js";
18
23
  import { installLlmUsagePersistenceIfAbsent } from "../../llm/usage-persist.js";
19
24
  import { withLlmStage } from "../../llm/usage-telemetry.js";
25
+ import { extractCommand } from "../improve/extract-cli.js";
20
26
  import { resolveImproveStrategy } from "../improve/improve-strategies.js";
21
27
  import { drainProposals } from "./drain.js";
22
28
  import { resolveDrainPolicy } from "./drain-policies.js";
23
29
  import { akmProposalAccept, akmProposalDiff, akmProposalList, akmProposalReject, akmProposalRevert, akmProposalShow, bulkAdjudicateProposals, } from "./proposal.js";
30
+ import { proposeCommand } from "./propose-cli.js";
31
+ /**
32
+ * `--source` was renamed to `--generator` on `proposal accept`/`proposal
33
+ * reject` in 0.9 (WS3/S8 — "Removed in 0.9.0"). citty is non-strict, so the
34
+ * retired spelling is silently absorbed rather than rejected — a bulk
35
+ * accept/reject invoked with `--source <name>` then has neither `--generator`
36
+ * nor a positional id, and falls through to the single-proposal path, which
37
+ * throws MISSING_REQUIRED_ARGUMENT instead of running the bulk action the
38
+ * caller asked for. Reject it explicitly instead.
39
+ */
40
+ function rejectRetiredProposalSourceFlag(subcommand) {
41
+ if (!getParsedInvocation().hasFlag("--source"))
42
+ return;
43
+ throw new UsageError(`\`akm proposal ${subcommand} --source\` was renamed to \`--generator\` in 0.9. Use \`--generator <name>\` instead.`, "INVALID_FLAG_VALUE");
44
+ }
24
45
  /**
25
46
  * Parse + validate the shared bulk-adjudication filter flags
26
47
  * (`--max-diff-lines`, `--older-than`). Extracted from the two verbatim
@@ -54,6 +75,7 @@ function parseProposalStatus(raw) {
54
75
  const proposalListCommand = defineJsonCommand({
55
76
  meta: { name: "list", description: "List proposal queue entries" },
56
77
  args: {
78
+ queue: { type: "string", description: "Select the proposal queue by source name" },
57
79
  status: {
58
80
  type: "string",
59
81
  description: "Filter by status (pending|accepted|rejected|reverted)",
@@ -64,6 +86,7 @@ const proposalListCommand = defineJsonCommand({
64
86
  run({ args }) {
65
87
  const status = parseProposalStatus(args.status);
66
88
  const result = akmProposalList({
89
+ queue: args.queue,
67
90
  status,
68
91
  ref: args.ref,
69
92
  type: args.type,
@@ -73,30 +96,31 @@ const proposalListCommand = defineJsonCommand({
73
96
  },
74
97
  });
75
98
  const proposalAcceptCommand = defineJsonCommand({
76
- meta: { name: "accept", description: "Accept a proposal and promote it into the stash" },
99
+ meta: { name: "accept", description: "Accept a proposal and promote it into the bundle" },
77
100
  args: {
78
101
  id: {
79
102
  type: "positional",
80
- description: "Proposal id (uuid / prefix) or asset ref (e.g. skill:akm-dream). Optional when --generator is provided.",
103
+ description: "Proposal id (uuid / prefix) or asset ref (e.g. skills/akm-dream). Optional when --generator is provided.",
81
104
  required: false,
82
105
  },
83
- target: { type: "string", description: "Override the write target by source name" },
106
+ queue: { type: "string", description: "Select the proposal queue by source name" },
107
+ target: { type: "string", description: "Write destination; must match the proposal's recorded target" },
84
108
  // F-6 / #393: Batch accept by generator, diff size, or age.
85
109
  generator: {
86
110
  type: "string",
87
- description: "F-6: Bulk-accept all pending proposals from this generator (e.g. reflect, distill). Requires no positional id.",
111
+ description: "Bulk-accept all pending proposals from this generator (e.g. reflect, distill). Requires no positional id.",
88
112
  },
89
113
  "max-diff-lines": {
90
114
  type: "string",
91
- description: "F-6: When bulk-accepting, only accept proposals whose content is <= this many lines. Skips larger proposals.",
115
+ description: "When bulk-accepting, only accept proposals whose content is <= this many lines. Skips larger proposals.",
92
116
  },
93
117
  "older-than": {
94
118
  type: "string",
95
- description: "F-6: When bulk-accepting, only accept proposals created more than this many days ago (e.g. '7' for 7 days).",
119
+ description: "When bulk-accepting, only accept proposals created more than this many days ago (e.g. '7' for 7 days).",
96
120
  },
97
121
  "dry-run": {
98
122
  type: "boolean",
99
- description: "F-6: List proposals that would be bulk-accepted without accepting them.",
123
+ description: "List proposals that would be bulk-accepted without accepting them.",
100
124
  default: false,
101
125
  },
102
126
  yes: {
@@ -107,6 +131,7 @@ const proposalAcceptCommand = defineJsonCommand({
107
131
  },
108
132
  },
109
133
  async run({ args }) {
134
+ rejectRetiredProposalSourceFlag("accept");
110
135
  const generator = args.generator;
111
136
  // F-6 / #393: Bulk-accept when --generator is provided without a positional id.
112
137
  if (generator && !args.id) {
@@ -123,6 +148,7 @@ const proposalAcceptCommand = defineJsonCommand({
123
148
  maxDiffLines,
124
149
  olderThanMs,
125
150
  dryRun: args["dry-run"],
151
+ queue: args.queue,
126
152
  target: args.target,
127
153
  });
128
154
  output("proposal-accept-batch", { accepted: count, results, dryRun: args["dry-run"] });
@@ -131,7 +157,11 @@ const proposalAcceptCommand = defineJsonCommand({
131
157
  if (!args.id) {
132
158
  throw new UsageError("Usage: akm proposal accept <id> OR akm proposal accept --generator <generator>", "MISSING_REQUIRED_ARGUMENT");
133
159
  }
134
- const result = await akmProposalAccept({ id: args.id, target: args.target });
160
+ const result = await akmProposalAccept({
161
+ id: args.id,
162
+ queue: args.queue,
163
+ target: args.target,
164
+ });
135
165
  output("proposal-accept", result);
136
166
  },
137
167
  });
@@ -140,26 +170,27 @@ const proposalRejectCommand = defineJsonCommand({
140
170
  args: {
141
171
  id: {
142
172
  type: "positional",
143
- description: "Proposal id (uuid / prefix) or asset ref (e.g. skill:akm-dream). Optional when --generator is provided.",
173
+ description: "Proposal id (uuid / prefix) or asset ref (e.g. skills/akm-dream). Optional when --generator is provided.",
144
174
  required: false,
145
175
  },
146
176
  reason: { type: "string", description: "Reason for rejection (required)" },
177
+ queue: { type: "string", description: "Select the proposal queue by source name" },
147
178
  // F-6 / #393: Batch reject by generator, diff size, or age.
148
179
  generator: {
149
180
  type: "string",
150
- description: "F-6: Bulk-reject all pending proposals from this generator (e.g. reflect, distill). Requires no positional id.",
181
+ description: "Bulk-reject all pending proposals from this generator (e.g. reflect, distill). Requires no positional id.",
151
182
  },
152
183
  "max-diff-lines": {
153
184
  type: "string",
154
- description: "F-6: When bulk-rejecting, only reject proposals whose content is <= this many lines. Skips larger proposals.",
185
+ description: "When bulk-rejecting, only reject proposals whose content is <= this many lines. Skips larger proposals.",
155
186
  },
156
187
  "older-than": {
157
188
  type: "string",
158
- description: "F-6: When bulk-rejecting, only reject proposals created more than this many days ago (e.g. '7' for 7 days).",
189
+ description: "When bulk-rejecting, only reject proposals created more than this many days ago (e.g. '7' for 7 days).",
159
190
  },
160
191
  "dry-run": {
161
192
  type: "boolean",
162
- description: "F-6: List proposals that would be bulk-rejected without rejecting them.",
193
+ description: "List proposals that would be bulk-rejected without rejecting them.",
163
194
  default: false,
164
195
  },
165
196
  yes: {
@@ -170,6 +201,7 @@ const proposalRejectCommand = defineJsonCommand({
170
201
  },
171
202
  },
172
203
  async run({ args }) {
204
+ rejectRetiredProposalSourceFlag("reject");
173
205
  const generator = args.generator;
174
206
  if (!args.reason || !String(args.reason).trim()) {
175
207
  throw new UsageError("Usage: akm proposal reject <id> --reason '<reason>' OR akm proposal reject --generator <generator> --reason '<reason>'", "MISSING_REQUIRED_ARGUMENT");
@@ -189,6 +221,7 @@ const proposalRejectCommand = defineJsonCommand({
189
221
  maxDiffLines,
190
222
  olderThanMs,
191
223
  dryRun: args["dry-run"],
224
+ queue: args.queue,
192
225
  reason: String(args.reason),
193
226
  });
194
227
  output("proposal-reject-batch", { rejected: count, results, dryRun: args["dry-run"] });
@@ -205,7 +238,11 @@ const proposalRejectCommand = defineJsonCommand({
205
238
  process.stderr.write("Aborted.\n");
206
239
  return;
207
240
  }
208
- const result = await akmProposalReject({ id: args.id, reason: String(args.reason) });
241
+ const result = await akmProposalReject({
242
+ id: args.id,
243
+ queue: args.queue,
244
+ reason: String(args.reason),
245
+ });
209
246
  output("proposal-reject", result);
210
247
  },
211
248
  });
@@ -214,13 +251,14 @@ const proposalDiffCommand = defineJsonCommand({
214
251
  args: {
215
252
  id: {
216
253
  type: "positional",
217
- description: "Proposal id (uuid / prefix) or asset ref (e.g. skill:akm-dream)",
254
+ description: "Proposal id (uuid / prefix) or asset ref (e.g. skills/akm-dream)",
218
255
  required: true,
219
256
  },
220
- target: { type: "string", description: "Override the write target by source name" },
257
+ queue: { type: "string", description: "Select the proposal queue by source name" },
258
+ target: { type: "string", description: "Diff destination; must match the proposal's recorded target" },
221
259
  },
222
260
  run({ args }) {
223
- const result = akmProposalDiff({ id: args.id, target: args.target });
261
+ const result = akmProposalDiff({ id: args.id, queue: args.queue, target: args.target });
224
262
  output("proposal-diff", result);
225
263
  },
226
264
  });
@@ -243,33 +281,34 @@ const proposalRevertCommand = defineJsonCommand({
243
281
  args: {
244
282
  id: {
245
283
  type: "positional",
246
- description: "Proposal id (full uuid) or asset ref (e.g. skill:akm-dream). UUID prefixes are not supported for archived proposals — use the full UUID.",
284
+ description: "Proposal id (full uuid) or asset ref (e.g. skills/akm-dream). UUID prefixes are not supported for archived proposals — use the full UUID.",
247
285
  required: true,
248
286
  },
249
- target: { type: "string", description: "Override the write target by source name" },
287
+ queue: { type: "string", description: "Select the proposal queue by source name" },
288
+ target: { type: "string", description: "Write destination; must match the proposal's recorded target" },
250
289
  },
251
290
  async run({ args }) {
252
291
  const result = await akmProposalRevert({
253
292
  id: args.id,
293
+ queue: args.queue,
254
294
  target: args.target,
255
295
  });
256
296
  output("proposal-revert", result);
257
297
  },
258
298
  });
259
299
  // `proposal show` (#225): show a single proposal with its validation findings.
260
- // `akmProposalShow` already backs `akm show proposal <id>` (now deprecated); this
261
- // is the canonical noun-group entry point.
262
300
  const proposalShowCommand = defineJsonCommand({
263
301
  meta: { name: "show", description: "Show a single proposal and its validation findings" },
264
302
  args: {
265
303
  id: {
266
304
  type: "positional",
267
- description: "Proposal id (uuid / prefix) or asset ref (e.g. skill:akm-dream)",
305
+ description: "Proposal id (uuid / prefix) or asset ref (e.g. skills/akm-dream)",
268
306
  required: true,
269
307
  },
308
+ queue: { type: "string", description: "Select the proposal queue by source name" },
270
309
  },
271
310
  run({ args }) {
272
- const result = akmProposalShow({ id: args.id });
311
+ const result = akmProposalShow({ id: args.id, queue: args.queue });
273
312
  output("proposal-show", result);
274
313
  },
275
314
  });
@@ -415,22 +454,17 @@ const proposalDrainCommand = defineJsonCommand({
415
454
  });
416
455
  },
417
456
  });
418
- // ── proposal noun group (#225 / 0.8 CLI stabilization) ────────────────────────
419
- //
420
- // `akm proposal <verb>` is the canonical grammar in 0.8. The flat verbs
421
- // (`proposals`/`accept`/`reject`/`diff`/`revert`) remain as deprecated aliases
422
- // that warn to stderr and delegate to the same command bodies; they are removed
423
- // in 0.9.0. Bare `akm proposal` behaves as `proposal list` (mirrors `akm env`).
457
+ // ── proposal noun group ───────────────────────────────────────────────────────
424
458
  export const proposalCommand = defineGroupCommand({
425
- meta: { name: "proposal", description: "Manage the proposal queue: list, show, diff, accept, reject, revert" },
426
- args: {
427
- status: {
428
- type: "string",
429
- description: "Filter by status (pending|accepted|rejected|reverted)",
430
- },
431
- ref: { type: "string", description: "Filter by asset ref ([bundle//]conceptId, e.g. knowledge/guide.md)" },
432
- type: { type: "string", description: "Filter by asset type" },
459
+ meta: {
460
+ name: "proposal",
461
+ description: "Manage the proposal queue: list, show, diff, accept, reject, revert, extract, new, drain",
433
462
  },
463
+ // The group declared `--queue`/`--status`/`--ref`/`--type` only so the bare
464
+ // form could act as `proposal list`. That form is gone (see below), and
465
+ // `proposalListCommand` declares the identical set, so keeping them here
466
+ // would just advertise flags in `akm proposal --help` that no group-level
467
+ // body reads.
434
468
  subCommands: {
435
469
  list: proposalListCommand,
436
470
  show: proposalShowCommand,
@@ -439,16 +473,10 @@ export const proposalCommand = defineGroupCommand({
439
473
  reject: proposalRejectCommand,
440
474
  revert: proposalRevertCommand,
441
475
  drain: proposalDrainCommand,
476
+ extract: extractCommand,
477
+ new: proposeCommand,
442
478
  },
443
- // Default body fires only for bare `akm proposal [--status …]`.
444
- defaultRun({ args }) {
445
- const status = parseProposalStatus(args.status);
446
- const result = akmProposalList({
447
- status,
448
- ref: args.ref,
449
- type: args.type,
450
- includeArchive: status === "accepted" || status === "rejected" || status === "reverted",
451
- });
452
- output("proposal-list", result);
453
- },
479
+ // No `defaultRun`: bare `akm proposal [--status …]` is a usage error (exit 2),
480
+ // the canonical bare-group behavior — owner ruling 12. `akm proposal list`
481
+ // takes the same flags and produces what the bare form used to.
454
482
  });
@@ -13,8 +13,9 @@
13
13
  */
14
14
  import { resolveStashDir } from "../../core/common.js";
15
15
  import { loadConfig } from "../../core/config/config.js";
16
+ import { resolveWriteTarget } from "../../core/write-source.js";
16
17
  import { withAssetMutationLease } from "../../indexer/index-writer-lock.js";
17
- import { createProposal, diffProposal, getProposal, isProposalSkipped, listProposals, promoteProposal, proposalContent, recoverProposalTransactionsForStash, rejectProposalDurably, resolveProposalId, revertProposal, } from "./repository.js";
18
+ import { createProposal, diffProposal, isProposalSkipped, listProposals, preflightProposalPromotion, promoteProposal, proposalContent, recoverProposalTransactionsForStash, rejectProposalDurably, resolveProposalId, resolveProposalIdForReject, revertProposal, } from "./repository.js";
18
19
  import { validateProposal } from "./validators/proposals.js";
19
20
  // ── Shared helpers ──────────────────────────────────────────────────────────
20
21
  function resolveStash(stashDir) {
@@ -22,6 +23,14 @@ function resolveStash(stashDir) {
22
23
  return stashDir;
23
24
  return resolveStashDir();
24
25
  }
26
+ function resolveProposalQueue(stashDir, queue, config) {
27
+ if (stashDir)
28
+ return { stashDir };
29
+ if (!queue)
30
+ return { stashDir: resolveStash() };
31
+ const target = resolveWriteTarget(config ?? loadConfig(), queue);
32
+ return { stashDir: target.source.path, target };
33
+ }
25
34
  /**
26
35
  * Thin in-process read of the pending proposal queue, used by the health HTML
27
36
  * report builder (#582) so it never shells out to `akm proposal list`.
@@ -34,7 +43,7 @@ export function listPendingProposals(stashDir) {
34
43
  return listProposals(resolveStash(stashDir), { status: "pending" });
35
44
  }
36
45
  export function akmProposalList(options = {}) {
37
- const stash = resolveStash(options.stashDir);
46
+ const { stashDir: stash } = resolveProposalQueue(options.stashDir, options.queue, options.config);
38
47
  // `--status accepted|rejected|reverted` implies archive-inclusion since the
39
48
  // live queue only ever contains pending entries.
40
49
  const includeArchive = options.includeArchive === true ||
@@ -50,19 +59,37 @@ export function akmProposalList(options = {}) {
50
59
  return { schemaVersion: 1, totalCount: proposals.length, proposals };
51
60
  }
52
61
  export function akmProposalShow(options) {
53
- const stash = resolveStash(options.stashDir);
54
- const proposal = getProposal(stash, options.id);
62
+ const queue = resolveProposalQueue(options.stashDir, options.queue, options.config);
63
+ const stash = queue.stashDir;
64
+ const proposal = resolveProposalId(stash, options.id);
65
+ let validation = validateProposal(proposal);
66
+ // An explicit stashDir without config is an in-process storage test seam; it
67
+ // has no authenticated write-target context to preflight against.
68
+ if (validation.ok &&
69
+ proposal.status === "pending" &&
70
+ (options.config !== undefined || options.stashDir === undefined)) {
71
+ try {
72
+ preflightProposalPromotion(options.config ?? loadConfig(), proposal, { queueTarget: queue.target });
73
+ }
74
+ catch (error) {
75
+ validation = {
76
+ ok: false,
77
+ findings: [{ kind: "promotion", message: error instanceof Error ? error.message : String(error) }],
78
+ };
79
+ }
80
+ }
55
81
  return {
56
82
  schemaVersion: 1,
57
83
  proposal,
58
- validation: validateProposal(proposal),
84
+ validation,
59
85
  };
60
86
  }
61
87
  export async function akmProposalAccept(options) {
62
- const stash = resolveStash(options.stashDir);
63
88
  const config = options.config ?? loadConfig();
89
+ const queue = resolveProposalQueue(options.stashDir, options.queue, config);
90
+ const stash = queue.stashDir;
64
91
  const resolvedId = resolveProposalId(stash, options.id).id;
65
- const result = await promoteProposal(stash, config, resolvedId, { target: options.target }, options.ctx);
92
+ const result = await promoteProposal(stash, config, resolvedId, { target: options.target, queueTarget: queue.target, gateDecision: options.gateDecision }, options.ctx);
66
93
  return {
67
94
  schemaVersion: 1,
68
95
  ok: true,
@@ -74,11 +101,14 @@ export async function akmProposalAccept(options) {
74
101
  }
75
102
  export async function akmProposalReject(options) {
76
103
  return withAssetMutationLease("proposal-reject", async () => {
77
- const stash = resolveStash(options.stashDir);
78
104
  const config = options.config ?? loadConfig();
79
- const proposalId = resolveProposalId(stash, options.id).id;
105
+ const { stashDir: stash } = resolveProposalQueue(options.stashDir, options.queue, config);
106
+ // resolveProposalIdForReject tolerates a legacy row whose metadata fails
107
+ // strict decoding — resolveProposalId's exact-UUID match would otherwise
108
+ // throw here, before the terminal-status machinery even runs.
109
+ const proposalId = resolveProposalIdForReject(stash, options.id, options.ctx);
80
110
  await recoverProposalTransactionsForStash(stash, config, options.ctx, proposalId);
81
- const updated = rejectProposalDurably(stash, proposalId, options.reason, options.ctx);
111
+ const updated = rejectProposalDurably(stash, proposalId, options.reason, options.ctx, options.gateDecision);
82
112
  return {
83
113
  schemaVersion: 1,
84
114
  ok: true,
@@ -90,10 +120,11 @@ export async function akmProposalReject(options) {
90
120
  });
91
121
  }
92
122
  export function akmProposalDiff(options) {
93
- const stash = resolveStash(options.stashDir);
94
123
  const config = options.config ?? loadConfig();
124
+ const queue = resolveProposalQueue(options.stashDir, options.queue, config);
125
+ const stash = queue.stashDir;
95
126
  const proposal = resolveProposalId(stash, options.id);
96
- const diff = diffProposal(stash, config, proposal.id, { target: options.target });
127
+ const diff = diffProposal(stash, config, proposal.id, { target: options.target, queueTarget: queue.target });
97
128
  return {
98
129
  schemaVersion: 1,
99
130
  id: proposal.id,
@@ -104,12 +135,15 @@ export function akmProposalDiff(options) {
104
135
  };
105
136
  }
106
137
  export function akmProposalCreate(options) {
107
- const stash = resolveStash(options.stashDir);
138
+ const queue = resolveProposalQueue(options.stashDir, options.queue, options.config);
139
+ const stash = queue.stashDir;
140
+ const target = options.target ?? (queue.target ? { source: queue.target.source.name, root: queue.target.source.path } : undefined);
108
141
  // Manual proposal creation (via `akm proposal create`) always bypasses
109
142
  // dedup/cooldown guards — the operator is explicitly requesting a proposal.
110
143
  const result = createProposal(stash, {
111
144
  ref: options.ref,
112
145
  source: options.source,
146
+ ...(target !== undefined ? { target } : {}),
113
147
  ...(options.sourceRun !== undefined ? { sourceRun: options.sourceRun } : {}),
114
148
  payload: options.payload,
115
149
  force: true,
@@ -137,10 +171,11 @@ export function akmProposalCreate(options) {
137
171
  * `rejected`.
138
172
  */
139
173
  export async function akmProposalRevert(options) {
140
- const stash = resolveStash(options.stashDir);
141
174
  const config = options.config ?? loadConfig();
175
+ const queue = resolveProposalQueue(options.stashDir, options.queue, config);
176
+ const stash = queue.stashDir;
142
177
  const resolvedId = resolveProposalId(stash, options.id).id;
143
- const result = await revertProposal(stash, config, resolvedId, { target: options.target }, options.ctx);
178
+ const result = await revertProposal(stash, config, resolvedId, { target: options.target, queueTarget: queue.target }, options.ctx);
144
179
  return {
145
180
  schemaVersion: 1,
146
181
  ok: true,
@@ -158,7 +193,8 @@ export async function akmProposalRevert(options) {
158
193
  * dry-run record shape. The destructive-confirmation prompt stays CLI-side.
159
194
  */
160
195
  export async function bulkAdjudicateProposals(options) {
161
- const stashDir = resolveStash(options.stashDir);
196
+ const config = options.config ?? loadConfig();
197
+ const { stashDir } = resolveProposalQueue(options.stashDir, options.queue, config);
162
198
  const pending = listProposals(stashDir, { status: "pending" }).filter((p) => {
163
199
  if (p.source !== options.generator)
164
200
  return false;
@@ -180,10 +216,10 @@ export async function bulkAdjudicateProposals(options) {
180
216
  results.push({ id: proposal.id, ref: proposal.ref, source: proposal.source, dryRun: true });
181
217
  }
182
218
  else if (options.action === "accept") {
183
- results.push(await akmProposalAccept({ id: proposal.id, target: options.target }));
219
+ results.push(await akmProposalAccept({ stashDir, id: proposal.id, queue: options.queue, target: options.target, config }));
184
220
  }
185
221
  else {
186
- results.push(await akmProposalReject({ id: proposal.id, reason: options.reason }));
222
+ results.push(await akmProposalReject({ stashDir, id: proposal.id, queue: options.queue, reason: options.reason, config }));
187
223
  }
188
224
  }
189
225
  return { count: results.length, results };
@@ -0,0 +1,88 @@
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
+ * `akm proposal new` — the asset-authoring entry point (formerly the
6
+ * top-level `akm propose`, moved under the `proposal` group per the 0.9 CLI
7
+ * overhaul, S8). Shares no private helper with the proposal MANAGEMENT
8
+ * family (list/show/accept/reject/…, `./proposal-cli.ts`) — its path/name
9
+ * helpers come from the shared src/core/asset/asset-create.ts module.
10
+ *
11
+ * Keeps the inline `runWithJsonErrors` form (branches on the result and sets
12
+ * `process.exitCode` conditionally on a failed proposal) rather than
13
+ * migrating to `defineJsonCommand`, matching the original contribute-cli.ts
14
+ * rationale: `process.exitCode` (not `process.exit()`) so the process still
15
+ * exits via natural event-loop drain rather than skipping pending cleanup.
16
+ */
17
+ import fs from "node:fs";
18
+ import path from "node:path";
19
+ import { defineCommand } from "citty";
20
+ import { getStringArg, parsePositiveIntFlag } from "../../cli/parse-args.js";
21
+ import { EXIT_CODES, GLOBAL_OUTPUT_ARGS, output, runWithJsonErrors } from "../../cli/shared.js";
22
+ import { assertFlatAssetName, combineCreatePath, normalizeCreateSubPath } from "../../core/asset/asset-create.js";
23
+ import { UsageError } from "../../core/errors.js";
24
+ import { akmPropose } from "./propose.js";
25
+ const EXIT_GENERAL = EXIT_CODES.GENERAL;
26
+ export const proposeCommand = defineCommand({
27
+ meta: {
28
+ name: "new",
29
+ description: "Ask the configured agent CLI to author a brand-new asset and queue it as a proposal",
30
+ },
31
+ // Raw defineCommand: declare the global output flags so their space-separated
32
+ // values are consumed rather than shifting the `type` / `name` positionals.
33
+ args: {
34
+ ...GLOBAL_OUTPUT_ARGS,
35
+ // Optional in citty so run() is invoked when omitted; we re-validate
36
+ // below to surface a structured UsageError (exit 2) instead of citty's
37
+ // default help-banner exit-0.
38
+ type: { type: "positional", description: "Asset type (skill, command, knowledge, lesson, ...)", required: false },
39
+ name: {
40
+ type: "positional",
41
+ description: "Asset name (flat, no '/'; use --path for a subdirectory)",
42
+ required: false,
43
+ },
44
+ path: {
45
+ type: "string",
46
+ description: "Relative subdirectory under the type dir to place the proposed asset in (e.g. 'release'). The filename comes from the name.",
47
+ },
48
+ task: { type: "string", description: "Task description for the agent (what should the asset do?)" },
49
+ file: { type: "string", description: "Read the task or prompt text from a UTF-8 file" },
50
+ engine: { type: "string", description: "Engine to use (defaults to defaults.engine)" },
51
+ "timeout-ms": { type: "string", description: "Override the agent CLI timeout in milliseconds" },
52
+ },
53
+ async run({ args }) {
54
+ await runWithJsonErrors(async () => {
55
+ // citty silently shows help and exits 0 when required positionals are
56
+ // omitted. Re-validate explicitly so the exit code is 2 (USAGE) and a
57
+ // structured JSON error reaches scripted callers.
58
+ const taskFromFlag = typeof args.task === "string" ? args.task : undefined;
59
+ const fileFromFlag = typeof args.file === "string" ? args.file : undefined;
60
+ if (!args.type || !args.name || (!taskFromFlag && !fileFromFlag)) {
61
+ throw new UsageError("Usage: akm proposal new <type> <name> (--task '<task>' | --file <path>).", "MISSING_REQUIRED_ARGUMENT", "Provide the asset type, name, and exactly one of --task or --file.");
62
+ }
63
+ if (taskFromFlag && fileFromFlag) {
64
+ throw new UsageError("Pass exactly one of --task or --file.", "INVALID_FLAG_VALUE");
65
+ }
66
+ // `name` is flat; subdirectory placement is `--path`'s job.
67
+ assertFlatAssetName(String(args.name));
68
+ const proposedName = combineCreatePath(normalizeCreateSubPath(getStringArg(args, "path")), String(args.name));
69
+ const taskText = fileFromFlag ? fs.readFileSync(path.resolve(fileFromFlag), "utf8") : (taskFromFlag ?? "");
70
+ const timeoutMs = parsePositiveIntFlag(args["timeout-ms"], "--timeout-ms");
71
+ const result = await akmPropose({
72
+ type: String(args.type),
73
+ name: proposedName,
74
+ task: taskText,
75
+ engine: getStringArg(args, "engine"),
76
+ ...(timeoutMs !== undefined ? { timeoutMs } : {}),
77
+ });
78
+ output("proposal-new", result);
79
+ if (result.ok === false) {
80
+ // Same reasoning as agentCommand in contribute-cli.ts: output() already
81
+ // ran, this is the last statement in the handler, so process.exitCode +
82
+ // return is equivalent without skipping any pending cleanup.
83
+ process.exitCode = EXIT_GENERAL;
84
+ return;
85
+ }
86
+ });
87
+ },
88
+ });
@@ -20,12 +20,14 @@ import { ConfigError, UsageError } from "../../core/errors.js";
20
20
  import { appendEvent } from "../../core/events.js";
21
21
  import { redactSensitiveText } from "../../core/redaction.js";
22
22
  import { resolveStandardsContext } from "../../core/standards/resolve-standards-context.js";
23
- import { deriveEntryProvenance, deriveInstallations, slugForPath } from "../../indexer/installations.js";
23
+ import { warn } from "../../core/warn.js";
24
+ import { deriveEntryProvenance } from "../../indexer/installations.js";
25
+ import { fallbackAnnouncement, NO_ENGINE_MESSAGE_SUFFIX, NO_ENGINE_REMEDY, withEngineFallback, } from "../../integrations/agent/engine-fallback.js";
24
26
  import { resolveEngine } from "../../integrations/agent/engine-resolution.js";
25
27
  import { buildProposePrompt, parseAgentProposalPayload } from "../../integrations/agent/prompts.js";
26
28
  import { collectDispatchSensitiveValues, executeRunner } from "../../integrations/agent/runner-dispatch.js";
27
29
  import { baseFailureFields, enoentHintMessage, isEnoentFailure } from "../agent/agent-support.js";
28
- import { createProposal, isProposalSkipped, } from "./repository.js";
30
+ import { createProposal, isProposalSkipped, resolveProposalQueueTarget, } from "./repository.js";
29
31
  function failureEnvelope(result, type, name, engine, fallbackReason = "non_zero_exit") {
30
32
  return {
31
33
  ...baseFailureFields(result, fallbackReason),
@@ -44,8 +46,7 @@ function failureEnvelope(result, type, name, engine, fallbackReason = "non_zero_
44
46
  * uses). Matches `createProposal`'s durable `proposals.ref` mint, so the entry
45
47
  * event, the fallback ref, and the stored proposal all carry one spelling.
46
48
  */
47
- function proposeItemRef(stashDir, type, name) {
48
- const bundleId = deriveInstallations([{ path: stashDir, writable: true }])[0]?.id ?? slugForPath(stashDir);
49
+ function proposeItemRef(bundleId, type, name) {
49
50
  return deriveEntryProvenance({ bundleId, componentId: bundleId, adapterId: "akm" }, type, name).itemRef;
50
51
  }
51
52
  /**
@@ -53,10 +54,10 @@ function proposeItemRef(stashDir, type, name) {
53
54
  * fully-qualified item_ref the durable proposal is minted under
54
55
  * (`proposeItemRef`), so the entry event and the stored proposal agree.
55
56
  */
56
- function emitProposeInvoked(stash, options) {
57
+ function emitProposeInvoked(bundleId, options) {
57
58
  appendEvent({
58
59
  eventType: "propose_invoked",
59
- ref: proposeItemRef(stash, options.type, options.name),
60
+ ref: proposeItemRef(bundleId, options.type, options.name),
60
61
  metadata: {
61
62
  type: options.type,
62
63
  name: options.name,
@@ -79,15 +80,21 @@ export async function akmPropose(options) {
79
80
  throw new UsageError(`propose: unknown asset type "${options.type}". Known types: ${[...placementTypes()].sort().join(", ")}.`, "INVALID_FLAG_VALUE");
80
81
  }
81
82
  const stash = options.stashDir ?? resolveStashDir();
82
- // 1. Always emit `propose_invoked` (extracted: emitProposeInvoked).
83
- emitProposeInvoked(stash, options);
84
- // 2. Resolve the selected engine exactly once. Propose accepts either kind;
83
+ // 1. Resolve the selected engine and write target exactly once.
85
84
  // the LLM arm uses the caller-specific plain-chat handler below.
86
85
  const config = options.agentConfig ?? (await import("../../core/config/config.js")).loadConfig();
87
- const engineName = options.engine ?? config.defaults?.engine;
86
+ const target = resolveProposalQueueTarget(stash, config);
87
+ emitProposeInvoked(target.source, options);
88
+ const { config: engineConfig, fallbackEngineName } = withEngineFallback(config);
89
+ const engineName = options.engine ?? engineConfig.defaults?.engine;
90
+ // Announced, never silent: `options.engine` outranks the default, so the
91
+ // fallback is only reportable when it is the engine actually selected.
92
+ const engineAnnouncement = fallbackAnnouncement(fallbackEngineName, engineName);
93
+ if (engineAnnouncement)
94
+ warn(engineAnnouncement);
88
95
  if (!engineName)
89
- throw new ConfigError("propose requires --engine or defaults.engine.", "INVALID_CONFIG_FILE");
90
- const runner = resolveEngine(engineName, config);
96
+ throw new ConfigError(`propose ${NO_ENGINE_MESSAGE_SUFFIX} ${NO_ENGINE_REMEDY}`, "INVALID_CONFIG_FILE");
97
+ const runner = resolveEngine(engineName, engineConfig);
91
98
  const profile = runner.kind === "llm" ? undefined : runner.profile;
92
99
  // 3. Build prompt.
93
100
  // Synthesize a temp draft path so opencode can write the asset content
@@ -158,7 +165,7 @@ export async function akmPropose(options) {
158
165
  const draftContent = fs.readFileSync(resolvedDraftPath, "utf8");
159
166
  fs.unlinkSync(resolvedDraftPath);
160
167
  payload = {
161
- ref: proposeItemRef(stash, options.type, options.name), // WI-8.5a item_ref flip
168
+ ref: proposeItemRef(target.source, options.type, options.name),
162
169
  content: draftContent,
163
170
  };
164
171
  }
@@ -201,7 +208,7 @@ export async function akmPropose(options) {
201
208
  // 6. Insert the proposal. Note: we allow the agent's `ref` to normalise the
202
209
  // asset name (e.g. path-cleanup), but only after validating that the ref is
203
210
  // well-formed and the type still matches the requested type.
204
- const expectedRef = proposeItemRef(stash, options.type, options.name); // WI-8.5a item_ref flip
211
+ const expectedRef = proposeItemRef(target.source, options.type, options.name);
205
212
  let ref = expectedRef;
206
213
  if (payload.ref) {
207
214
  let parsedRef;
@@ -236,12 +243,13 @@ export async function akmPropose(options) {
236
243
  ...(result.stderr ? { stderr: result.stderr } : {}),
237
244
  };
238
245
  }
239
- ref = proposeItemRef(stash, parsedRef.type, parsedRef.name); // WI-8.5a item_ref flip
246
+ ref = proposeItemRef(target.source, parsedRef.type, parsedRef.name);
240
247
  }
241
248
  const createInput = {
242
249
  ref,
243
250
  source: "propose",
244
251
  sourceRun: `propose-${Date.now()}`,
252
+ target,
245
253
  // User-initiated proposals always bypass dedup/cooldown guards — the
246
254
  // operator is explicitly asking for a new proposal.
247
255
  force: true,