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
@@ -4,9 +4,12 @@
4
4
  import fs from "node:fs";
5
5
  import path from "node:path";
6
6
  import { parseFrontmatter } from "../../core/asset/frontmatter.js";
7
- import { conceptIdFromTypeName, parseRefInput } from "../../core/asset/resolve-ref.js";
7
+ import { conceptIdFromTypeName, parseRefInput, resolveRef } from "../../core/asset/resolve-ref.js";
8
+ import { loadConfig } from "../../core/config/config.js";
8
9
  import { NotFoundError, rethrowIfTestIsolationError, UsageError } from "../../core/errors.js";
9
10
  import { readEvents } from "../../core/events.js";
11
+ import { getDbPath } from "../../core/paths.js";
12
+ import { deriveInstallations } from "../../indexer/installations.js";
10
13
  import { getWritableStashDirs, resolveSourceEntries } from "../../indexer/search/search-source.js";
11
14
  import { resolveAssetPath } from "../../indexer/walk/path-resolver.js";
12
15
  import { closeDatabase, openExistingDatabase, openReadonlyExistingDatabase, } from "../../storage/repositories/index-connection.js";
@@ -19,6 +22,17 @@ import { improveStateReadRefs } from "./source-identity.js";
19
22
  // Eligibility / candidate-selection predicates for improve. Free functions
20
23
  // (no akmImprove closure state) extracted from improve.ts to shrink the
21
24
  // orchestrator and make candidate selection independently testable.
