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
@@ -6,7 +6,7 @@
6
6
  * `config-schema.ts` monolith — no behavior change.
7
7
  */
8
8
  import { z } from "zod";
9
- import { positiveInt } from "./primitives.js";
9
+ import { engineName, positiveInt } from "./primitives.js";
10
10
  // ── Workflow engine ─────────────────────────────────────────────────────────
11
11
  /**
12
12
  * Workflow-engine settings (`workflow`).
@@ -19,11 +19,11 @@ import { positiveInt } from "./primitives.js";
19
19
  * `[1, WORKFLOW_MAX_CONCURRENCY_CEILING]` (64). Values above the ceiling
20
20
  * are clamped, not rejected, so a config shared across machines with wildly
21
21
  * different core counts never hard-fails validation.
22
- * The R3 brief/report driver surface does NOT consult this — drivers own their
23
- * own parallelism (the engine only caps native dispatch).
24
22
  */
25
23
  export const WorkflowConfigSchema = z
26
24
  .object({
27
25
  maxConcurrency: positiveInt.optional(),
26
+ /** Named LLM or agent engine frozen into every criteria-bearing gate. */
27
+ judgeEngine: engineName.optional(),
28
28
  })
29
29
  .passthrough();
@@ -11,15 +11,18 @@
11
11
  * helpers only resolve refs to absolute paths and guard against directory
12
12
  * traversal.
13
13
  */
14
+ import fs from "node:fs";
14
15
  import path from "node:path";
15
16
  import { resolveSourceEntries } from "../indexer/search/search-source.js";
17
+ import { resolveSourcesForOrigin } from "../registry/origin-resolve.js";
16
18
  import { assertFlatAssetName, combineCreatePath, normalizeCreateSubPath } from "./asset/asset-create.js";
17
19
  import { assetPathForName } from "./asset/asset-placement.js";
18
20
  import { displayRef, isFullRefInput, parseRefInput } from "./asset/resolve-ref.js";
19
21
  import { isWithin } from "./common.js";
20
22
  import { loadConfig } from "./config/config.js";
21
23
  import { NotFoundError, UsageError } from "./errors.js";
22
- import { commitWriteTargetBoundary, formatRefForMessage, recordWriteTargetPath, resolveWriteTarget, } from "./write-source.js";
24
+ import { resolveMutationTarget } from "./mutation-target.js";
25
+ import { formatRefForMessage, withWriteTargetMutation } from "./write-source.js";
23
26
  /**
24
27
  * The `vault` asset type was removed in 0.9.0. The env/secret input path no
25
28
  * longer routes through the legacy stored-ref parser (which carries the removal
@@ -31,25 +34,58 @@ function assertNotRemovedVaultRef(ref) {
31
34
  const boundary = ref.indexOf("//");
32
35
  const bare = boundary >= 0 ? ref.slice(boundary + 2) : ref;
33
36
  if (/^vault[:/]/.test(bare.trim())) {
34
- throw new UsageError("The `vault` asset type was removed in 0.9.0 — use `env:` (whole .env config) or `secret:` (a single value).", "INVALID_FLAG_VALUE");
37
+ throw new UsageError("The `vault` asset type was removed in 0.9.0 — use `env/` (whole .env config) or `secrets/` (a single value).", "INVALID_FLAG_VALUE");
35
38
  }
36
39
  }
40
+ /**
41
+ * Q-08 ruling: the pre-0.9.0 `type:name` ref grammar taught `env:<name>` /
42
+ * `secret:<name>` (help text and docs also implied `environment:`/`secrets:`
43
+ * variants) as the way to address a single env/secret. That grammar is GONE —
44
+ * NO alias, no re-acceptance (same rule as the retired `vault:` prefix above).
45
+ * Left unchecked, a colon-prefixed ref does not error here at all: it falls
46
+ * through to the "bare name" convenience below and gets silently qualified
47
+ * into a literal `env/env:name` (or `secrets/secret:name`) file that can never
48
+ * exist — a confusing not-found that hides the real mistake instead of naming
49
+ * it. Reject it here, loudly, before that happens.
50
+ */
51
+ function assertNotColonRef(ref, aliases, replacement) {
52
+ const boundary = ref.indexOf("//");
53
+ const bare = (boundary >= 0 ? ref.slice(boundary + 2) : ref).trim();
54
+ const colon = bare.indexOf(":");
55
+ if (colon <= 0)
56
+ return;
57
+ const head = bare.slice(0, colon).toLowerCase();
58
+ if (!aliases.includes(head))
59
+ return;
60
+ const name = bare.slice(colon + 1);
61
+ throw new UsageError(`The \`${head}:\` ref spelling was removed in 0.9.0 — use the slash form instead: \`${replacement}${name}\`.`, "INVALID_FLAG_VALUE");
62
+ }
37
63
  export function parseEnvRef(ref) {
38
64
  // Accept a bare env name (`prod`, `sub/prod`) or the new-grammar
39
65
  // `[bundle//]env/name` conceptId. A bare name's leading segment maps to no
40
66
  // asset type, so it is qualified with the `env/` conceptId prefix; anything
41
67
  // already a full new-grammar ref is parsed as-is.
42
68
  assertNotRemovedVaultRef(ref);
69
+ assertNotColonRef(ref, ["env", "environment"], "env/");
43
70
  return parseRefInput(isFullRefInput(ref) ? ref : `env/${ref}`);
44
71
  }