25
+ /**
26
+ * Open the index for eligibility queries, or `undefined` when no index exists
27
+ * yet. `openExistingDatabase` refuses to create a missing `index.db` (see
28
+ * index-connection.ts) — for eligibility, "no index" simply means nothing is
29
+ * eligible, exactly like the readOnly arm's `undefined`.
30
+ */
31
+ function openEligibilityDb(readOnly) {
32
+ if (readOnly)
33
+ return openReadonlyExistingDatabase();
34
+ return fs.existsSync(getDbPath()) ? openExistingDatabase() : undefined;
35
+ }
22
36
  export function resolveImproveScope(scope) {
23
37
  const trimmed = scope?.trim();
24
38
  if (!trimmed)
@@ -28,9 +42,8 @@ export function resolveImproveScope(scope) {
28
42
  return { mode: "ref", value: trimmed };
29
43
  }
30
44
  catch (err) {
31
- // Open type token (chunk 1.5, D1.5-1): a bare word with no `type:name`
32
- // shape (no colon) is a `--scope <type>` filter attempt, not a ref — ANY
33
- // such word is now accepted, including foreign/unknown type strings,
45
+ // A bare word with no ref separator is a `--scope <type>` filter attempt,
46
+ // not a ref. Any such word is accepted, including foreign/unknown type strings,
34
47
  // which simply match zero entries downstream (a read-only query filter,
35
48
  // not a data-acceptance gate, so no deny-list is needed here: an
36
49
  // unrecognized type just matches nothing, since nothing is ever indexed
@@ -42,7 +55,7 @@ export function resolveImproveScope(scope) {
42
55
  // deliberately-removed type like tool/vault, D1.5-6) — that must still
43
56
  // surface as a real error, not be silently absorbed into a type filter
44
57
  // that will never match anything.
45
- if (!trimmed.includes(":")) {
58
+ if (!/[/:#]/.test(trimmed)) {
46
59
  return { mode: "type", value: trimmed };
47
60
  }
48
61
  const message = err instanceof Error ? err.message : String(err);
@@ -50,7 +63,8 @@ export function resolveImproveScope(scope) {
50
63
  }
51
64
  }
52
65
  /**
53
- * Dedupe a list of eligible refs by `ref`, preserving first-seen order. Used to
66
+ * Dedupe eligible refs by their durable item ref when available, preserving
67
+ * the first candidate and its display ref. Used to
54
68
  * merge the eligibility sources (feedback-signal, Layer-2 proactive-maintenance,
55
69
  * high-salience) without admitting a ref into the loop twice.
56
70
  */
@@ -58,44 +72,76 @@ export function dedupeRefs(refs) {
58
72
  const seen = new Set();
59
73
  const out = [];
60
74
  for (const r of refs) {
61
- if (seen.has(r.ref))
75
+ const key = r.itemRef ?? r.ref;
76
+ if (seen.has(key))
62
77
  continue;
63
- seen.add(r.ref);
78
+ seen.add(key);
64
79
  out.push(r);
65
80
  }
66
81
  return out;
67
82
  }
68
- export async function collectEligibleRefs(scope, stashDir, improveProfile) {
69
- return collectEligibleRefsFromIndex(scope, stashDir, improveProfile, false);
83
+ export async function collectEligibleRefs(scope, stashDir, improveProfile, config) {
84
+ return collectEligibleRefsFromIndex(scope, stashDir, improveProfile, false, config);
70
85
  }
71
86
  /** Dry-run planner path: query an existing index without creating or mutating it. */
72
- export async function collectEligibleRefsReadOnly(scope, stashDir, improveProfile) {
73
- return collectEligibleRefsFromIndex(scope, stashDir, improveProfile, true);
87
+ export async function collectEligibleRefsReadOnly(scope, stashDir, improveProfile, config) {
88
+ return collectEligibleRefsFromIndex(scope, stashDir, improveProfile, true, config);
74
89
  }
75
- async function collectEligibleRefsFromIndex(scope, stashDir, improveProfile, readOnly) {
90
+ async function collectEligibleRefsFromIndex(scope, stashDir, improveProfile, readOnly, configOverride) {
91
+ const config = configOverride ?? loadConfig();
76
92
  if (scope.mode === "ref" && scope.value) {
77
- const parsed = parseRefInput(scope.value);
78
- const writableDirs = new Set(getWritableStashDirs(stashDir).map((dir) => path.resolve(dir)));
79
- const filePath = await findAssetFilePath(scope.value, stashDir, writableDirs);
80
- if (!filePath) {
93
+ const writableDirs = new Set(getWritableStashDirs(stashDir, config).map((dir) => path.resolve(dir)));
94
+ let db;
95
+ try {
96
+ db = openEligibilityDb(readOnly);
97
+ if (!db) {
98
+ return { plannedRefs: [], memorySummary: { eligible: 0, derived: 0 }, strategyFilteredRefs: [] };
99
+ }
100
+ const entries = getAllEntries(db);
101
+ const entriesByItemRef = new Map(entries.flatMap((entry) => entry.bundleId && entry.conceptId ? [[`${entry.bundleId}//${entry.conceptId}`, entry]] : []));
102
+ const installations = deriveInstallations(resolveSourceEntries(stashDir, config));
103
+ const resolved = resolveRef(scope.value, {
104
+ defaultBundle: config.defaultBundle,
105
+ bundles: installations.map((installation) => ({
106
+ id: installation.id,
107
+ hasConcept: (conceptId) => entriesByItemRef.has(`${installation.id}//${conceptId}`),
108
+ })),
109
+ });
110
+ const indexed = entriesByItemRef.get(`${resolved.bundle}//${resolved.conceptId}`);
111
+ if (!indexed?.bundleId || !indexed.conceptId || !fs.existsSync(indexed.filePath)) {
112
+ if (await findAssetFilePath(scope.value, stashDir)) {
113
+ return { plannedRefs: [], memorySummary: { eligible: 0, derived: 0 }, strategyFilteredRefs: [] };
114
+ }
115
+ throw new NotFoundError(`Asset not found in the selected writable source: ${scope.value}`, "ASSET_NOT_FOUND");
116
+ }
117
+ if (!isEntryInScope(indexed.stashDir, indexed.filePath, stashDir) ||
118
+ !isEntryInWritableSource(indexed.stashDir, indexed.filePath, writableDirs)) {
119
+ return { plannedRefs: [], memorySummary: { eligible: 0, derived: 0 }, strategyFilteredRefs: [] };
120
+ }
121
+ const itemRef = `${indexed.bundleId}//${indexed.conceptId}`;
81
122
  return {
82
- plannedRefs: [],
83
- memorySummary: { eligible: 0, derived: 0 },
123
+ plannedRefs: [{ ref: indexed.conceptId, itemRef, reason: "scope-ref", filePath: indexed.filePath }],
124
+ memorySummary: {
125
+ eligible: indexed.entry.type === "memory" ? 1 : 0,
126
+ derived: indexed.entry.type === "memory" && indexed.entry.name.endsWith(".derived") ? 1 : 0,
127
+ },
84
128
  strategyFilteredRefs: [],
85
129
  };
86
130
  }
87
- return {
88
- plannedRefs: [{ ref: scope.value, reason: "scope-ref", filePath }],
89
- memorySummary: {
90
- eligible: parsed.type === "memory" ? 1 : 0,
91
- derived: parsed.type === "memory" && parsed.name.endsWith(".derived") ? 1 : 0,
92
- },
93
- strategyFilteredRefs: [],
94
- };
131
+ catch (error) {
132
+ if (error instanceof Error && /no such table:\s*entries/i.test(error.message)) {
133
+ return { plannedRefs: [], memorySummary: { eligible: 0, derived: 0 }, strategyFilteredRefs: [] };
134
+ }
135
+ throw error;
136
+ }
137
+ finally {
138
+ if (db)
139
+ closeDatabase(db);
140
+ }
95
141
  }
96
142
  let sources;
97
143
  try {
98
- sources = resolveSourceEntries(stashDir);
144
+ sources = resolveSourceEntries(stashDir, config);
99
145
  }
100
146
  catch {
101
147
  return { plannedRefs: [], memorySummary: { eligible: 0, derived: 0 }, strategyFilteredRefs: [] };
@@ -107,7 +153,7 @@ async function collectEligibleRefsFromIndex(scope, stashDir, improveProfile, rea
107
153
  // or remote stashes that the user did not mark writable.
108
154
  let writableDirs;
109
155
  try {
110
- writableDirs = getWritableStashDirs(stashDir);
156
+ writableDirs = getWritableStashDirs(stashDir, config);
111
157
  }
112
158
  catch {
113
159
  writableDirs = sources.slice(0, 1).map((s) => s.path); // fallback: primary only
@@ -115,7 +161,7 @@ async function collectEligibleRefsFromIndex(scope, stashDir, improveProfile, rea
115
161
  const writableDirSet = new Set(writableDirs.map((d) => path.resolve(d)));
116
162
  let db;
117
163
  try {
118
- db = readOnly ? openReadonlyExistingDatabase() : openExistingDatabase();
164
+ db = openEligibilityDb(readOnly);
119
165
  if (!db) {
120
166
  return { plannedRefs: [], memorySummary: { eligible: 0, derived: 0 }, strategyFilteredRefs: [] };
121
167
  }
@@ -127,7 +173,7 @@ async function collectEligibleRefsFromIndex(scope, stashDir, improveProfile, rea
127
173
  return isEntryInWritableSource(indexed.stashDir, indexed.filePath, writableDirSet);
128
174
  });
129
175
  const planned = new Map();
130
- const profileFiltered = new Map();
176
+ const strategyFiltered = new Map();
131
177
  let memoryEligible = 0;
132
178
  let memoryDerived = 0;
133
179
  for (const indexed of entries) {
@@ -136,11 +182,16 @@ async function collectEligibleRefsFromIndex(scope, stashDir, improveProfile, rea
136
182
  // xrefs, and `displayRef` output spelling. `.itemRef` below stays the
137
183
  // fully-qualified durable key.
138
184
  const ref = conceptIdFromTypeName(indexed.entry.type, indexed.entry.name);
139
- // Chunk-5 flip F5d (Step 4): the durable `item_ref` (`<bundle>//<concept-id>`),
140
- // reconstructed from the mapper-unlocked provenance columns with ZERO extra
141
- // queries (D-R3 — derived from the resolved index entry, never raw input).
142
- // `undefined` for a NULL-provenance (pre-flip / write-back) row; the durable
143
- // writers then fall back to the legacy `type:name` key.
185
+ try {
186
+ parseRefInput(ref);
187
+ }
188
+ catch (error) {
189
+ if (error instanceof UsageError || error instanceof NotFoundError)
190
+ continue;
191
+ throw error;
192
+ }
193
+ // Derive the durable item_ref from indexed provenance without another query.
194
+ // A provenance-free row uses the short conceptId ref for improve state.
144
195
  const itemRef = indexed.bundleId && indexed.conceptId ? `${indexed.bundleId}//${indexed.conceptId}` : undefined;
145
196
  const isDerived = indexed.entry.name.endsWith(".derived");
146
197
  // `.derived` memories are LLM-inferred and intentionally skip reflect
@@ -150,16 +201,16 @@ async function collectEligibleRefsFromIndex(scope, stashDir, improveProfile, rea
150
201
  // 2026-05-21: 11 derived refs re-planned every hour during idle periods.
151
202
  // The cleanup phase (analyzeMemoryCleanup) inspects derived memories
152
203
  // independently of `plannedRefs`, so dropping them here loses nothing.
153
- if (!isDerived && !planned.has(ref) && !profileFiltered.has(ref)) {
154
- // 2026-05-27: extend the .derived precedent to profile-incompatible
204
+ if (!isDerived && !planned.has(ref) && !strategyFiltered.has(ref)) {
205
+ // 2026-05-27: extend the .derived precedent to strategy-incompatible
155
206
  // refs. If every per-ref pass (reflect + distill) on the active
156
- // profile would refuse this ref, drop it from `plannedRefs`. The
207
+ // strategy would refuse this ref, drop it from `plannedRefs`. The
157
208
  // caller emits `improve_skipped { reason: strategy_filtered_all_passes }`
158
209
  // once `eventsCtx` is available so the audit trail is preserved in a
159
210
  // single event per ref instead of 2× synthetic actions per run.
160
211
  // Background: see /tmp/akm-health-investigations/planner-profile-metrics-deep-analysis.md
161
212
  if (improveProfile && isStrategyFilteredForAllPasses(ref, improveProfile)) {
162
- profileFiltered.set(ref, {
213
+ strategyFiltered.set(ref, {
163
214
  ref,
164
215
  reason: "strategy_filtered_all_passes",
165
216
  filePath: indexed.filePath,
@@ -184,13 +235,13 @@ async function collectEligibleRefsFromIndex(scope, stashDir, improveProfile, rea
184
235
  return {
185
236
  plannedRefs: [...planned.values()],
186
237
  memorySummary: { eligible: memoryEligible, derived: memoryDerived },
187
- strategyFilteredRefs: [...profileFiltered.values()],
238
+ strategyFilteredRefs: [...strategyFiltered.values()],
188
239
  };
189
240
  }
190
241
  catch (error) {
191
- // The bun-test isolation guard must never be downgraded to "empty plan".
242
+ // Empty-stash setup paths can open index.db before its schema exists.
192
243
  rethrowIfTestIsolationError(error);
193
- if (error instanceof NotFoundError || error instanceof Error) {
244
+ if (error instanceof Error && /no such table:\s*entries/i.test(error.message)) {
194
245
  return { plannedRefs: [], memorySummary: { eligible: 0, derived: 0 }, strategyFilteredRefs: [] };
195
246
  }
196
247
  throw error;
@@ -247,9 +298,8 @@ export function memoryCleanupParentRef(scope, stashDir) {
247
298
  continue;
248
299
  const raw = fs.readFileSync(candidate, "utf8");
249
300
  const fm = parseFrontmatter(raw).data;
250
- // The `source:` backref (the `derived_from` channel) is read through the
251
- // legacy-tolerant parseMemoryRef, whose NORMALISED output is now the 0.9.0
252
- // `memories/<name>` conceptId (Group-C item 2). That is exactly what
301
+ // The `source:` backref is normalized to the `memories/<name>` conceptId.
302
+ // That is exactly what
253
303
  // analyzeMemoryCleanup's parentRef filter compares against — resolveParentRef
254
304
  // emits the same conceptId — so the two sites stay in lockstep.
255
305
  const parent = parseMemoryRef(typeof fm.source === "string" ? fm.source : undefined);
@@ -282,7 +332,7 @@ export function isLessonCandidate(ref) {
282
332
  * which was true *only* for `lesson:*` refs — exactly the set distill refuses.
283
333
  * The result: every hourly run re-queued the same lesson refs, the same skip
284
334
  * message returned, and no work was ever done. See
285
- * `tests/commands/improve-distill-planner-skip-lessons.test.ts`.
335
+ * `tests/integration/commands/improve-distill-planner-skip-lessons.test.ts`.
286
336
  */
287
337
  export function isDistillCandidateRef(ref, stashDir) {
288
338
  const parsed = parseRefInput(ref);
@@ -325,13 +375,12 @@ export function shouldDistillMemoryRef(ref, stashDir) {
325
375
  * metadata events are ignored so a stray `akm feedback <ref>` invocation
326
376
  * without a flag doesn't trigger downstream re-processing.
327
377
  */
328
- export function buildLatestFeedbackTsMap(refs, sinceIso, sourceName, includeLegacyBare = false, itemRefByRef) {
378
+ export function buildLatestFeedbackTsMap(refs, sinceIso, itemRefByRef) {
329
379
  const out = new Map();
330
380
  if (refs.length === 0)
331
381
  return out;
332
- // Chunk-5 flip F5e — dual-arm on [item_ref, durable, bare] so an item_ref-
333
- // keyed feedback event resolves once the writers emit it. // Chunk-8: [item_ref].
334
- const refByDurableKey = new Map(refs.flatMap((ref) => improveStateReadRefs(ref, sourceName, includeLegacyBare, itemRefByRef?.get(ref)).map((key) => [key, ref])));
382
+ // Correlate item_ref-keyed events and conceptId-keyed direct invocations.
383
+ const refByDurableKey = new Map(refs.flatMap((ref) => improveStateReadRefs(ref, itemRefByRef?.get(ref)).map((key) => [key, ref])));
335
384
  const { events } = readEvents({ type: "feedback", since: sinceIso });
336
385
  for (const e of events) {
337
386
  const ref = e.ref ? refByDurableKey.get(e.ref) : undefined;
@@ -351,18 +400,17 @@ export function buildLatestFeedbackTsMap(refs, sinceIso, sourceName, includeLega
351
400
  * Latest proposal timestamp per input-ref, filtered by source ('reflect' or
352
401
  * 'distill'). Reads the corresponding `*_invoked` events from state.db —
353
402
  * these events are emitted at proposal creation time and carry the *input*
354
- * asset ref (memory:foo, skill:bar, etc.) directly. We use them rather than
403
+ * asset ref (`memories/foo`, `skills/bar`, etc.) directly. We use them rather than
355
404
  * `listProposals` because distill proposals are keyed by the derived
356
405
  * lesson/knowledge ref, not the source memory — joining back through the
357
406
  * payload would be fragile.
358
407
  */
359
- export function buildLatestProposalTsMap(refs, source, sourceName, includeLegacyBare = false, itemRefByRef) {
408
+ export function buildLatestProposalTsMap(refs, source, itemRefByRef) {
360
409
  const out = new Map();
361
410
  if (refs.length === 0)
362
411
  return out;
363
- // Chunk-5 flip F5e — dual-arm on [item_ref, durable, bare] so an item_ref-
364
- // keyed *_invoked event resolves once the writers emit it. // Chunk-8: [item_ref].
365
- const refByDurableKey = new Map(refs.flatMap((ref) => improveStateReadRefs(ref, sourceName, includeLegacyBare, itemRefByRef?.get(ref)).map((key) => [key, ref])));
412
+ // Correlate item_ref-keyed events and conceptId-keyed direct invocations.
413
+ const refByDurableKey = new Map(refs.flatMap((ref) => improveStateReadRefs(ref, itemRefByRef?.get(ref)).map((key) => [key, ref])));
366
414
  const eventType = source === "reflect" ? "reflect_invoked" : "distill_invoked";
367
415
  const { events } = readEvents({ type: eventType });
368
416
  for (const e of events) {
@@ -479,6 +527,6 @@ export async function findAssetFilePath(ref, stashDir, writableDirSet) {
479
527
  writableDirSet,
480
528
  directoryIndexNames: ["SKILL.md"],
481
529
  preserveDirectNameFallback: true,
482
- honorOrigin: false,
530
+ honorOrigin: true,
483
531
  });
484
532
  }
@@ -2,31 +2,30 @@
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
4
  /**
5
- * CLI surface for `akm extract`.
5
+ * CLI surface for `akm proposal extract` (formerly the top-level `akm
6
+ * extract`, moved under the `proposal` group in the 0.9 CLI overhaul, S8 —
7
+ * see src/commands/proposal/proposal-cli.ts for its registration).
6
8
  *
7
9
  * Examples:
8
- * akm extract --type claude-code --session-id <id>
9
- * akm extract --type claude-code --since 24h
10
- * akm extract --type opencode --since 7d --dry-run
11
- * akm extract --auto # iterate all available harnesses
12
- * akm extract --type claude-code --location /custom/path --session-id <id>
10
+ * akm proposal extract --type claude-code --session-id <id>
11
+ * akm proposal extract --type claude-code --since 24h
12
+ * akm proposal extract --type opencode --since 7d --dry-run
13
+ * akm proposal extract --auto # iterate all available harnesses
14
+ * akm proposal extract --type claude-code --location /custom/path --session-id <id>
13
15
  *
14
16
  * Output is the AkmExtractResult JSON envelope (or an aggregated one when
15
17
  * `--auto` runs multiple harnesses).
16
18
  */
17
- import fs from "node:fs";
18
- import path from "node:path";
19
19
  import { getStringArg } from "../../cli/parse-args.js";
20
20
  import { defineJsonCommand, EXIT_CODES, output } from "../../cli/shared.js";
21
21
  import { loadConfig } from "../../core/config/config.js";
22
22
  import { UsageError } from "../../core/errors.js";
23
- import { getAvailableHarnesses, getWatchTargets } from "../../integrations/session-logs/index.js";
24
- import { akmExtract, resolveStandaloneExtractPlan, } from "./extract.js";
25
- import { akmExtractWatch } from "./extract-watch.js";
23
+ import { getAvailableHarnesses } from "../../integrations/session-logs/index.js";
24
+ import { akmExtract, resolveStandaloneExtractPlan } from "./extract.js";
26
25
  export const extractCommand = defineJsonCommand({
27
26
  meta: {
28
27
  name: "extract",
29
- description: "Extract durable insights from native session files (claude-code, opencode) and queue them as proposals. Replaces the legacy session-checkpoint hook.",
28
+ description: "Extract durable insights from native session files (claude-code, opencode) and queue them as proposals.",
30
29
  },
31
30
  args: {
32
31
  type: {
@@ -72,15 +71,6 @@ export const extractCommand = defineJsonCommand({
72
71
  type: "string",
73
72
  description: "Improve strategy supplying extract behavior and engine. Mutually exclusive with --engine.",
74
73
  },
75
- watch: {
76
- type: "boolean",
77
- description: "Watch harness session-log directories and run extract on change (debounced). Stays alive until SIGINT/SIGTERM.",
78
- default: false,
79
- },
80
- "debounce-ms": {
81
- type: "string",
82
- description: "Debounce window in ms for --watch (default 2000).",
83
- },
84
74
  },
85
75
  async run({ args }) {
86
76
  const type = getStringArg(args, "type") ?? "";
@@ -101,17 +91,10 @@ export const extractCommand = defineJsonCommand({
101
91
  if (engine && strategy) {
102
92
  throw new UsageError("--engine and --strategy are mutually exclusive. Pick one.", "INVALID_FLAG_VALUE");
103
93
  }
104
- const watch = args.watch === true;
105
- const debounceMs = typeof args["debounce-ms"] === "string" && args["debounce-ms"] !== ""
106
- ? Number.parseInt(args["debounce-ms"], 10)
107
- : 2000;
108
- if (watch && (!Number.isFinite(debounceMs) || debounceMs <= 0)) {
109
- throw new UsageError(`--debounce-ms must be a positive integer (got "${args["debounce-ms"]}").`, "INVALID_FLAG_VALUE");
110
- }
111
- if (!watch && auto && type) {
94
+ if (auto && type) {
112
95
  throw new UsageError("--auto and --type are mutually exclusive. Pick one.", "INVALID_FLAG_VALUE");
113
96
  }
114
- if (!watch && !auto && !type) {
97
+ if (!auto && !type) {
115
98
  throw new UsageError("--type is required (or pass --auto to try every available harness).", "MISSING_REQUIRED_ARGUMENT");
116
99
  }
117
100
  const config = loadConfig();
@@ -120,10 +103,6 @@ export const extractCommand = defineJsonCommand({
120
103
  ...(strategy ? { strategy } : {}),
121
104
  ...(timeoutMs !== undefined ? { timeoutMs } : {}),
122
105
  });
123
- if (watch) {
124
- await runWatchMode({ debounceMs, dryRun, force, config, resolvedPlan, ...(since ? { since } : {}) });
125
- return;
126
- }
127
106
  const commonOptions = Object.freeze({
128
107
  ...(sessionId ? { sessionId } : {}),
129
108
  ...(location ? { location } : {}),
@@ -164,7 +143,7 @@ export const extractCommand = defineJsonCommand({
164
143
  // Signal failure to callers/schedulers when every harness failed. output()
165
144
  // only renders; without this a scheduled run exits 0 on a total failure
166
145
  // and the breakage is invisible to exit-code monitoring. process.exitCode
167
- // (not process.exit) lets stdout flush and the watcher/timers settle.
146
+ // (not process.exit) lets stdout flush before the process exits.
168
147
  if (!ok)
169
148
  process.exitCode = EXIT_CODES.GENERAL;
170
149
  return;
@@ -175,101 +154,3 @@ export const extractCommand = defineJsonCommand({
175
154
  process.exitCode = EXIT_CODES.GENERAL;
176
155
  },
177
156
  });
178
- /**
179
- * A thin {@link WatchEventSource} over `fs.watch` for each configured root.
180
- * This adapter is the ONLY place a real `fs.watch` is created (the core stays
181
- * injectable + fully unit-tested); it is intentionally not unit-covered.
182
- *
183
- * `fs.watch(dir, { recursive: true })` is unreliable for recursive mode on some
184
- * Node/Bun/Linux combinations. A root that cannot be watched is skipped while
185
- * successfully-created watchers continue running.
186
- */
187
- function createFsWatchEventSource(roots) {
188
- return {
189
- subscribe(listener) {
190
- const watchers = [];
191
- for (const root of roots) {
192
- try {
193
- const watcher = fs.watch(root, { recursive: true }, (_event, filename) => {
194
- if (!filename)
195
- return;
196
- const filePath = path.isAbsolute(filename.toString())
197
- ? filename.toString()
198
- : path.join(root, filename.toString());
199
- listener({ path: filePath });
200
- });
201
- watchers.push(watcher);
202
- }
203
- catch {
204
- // A root that can't be watched is skipped.
205
- }
206
- }
207
- return () => {
208
- for (const w of watchers) {
209
- try {
210
- w.close();
211
- }
212
- catch {
213
- // best-effort teardown
214
- }
215
- }
216
- };
217
- },
218
- };
219
- }
220
- /** Snapshot the CLI-resolved watch options once and reuse them for every debounced trigger. */
221
- export function createExtractWatchTrigger(options, extractFn = akmExtract) {
222
- const snapshot = Object.freeze({ ...options });
223
- return async (harnessName) => {
224
- await extractFn({ type: harnessName, ...snapshot });
225
- };
226
- }
227
- /**
228
- * Run `akm extract --watch`: watch every available harness's session-log
229
- * roots and run extract (debounced, per-harness) on change. Stays alive until
230
- * SIGINT/SIGTERM, then stops cleanly. PROCESS-HYGIENE: stop() removes every
231
- * watcher + pending timer before the process exits.
232
- */
233
- async function runWatchMode(opts) {
234
- const targets = getWatchTargets();
235
- if (targets.length === 0) {
236
- output("extract", {
237
- schemaVersion: 1,
238
- ok: false,
239
- shape: "extract-watch-started",
240
- warnings: ["no watchable harness session-log directories found on this machine"],
241
- watching: [],
242
- });
243
- return;
244
- }
245
- const allRoots = targets.flatMap((t) => t.roots);
246
- const eventSource = createFsWatchEventSource(allRoots);
247
- const onTrigger = createExtractWatchTrigger({
248
- dryRun: opts.dryRun,
249
- force: opts.force,
250
- config: opts.config,
251
- resolvedPlan: opts.resolvedPlan,
252
- ...(opts.since ? { since: opts.since } : {}),
253
- });
254
- const handle = akmExtractWatch({
255
- roots: targets,
256
- eventSource,
257
- debounceMs: opts.debounceMs,
258
- onTrigger,
259
- });
260
- output("extract", {
261
- schemaVersion: 1,
262
- ok: true,
263
- shape: "extract-watch-started",
264
- debounceMs: opts.debounceMs,
265
- watching: allRoots,
266
- });
267
- await new Promise((resolve) => {
268
- const shutdown = () => {
269
- handle.stop();
270
- resolve();
271
- };
272
- process.once("SIGINT", shutdown);
273
- process.once("SIGTERM", shutdown);
274
- });
275
- }