45
- export function findEnvSource(origin) {
72
+ export function findEnvSource(origin, type, name) {
46
73
  const sources = resolveSourceEntries(undefined, loadConfig());
47
74
  if (sources.length === 0) {
48
- throw new UsageError("No stashes configured. Run `akm init` to create your working stash.");
75
+ throw new UsageError("No bundles configured. Run `akm bundle create` to create your working bundle.");
76
+ }
77
+ const candidates = origin ? resolveSourcesForOrigin(origin, sources) : sources;
78
+ const typeDir = type === "env" ? "env" : "secrets";
79
+ const member = candidates.find((source) => fs.existsSync(assetPathForName(type, path.join(source.path, typeDir), name)));
80
+ if (member)
81
+ return member;
82
+ if (!origin) {
83
+ const fallback = candidates[0];
84
+ if (fallback)
85
+ return fallback;
86
+ throw new UsageError("No bundles configured. Run `akm bundle create` to create your working bundle.");
49
87
  }
50
- if (!origin || origin === "local")
51
- return sources[0];
52
- const named = sources.find((source) => source.registryId === origin);
88
+ const named = candidates[0];
53
89
  if (!named) {
54
90
  throw new NotFoundError(`Source not found for origin: ${origin}`);
55
91
  }
@@ -58,19 +94,21 @@ export function findEnvSource(origin) {
58
94
  export function makeEnvRef(name, source) {
59
95
  // F4b output-spelling flip: `env/name` in the primary stash, `bundle//env/name`
60
96
  // for a slug-clean named source.
61
- return displayRef({ type: "env", name, bundleId: source?.registryId });
97
+ return displayRef({ type: "env", name, bundleId: source?.registryId }, displayDefaultBundle(source));
62
98
  }
63
99
  /**
64
- * Resolve an env ref to an absolute `.env` path. Accepts `env:` and
65
- * `environment:` (alias) refs as well as bare names. The path is returned even
66
- * when the file does not yet exist (so `create` writes under `env/`).
100
+ * Resolve an env ref to an absolute `.env` path. Accepts the `env/<name>`
101
+ * conceptId (or a bare name, auto-qualified into it) the retired
102
+ * `env:`/`environment:` colon spelling is rejected loudly (Q-08), never
103
+ * silently resolved. The path is returned even when the file does not yet
104
+ * exist (so `create` writes under `env/`).
67
105
  */
68
106
  export function resolveEnvPath(ref) {
69
107
  const parsed = parseEnvRef(ref);
70
108
  if (parsed.type !== "env") {
71
- throw new UsageError(`Expected an env ref (env:<name>); got "${ref}".`);
109
+ throw new UsageError(`Expected an env ref (env/<name>); got "${ref}".`);
72
110
  }
73
- const source = findEnvSource(parsed.origin);
111
+ const source = findEnvSource(parsed.origin, "env", parsed.name);
74
112
  const envRoot = path.join(source.path, "env");
75
113
  const envPath = assetPathForName("env", envRoot, parsed.name);
76
114
  // Defense-in-depth: ensure the resolved path stays inside the env directory.
@@ -86,12 +124,20 @@ export function parseSecretRef(ref) {
86
124
  // Same bare-name-vs-full-ref rule as parseEnvRef; a bare name is qualified
87
125
  // with the `secrets/` conceptId prefix (secret's stash subdir).
88
126
  assertNotRemovedVaultRef(ref);
127
+ assertNotColonRef(ref, ["secret", "secrets"], "secrets/");
89
128
  return parseRefInput(isFullRefInput(ref) ? ref : `secrets/${ref}`);
90
129
  }
91
130
  export function makeSecretRef(name, source) {
92
131
  // F4b output-spelling flip: `secrets/name` in the primary stash,
93
132
  // `bundle//secrets/name` for a slug-clean named source.
94
- return displayRef({ type: "secret", name, bundleId: source?.registryId });
133
+ return displayRef({ type: "secret", name, bundleId: source?.registryId }, displayDefaultBundle(source));
134
+ }
135
+ function displayDefaultBundle(source) {
136
+ const config = loadConfig();
137
+ if (config.defaultBundle || !source)
138
+ return config.defaultBundle;
139
+ const primary = resolveSourceEntries(undefined, config)[0];
140
+ return primary && path.resolve(primary.path) === path.resolve(source.path) ? source.registryId : undefined;
95
141
  }
96
142
  export function resolveSecretPath(ref,
97
143
  // Create-only (`secret set`): enforce a flat ref name and apply `--path` as
@@ -99,14 +145,14 @@ export function resolveSecretPath(ref,
99
145
  create) {
100
146
  const parsed = parseSecretRef(ref);
101
147
  if (parsed.type !== "secret") {
102
- throw new UsageError(`Expected a secret ref (secret:<name>); got "${ref}".`);
148
+ throw new UsageError(`Expected a secret ref (secrets/<name>); got "${ref}".`);
103
149
  }
104
150
  if (create) {
105
151
  assertFlatAssetName(parsed.name);
106
152
  parsed.name = combineCreatePath(normalizeCreateSubPath(create.subPath), parsed.name);
107
153
  }
108
154
  // Source resolution is identical for every asset type; reuse the env helper.
109
- const source = findEnvSource(parsed.origin);
155
+ const source = findEnvSource(parsed.origin, "secret", parsed.name);
110
156
  const typeRoot = path.join(source.path, "secrets");
111
157
  const absPath = assetPathForName("secret", typeRoot, parsed.name);
112
158
  // Defense-in-depth: ensure the resolved path stays inside the secrets dir.
@@ -115,26 +161,6 @@ create) {
115
161
  }
116
162
  return { name: parsed.name, absPath, source };
117
163
  }
118
- // ── Write-target resolution (env/secret mutations) ───────────────────────────
119
- //
120
- // READS (`env run`/`show`/`list`/`path`, `secret run`/`path`/`list`) keep the
121
- // origin-aware, all-sources `findEnvSource` resolution above. WRITES route
122
- // through the canonical `resolveWriteTarget` selection every other write command
123
- // (remember/import/tasks/knowledge) shares: explicit `--target` wins, else
124
- // `defaultWriteTarget`, else the working stash, and the chosen source must be
125
- // writable (a non-writable `--target`/`defaultWriteTarget` fails fast with the
126
- // shared typed ConfigError). Env/secret VALUES are still never read or surfaced
127
- // here — these helpers only resolve the write target and the absolute path.
128
- /**
129
- * Spell an env/secret ref for a resolved write target. `target.selector` is the
130
- * config source name for a `--target`/`defaultWriteTarget` destination and
131
- * undefined for the working-stash fallback; `displayRef` suppresses the
132
- * `local`/`stash`/default sentinels, so the primary stash still spells the bare
133
- * `env/name` while a named bundle spells `bundle//env/name`.
134
- */
135
- export function writeTargetDisplaySource(target) {
136
- return { path: target.source.path, ...(target.selector ? { registryId: target.selector } : {}) };
137
- }
138
164
  /**
139
165
  * Resolve the destination for an env mutation. Mirrors {@link resolveEnvPath}
140
166
  * but selects the source via {@link resolveWriteTarget} (writability-checked)
@@ -144,19 +170,20 @@ export function writeTargetDisplaySource(target) {
144
170
  export function resolveEnvWriteTarget(ref, writeTarget, create) {
145
171
  const parsed = parseEnvRef(ref);
146
172
  if (parsed.type !== "env") {
147
- throw new UsageError(`Expected an env ref (env:<name>); got "${ref}".`);
173
+ throw new UsageError(`Expected an env ref (env/<name>); got "${ref}".`);
148
174
  }
149
175
  if (create) {
150
176
  assertFlatAssetName(parsed.name);
151
177
  parsed.name = combineCreatePath(normalizeCreateSubPath(create.subPath), parsed.name);
152
178
  }
153
- const target = resolveWriteTarget(loadConfig(), writeTarget);
179
+ const resolved = resolveMutationTarget(loadConfig(), parsed, writeTarget, { allowedAdapters: ["akm", "dotenv"] });
180
+ const { target } = resolved;
154
181
  const envRoot = path.join(target.source.path, "env");
155
182
  const absPath = assetPathForName("env", envRoot, parsed.name);
156
183
  if (!isWithin(absPath, envRoot)) {
157
184
  throw new UsageError(`Env name "${parsed.name}" escapes the env directory.`);
158
185
  }
159
- return { name: parsed.name, absPath, target, parsedRef: parsed };
186
+ return { name: parsed.name, absPath, target, parsedRef: resolved.ref, ref: resolved.displayRef };
160
187
  }
161
188
  /**
162
189
  * Resolve the destination for a secret mutation. Mirrors
@@ -167,19 +194,20 @@ export function resolveEnvWriteTarget(ref, writeTarget, create) {
167
194
  export function resolveSecretWriteTarget(ref, writeTarget, create) {
168
195
  const parsed = parseSecretRef(ref);
169
196
  if (parsed.type !== "secret") {
170
- throw new UsageError(`Expected a secret ref (secret:<name>); got "${ref}".`);
197
+ throw new UsageError(`Expected a secret ref (secrets/<name>); got "${ref}".`);
171
198
  }
172
199
  if (create) {
173
200
  assertFlatAssetName(parsed.name);
174
201
  parsed.name = combineCreatePath(normalizeCreateSubPath(create.subPath), parsed.name);
175
202
  }
176
- const target = resolveWriteTarget(loadConfig(), writeTarget);
203
+ const resolved = resolveMutationTarget(loadConfig(), parsed, writeTarget, { allowedAdapters: ["akm", "dotenv"] });
204
+ const { target } = resolved;
177
205
  const typeRoot = path.join(target.source.path, "secrets");
178
206
  const absPath = assetPathForName("secret", typeRoot, parsed.name);
179
207
  if (!isWithin(absPath, typeRoot)) {
180
208
  throw new UsageError(`Secret name "${parsed.name}" escapes the secrets directory.`);
181
209
  }
182
- return { name: parsed.name, absPath, target };
210
+ return { name: parsed.name, absPath, target, ref: resolved.displayRef };
183
211
  }
184
212
  /**
185
213
  * Land an env/secret mutation on its write target's git boundary. Mirrors the
@@ -188,8 +216,10 @@ export function resolveSecretWriteTarget(ref, writeTarget, create) {
188
216
  * primary stash included) and for `env/` paths a stash `.gitignore` excludes, so
189
217
  * callers invoke it unconditionally after every create/ingest/set/remove.
190
218
  */
191
- export function commitEnvSecretWrite(target, ref, op, paths) {
192
- for (const filePath of paths)
193
- recordWriteTargetPath(target.source, filePath);
194
- commitWriteTargetBoundary(target, `${op} ${formatRefForMessage({ type: ref.type, name: ref.name, ...(target.selector ? { origin: target.selector } : {}) })}`);
219
+ export function withEnvSecretWrite(target, ref, op, paths, mutate) {
220
+ return withWriteTargetMutation(target, paths, {
221
+ ignored: "local-only",
222
+ purpose: `${ref.type}-${op.toLowerCase()}`,
223
+ message: `${op} ${formatRefForMessage({ type: ref.type, name: ref.name, origin: target.source.name })}`,
224
+ }, mutate);
195
225
  }
@@ -6,33 +6,39 @@
6
6
  * imperative. Returning undefined means "no canned hint".
7
7
  */
8
8
  const CONFIG_HINTS = {
9
- STASH_DIR_NOT_FOUND: "Run `akm setup` to create and configure your stash, or set stashDir in your config.",
10
- STASH_DIR_NOT_A_DIRECTORY: "The configured stashDir exists but isn't a directory. Update stashDir to point at a folder.",
11
- STASH_DIR_UNREADABLE: "Check the path exists and your user has read permission, or update stashDir.",
9
+ STASH_DIR_NOT_FOUND: "Run `akm setup` to create and configure your bundle, or configure a defaultBundle path.",
10
+ STASH_DIR_NOT_A_DIRECTORY: "The configured default bundle path exists but isn't a directory. Update it to point at a folder.",
11
+ STASH_DIR_UNREADABLE: "Check the path exists and your user has read permission, or update the default bundle path.",
12
12
  EMBEDDING_NOT_CONFIGURED: 'Run `akm config set embedding \'{"endpoint":"...","model":"..."}\'` to enable embeddings.',
13
13
  LLM_NOT_CONFIGURED: 'Run `akm setup` or configure an `engines` entry with `kind: "llm"`, then select it with `defaults.llmEngine`.',
14
- TEST_ISOLATION_MISSING: "Under bun test, when AKM_STASH_DIR is set you MUST also set XDG_DATA_HOME (or AKM_DATA_DIR) and XDG_STATE_HOME (or AKM_STATE_DIR) to temp directories so the test does not touch the developer's real ~/.local/share/akm or ~/.local/state/akm.",
15
- SETUP_TMP_STASH_REFUSED: "Use a persistent directory, or set AKM_FORCE_SETUP_TMP_STASH=1 to opt in to a sandboxed setup (setup also pre-sets AKM_STASH_DIR so config and cache writes auto-isolate into $stashDir/.akm/ — host config is preserved).",
16
- UNSAFE_STASH_DIR: "Choose a path inside your home directory (e.g. ~/akm) or another empty workspace. The stash directory cannot be the filesystem root, your home directory itself, or a sensitive system path like /etc, /var, ~/.config, or ~/.ssh.",
14
+ TEST_ISOLATION_MISSING: "Under bun test, when AKM_BUNDLE_DIR is set you MUST also set XDG_DATA_HOME (or AKM_DATA_DIR) and XDG_STATE_HOME (or AKM_STATE_DIR) to temp directories so the test does not touch the developer's real ~/.local/share/akm or ~/.local/state/akm.",
15
+ SETUP_TMP_STASH_REFUSED: "Use a persistent directory, or set AKM_FORCE_SETUP_TMP_STASH=1 to opt in to a sandboxed setup (setup also pre-sets AKM_BUNDLE_DIR so config and cache writes auto-isolate into $stashDir/.akm/ — host config is preserved).",
16
+ UNSAFE_STASH_DIR: "Choose a path inside your home directory (e.g. ~/akm) or another empty workspace. The bundle directory cannot be the filesystem root, your home directory itself, or a sensitive system path like /etc, /var, ~/.config, or ~/.ssh.",
17
17
  UNKNOWN_IMPROVE_STRATEGY: "Pass one of the listed strategy names to `--strategy`, or define it under `improve.strategies`. Names are case-sensitive.",
18
18
  };
19
19
  /** Default hint for each UsageError code. */
20
20
  const USAGE_HINTS = {
21
21
  INVALID_FLAG_VALUE: "Run `akm <command> --help` to see accepted values.",
22
- INVALID_SOURCE_VALUE: "Pick one of: stash, registry, both.",
23
- INVALID_FORMAT_VALUE: "Pick one of: json, jsonl, text, yaml.",
22
+ INVALID_SOURCE_VALUE: "Pick one of: local, registry, all, or a configured source name.",
23
+ INVALID_FORMAT_VALUE: "Pick one of: json, jsonl, yaml, text, md, html.",
24
24
  INVALID_DETAIL_VALUE: "Pick one of: brief, normal, full. For agent/summary projections use --shape.",
25
25
  INVALID_SHAPE_VALUE: "Pick one of: human, agent, summary (summary is only valid on `akm show`).",
26
26
  INVALID_JSON_CONFIG_VALUE: 'Quote JSON values in your shell, for example: akm config set embedding \'{"endpoint":"http://localhost:11434/v1/embeddings","model":"nomic-embed-text"}\'.',
27
- MISSING_OR_AMBIGUOUS_TARGET: "Use `akm update --all` or pass a target like `akm update npm:@scope/pkg` (not both).",
28
- TARGET_NOT_UPDATABLE: "Run `akm list` to view your sources, then retry with one of those values.",
27
+ MISSING_OR_AMBIGUOUS_TARGET: "Use `akm bundle update --all` or pass a target like `akm bundle update npm:@scope/pkg` (not both).",
28
+ TARGET_NOT_UPDATABLE: "Run `akm bundle list` to view your sources, then retry with one of those values.",
29
29
  MISSING_REQUIRED_ARGUMENT: "Refs use the form [bundle//]conceptId, e.g. `akm show knowledge/guide.md` or `akm show skills/deploy`.",
30
+ UNKNOWN_COMMAND: "Run `akm --help` to see available commands.",
31
+ UNKNOWN_FLAG: "Run the command with `--help` to see its accepted flags.",
30
32
  };
31
33
  /** Default hint for each NotFoundError code. */
32
34
  const NOT_FOUND_HINTS = {
33
35
  ASSET_NOT_FOUND: "Run `akm search <query>` or `akm index` to refresh the index.",
34
- SOURCE_NOT_FOUND: "Run `akm list` to view your sources, then retry with one of those values.",
36
+ SOURCE_NOT_FOUND: "Run `akm bundle list` to view your sources, then retry with one of those values.",
35
37
  WORKFLOW_NOT_FOUND: "Run `akm workflow list --active` to see runs.",
38
+ // A proposal is addressed by id or ref, never by path — reusing
39
+ // FILE_NOT_FOUND here handed users "check the path exists and is readable"
40
+ // for a mistyped id, which points at the wrong thing entirely.
41
+ PROPOSAL_NOT_FOUND: "Run `akm proposal list` to see pending proposals and their ids.",
36
42
  FILE_NOT_FOUND: "Check the path exists and is readable.",
37
43
  };
38
44
  /**
@@ -97,7 +103,7 @@ export class NotFoundError extends AkmError {
97
103
  * Test-isolation guard helper.
98
104
  *
99
105
  * `src/core/paths.ts` throws `ConfigError("TEST_ISOLATION_MISSING")` under
100
- * `bun test` when `AKM_STASH_DIR` is set without a paired data-dir or
106
+ * `bun test` when `AKM_BUNDLE_DIR` is set without a paired data-dir or
101
107
  * state-dir override. That throw must never be swallowed by best-effort
102
108
  * catches around DB/data-dir operations — otherwise the guard's loud failure
103
109
  * silently degrades into a "no result" outcome (cold cache, missing snapshot,
@@ -1,52 +1,19 @@
1
1
  // This Source Code Form is subject to the terms of the Mozilla Public
2
2
  // License, v. 2.0. If a copy of the MPL was not distributed with this
3
3
  // file, You can obtain one at https://mozilla.org/MPL/2.0/.
4
- /**
5
- * Append-only events stream — backed by state.db (#204, Phase 3).
6
- *
7
- * Every mutating CLI verb funnels through `appendEvent` so external
8
- * observers (sync, replication, audit, dashboards) can react to stash
9
- * changes. Events are stored in the `events` table in `state.db`
10
- * (SQLite, WAL mode) instead of a flat `events.jsonl` file.
11
- *
12
- * The helper is the only thing in akm that writes to the events table. It
13
- * accepts an injectable `dbPath` (via `EventsContext`) so tests can pin a
14
- * tmpdir without any global mutation.
15
- *
16
- * Format (each EventEnvelope):
17
- * { "schemaVersion": 1, "id": <number>, "ts": "<ISO>",
18
- * "eventType": "<verb>", "ref"?: "<asset-ref>", ... }
19
- *
20
- * - `id` is a monotonic SQLite AUTOINCREMENT rowid. Callers can persist it
21
- * as a durable cursor for `--since` resumption (replaces the old byte-offset
22
- * cursor). The public API still surfaces this as `nextOffset` (an opaque
23
- * number) for backward compatibility with callers that stored byte-offset
24
- * cursors.
25
- * - `ts` is ISO-8601 (UTC, millisecond precision).
26
- */
27
- import path from "node:path";
28
4
  import { insertEvent, readStateEvents } from "../storage/repositories/events-repository.js";
29
5
  import { rethrowIfTestIsolationError } from "./errors.js";
30
- import { getDataDir } from "./paths.js";
31
- import { openStateDatabase, withStateDb } from "./state-db.js";
6
+ import { getStateDbPath, openStateDatabase, withStateDb } from "./state-db.js";
32
7
  import { error } from "./warn.js";
33
- /**
34
- * Legacy events.jsonl path — used only by the migration script
35
- * (`scripts/migrate-storage.ts`) to import existing event history into
36
- * state.db. No events are written here by akm v0.9+.
37
- */
38
- export function getEventsPath() {
39
- return path.join(getDataDir(), "events.jsonl");
40
- }
41
8
  /**
42
9
  * Resolve the state.db path from context:
43
10
  * 1. `ctx.dbPath` — explicit override (test seam)
44
- * 2. default — `<dataDir>/state.db`
11
+ * 2. default — the canonical state.db path
45
12
  */
46
13
  function resolveDbPath(ctx) {
47
14
  if (ctx?.dbPath)
48
15
  return ctx.dbPath;
49
- return path.join(getDataDir(), "state.db");
16
+ return getStateDbPath();
50
17
  }
51
18
  function resolveNow(ctx) {
52
19
  return ctx?.now ?? Date.now;
@@ -100,6 +67,17 @@ export function appendEvent(input, ctx) {
100
67
  error(`akm: appendEvent failed: ${String(err)}`);
101
68
  }
102
69
  }
70
+ /**
71
+ * 0.9.0 breaking change (owner ruling 12): `akm sync` used to persist
72
+ * `eventType: "save"`; it now writes `"sync"` instead (matching the command
73
+ * name). Existing `state.db` rows — and any user script running
74
+ * `akm log --type save` — still carry the old spelling. Rather than
75
+ * rewriting historical rows (a migration users never asked for, on data we
76
+ * don't get to touch at rest), reads treat the two names as synonyms: asking
77
+ * for either "save" or "sync" returns rows written under both names. Only
78
+ * the WRITE path (sources-cli.ts's `runSyncBody`) changed.
79
+ */
80
+ const SAVE_SYNC_EVENT_TYPE_ALIASES = new Set(["save", "sync"]);
103
81
  /**
104
82
  * Read all events matching the filter. Returns a `nextOffset` that callers
105
83
  * can persist between processes for monotonic resumption.
@@ -117,14 +95,37 @@ export function readEvents(options = {}, ctx) {
117
95
  return { events: [], nextOffset: 0 };
118
96
  }
119
97
  try {
98
+ // A "save"/"sync" query can't be expressed as a single SQL `event_type =
99
+ // ?` match (see SAVE_SYNC_EVENT_TYPE_ALIASES above), so widen the SQL
100
+ // filter to "no type filter" for that one case and apply the alias match
101
+ // client-side alongside the existing tag post-filter below.
102
+ const typeIsAliased = options.type !== undefined && SAVE_SYNC_EVENT_TYPE_ALIASES.has(options.type);
103
+ // D-38: a JS-side post-filter (the type alias above, or the tag filters
104
+ // below) runs AFTER the SQL read, so a SQL-level LIMIT applied before it
105
+ // could drop rows the post-filter would have kept out anyway, silently
106
+ // returning fewer than `limit` (or the wrong — oldest-in-the-SQL-window —
107
+ // events). Only push `limit` into SQL (readStateEvents) when nothing
108
+ // downstream can shrink the result further; otherwise read unbounded (the
109
+ // pre-existing behavior) and apply `limit` ourselves, below, AFTER the
110
+ // post-filter runs.
111
+ const needsPostFilter = typeIsAliased ||
112
+ (options.excludeTags?.length ?? 0) > 0 ||
113
+ (options.includeTags?.length ?? 0) > 0 ||
114
+ options.runId !== undefined;
115
+ const pushLimitToSql = options.limit !== undefined && !needsPostFilter;
120
116
  const { events: rawEvents, nextId } = readStateEvents(db, {
121
117
  sinceId: options.sinceOffset,
122
118
  since: options.since,
123
- type: options.type,
119
+ type: typeIsAliased ? undefined : options.type,
124
120
  ref: options.ref,
121
+ ...(pushLimitToSql ? { limit: options.limit } : {}),
125
122
  });
126
- // Apply tag filters in application code (same as the old JSONL implementation).
127
- const events = rawEvents.filter((envelope) => {
123
+ const filtered = rawEvents.filter((envelope) => {
124
+ if (typeIsAliased && !SAVE_SYNC_EVENT_TYPE_ALIASES.has(envelope.eventType))
125
+ return false;
126
+ if (options.runId !== undefined && envelope.metadata?.runId !== options.runId)
127
+ return false;
128
+ // Apply tag filters after the indexed state.db read.
128
129
  const tags = envelope.metadata?.tags ?? [];
129
130
  if (options.excludeTags?.some((t) => tags.includes(t)))
130
131
  return false;
@@ -132,98 +133,15 @@ export function readEvents(options = {}, ctx) {
132
133
  return false;
133
134
  return true;
134
135
  });
136
+ // `filtered` is ascending by id; slicing off the end keeps the MOST
137
+ // RECENT `limit` events post-filter, matching the SQL-pushdown path's
138
+ // semantics exactly. `nextOffset` intentionally stays `nextId` — the
139
+ // durable resume cursor tracks the underlying SQL read, not this
140
+ // display-only truncation.
141
+ const events = options.limit !== undefined && !pushLimitToSql ? filtered.slice(-options.limit) : filtered;
135
142
  return { events, nextOffset: nextId };
136
143
  }
137
144
  finally {
138
145
  db.close();
139
146
  }
140
147
  }
141
- /**
142
- * Follow the events table in state.db. Polls at `intervalMs` (default 75ms)
143
- * and emits every new event to `onEvent`. Resolves when `signal` aborts, when
144
- * `maxEvents` events have been observed, or when `maxDurationMs` elapses.
145
- *
146
- * The polling cursor is a monotonic SQLite rowid so concurrent writers cannot
147
- * cause skips: between two reads we always pick up everything inserted since
148
- * the last `nextOffset`.
149
- */
150
- export async function tailEvents(options = {}, ctx) {
151
- const intervalMs = options.intervalMs ?? 75;
152
- const collected = [];
153
- let cursor = options.sinceOffset ?? 0;
154
- // Seed the cursor: if the caller passed --since (timestamp) but no
155
- // sinceOffset, do an initial filtered read so they see history before
156
- // we start polling. This matches the documented behaviour of `tail
157
- // --since`: emit existing events that match, then follow.
158
- if (options.sinceOffset === undefined) {
159
- const initial = readEvents({
160
- since: options.since,
161
- type: options.type,
162
- ref: options.ref,
163
- excludeTags: options.excludeTags,
164
- includeTags: options.includeTags,
165
- }, ctx);
166
- for (const event of initial.events) {
167
- collected.push(event);
168
- options.onEvent?.(event);
169
- if (options.maxEvents !== undefined && collected.length >= options.maxEvents) {
170
- return { events: collected, nextOffset: initial.nextOffset, reason: "maxEvents" };
171
- }
172
- }
173
- cursor = initial.nextOffset;
174
- }
175
- const startedAt = Date.now();
176
- return new Promise((resolve) => {
177
- let resolved = false;
178
- let timer;
179
- function finish(reason) {
180
- if (resolved)
181
- return;
182
- resolved = true;
183
- if (timer)
184
- clearInterval(timer);
185
- resolve({ events: collected, nextOffset: cursor, reason });
186
- }
187
- function tick() {
188
- try {
189
- const result = readEvents({
190
- sinceOffset: cursor,
191
- type: options.type,
192
- ref: options.ref,
193
- excludeTags: options.excludeTags,
194
- includeTags: options.includeTags,
195
- }, ctx);
196
- cursor = result.nextOffset;
197
- for (const event of result.events) {
198
- // Apply --since filter inside the polling loop too — the cursor is
199
- // rowid-based so it can hand us events the user filtered out.
200
- if (options.since && event.ts && event.ts < options.since)
201
- continue;
202
- collected.push(event);
203
- options.onEvent?.(event);
204
- if (options.maxEvents !== undefined && collected.length >= options.maxEvents) {
205
- finish("maxEvents");
206
- return;
207
- }
208
- }
209
- }
210
- catch {
211
- // Non-fatal: stay in the loop.
212
- }
213
- if (options.maxDurationMs !== undefined && Date.now() - startedAt >= options.maxDurationMs) {
214
- finish("maxDuration");
215
- }
216
- }
217
- if (options.signal) {
218
- if (options.signal.aborted) {
219
- finish("signal");
220
- return;
221
- }
222
- options.signal.addEventListener("abort", () => finish("signal"), { once: true });
223
- }
224
- timer = setInterval(tick, intervalMs);
225
- // Run one tick immediately so callers don't have to wait an interval
226
- // for events written in the same tick as the tail starts.
227
- tick();
228
- });
229
- }
@@ -6,11 +6,12 @@
6
6
  *
7
7
  * By construction `changes[0].after === payload.content`; consumers read
8
8
  * through this accessor so the single-content assumption lives in ONE place
9
- * once multi-file proposals (consolidate ops) ride the envelope. Falls back
10
- * to the payload for legacy in-memory objects that predate the envelope.
11
- * Typed structurally (not against `Proposal`) so this module stays
12
- * dependency-free.
9
+ * once multi-file proposals (consolidate ops) ride the envelope. Typed
10
+ * structurally (not against `Proposal`) so this module stays dependency-free.
13
11
  */
14
12
  export function proposalContent(p) {
15
- return p.changes?.[0]?.after ?? p.payload.content;
13
+ const content = p.changes[0]?.after;
14
+ if (content === undefined)
15
+ throw new Error("Proposal primary change has no content.");
16
+ return content;
16
17
  }