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
@@ -26,8 +26,7 @@ import os from "node:os";
26
26
  import path from "node:path";
27
27
  import { assembleAssetFromString, serializeFrontmatter } from "../../core/asset/asset-serialize.js";
28
28
  import { parseFrontmatter } from "../../core/asset/frontmatter.js";
29
- import { stripMarkdownFences } from "../../core/asset/markdown.js";
30
- import { parseRefInput } from "../../core/asset/resolve-ref.js";
29
+ import { conceptIdFromTypeName, parseRefInput } from "../../core/asset/resolve-ref.js";
31
30
  import { DESCRIPTION_MAX_CHARS, requiresDescription } from "../../core/authoring-rules.js";
32
31
  import { loadConfig } from "../../core/config/config.js";
33
32
  import { ConfigError } from "../../core/errors.js";
@@ -36,8 +35,10 @@ import { lintLessonContent } from "../../core/lesson-lint.js";
36
35
  import { parseEmbeddedJsonResponse } from "../../core/parse.js";
37
36
  import { redactSensitiveText } from "../../core/redaction.js";
38
37
  import { resolveStandardsContext } from "../../core/standards/resolve-standards-context.js";
38
+ import { warn } from "../../core/warn.js";
39
39
  import { lookup } from "../../indexer/indexer.js";
40
40
  import { DEFAULT_LLM_TIMEOUT_MS } from "../../integrations/agent/config.js";
41
+ import { fallbackAnnouncement, NO_ENGINE_MESSAGE_SUFFIX, NO_ENGINE_REMEDY, withEngineFallback, } from "../../integrations/agent/engine-fallback.js";
41
42
  import { resolveEngine } from "../../integrations/agent/engine-resolution.js";
42
43
  import { buildReflectOutputRepairPrompt, buildReflectPrompt, extractDraftConfidence, parseAgentProposalPayload, } from "../../integrations/agent/prompts.js";
43
44
  import { materializeLlmRunnerConnection, resolveImproveProcessRunner, runnerIsLlm, runnerSupportsFileWrite, } from "../../integrations/agent/runner.js";
@@ -54,7 +55,7 @@ import { emitProposal } from "./proposal-envelope.js";
54
55
  import { classifyReflectChange } from "./reflect-noise.js";
55
56
  import { createRunContext, resolveRunStashDir } from "./run-context.js";
56
57
  import { MAX_REJECTED_PROPOSALS } from "./shared.js";
57
- import { bareImproveRef, durableImproveRef, improveStateReadRefs } from "./source-identity.js";
58
+ import { durableImproveRef, improveStateReadRefs } from "./source-identity.js";
58
59
  const MAX_FEEDBACK_LINES = 10;
59
60
  const MAX_GLOBAL_FEEDBACK_LINES = 20;
60
61
  /**
@@ -63,10 +64,9 @@ const MAX_GLOBAL_FEEDBACK_LINES = 20;
63
64
  * all assets so `akm reflect` can operate in a general "review recent
64
65
  * signals" mode. Best-effort — a missing or empty events stream returns `[]`.
65
66
  */
66
- function readRecentFeedback(ref, legacyRef) {
67
+ function readRecentFeedback(ref) {
67
68
  try {
68
- const result = readEvents({ type: "feedback", ...(ref && !legacyRef ? { ref } : {}) });
69
- const events = ref && legacyRef ? result.events.filter((event) => event.ref === ref || event.ref === legacyRef) : result.events;
69
+ const events = readEvents({ type: "feedback", ...(ref ? { ref } : {}) }).events;
70
70
  const lines = [];
71
71
  const limit = ref ? MAX_FEEDBACK_LINES : MAX_GLOBAL_FEEDBACK_LINES;
72
72
  for (const event of events.slice(-limit)) {
@@ -116,7 +116,7 @@ export const REFLECT_ALLOWED_TYPES = new Set([
116
116
  * LLM tried to rewrite them.
117
117
  *
118
118
  * Observed regression: proposal `26941510` (May 2026) renamed
119
- * `skill:openpalm-stack-diagnostics`'s `name` field to `"diagnostic-checklist"`.
119
+ * `skills/openpalm-stack-diagnostics`'s `name` field to `"diagnostic-checklist"`.
120
120
  */
121
121
  const PROTECTED_FRONTMATTER_FIELDS = new Set(["name", "ref", "id", "slug", "type"]);
122
122
  /**
@@ -146,12 +146,13 @@ function readRejectedProposals(stash, ref) {
146
146
  /**
147
147
  * Synthesize a tmp draft-file path for the agent/sdk file-write contract.
148
148
  *
149
- * Mirrors `src/commands/propose.ts:163-178` — when the runner is agent-CLI or
150
- * the OpenCode SDK, we instruct the agent to write the proposal body directly
151
- * to this file instead of inlining it in JSON on stdout. This bypasses two
149
+ * Mirrors the draft-path synthesis in `src/commands/proposal/propose.ts` —
150
+ * when the runner is agent-CLI or the OpenCode SDK, we instruct the agent to
151
+ * write the proposal body directly to this file instead of inlining it in
152
+ * JSON on stdout. This bypasses two
152
153
  * known failure modes for long assets: (a) ARG_MAX truncation on prompt
153
154
  * round-trips through fenced JSON, and (b) embedded-JSON parser brittleness
154
- * on multi-KB bodies (e.g. the `knowledge:systems/KOKORO_USAGE_GUIDE` 8.4KB
155
+ * on multi-KB bodies (e.g. the `knowledge/systems/KOKORO_USAGE_GUIDE` 8.4KB
155
156
  * payload that produced 4/5 `parse_error` in May 2026 reflect validation).
156
157
  *
157
158
  * The path lives under {@link os.tmpdir} and embeds the (sanitized) ref +
@@ -194,13 +195,13 @@ function hasRelatedSkillSource(content, skillRef) {
194
195
  const sources = parsed.data.sources;
195
196
  return Array.isArray(sources) && sources.some((source) => typeof source === "string" && source.trim() === skillRef);
196
197
  }
197
- async function readRelatedLessons(ctx, stash, ref, parsedRef, sourceName, itemRef, legacyBareState) {
198
+ async function readRelatedLessons(ctx, stash, ref, parsedRef, itemRef) {
198
199
  if (parsedRef.type !== "skill")
199
200
  return [];
200
201
  const related = new Map();
201
202
  const derivedLessonRef = deriveLessonRef(ref);
202
203
  const candidateRefs = new Set([derivedLessonRef]);
203
- const derivedLessonPath = path.join(stash, "lessons", `${derivedLessonRef.slice("lesson:".length)}.md`);
204
+ const derivedLessonPath = path.join(stash, "lessons", `${parseRefInput(derivedLessonRef).name}.md`);
204
205
  if (fs.existsSync(derivedLessonPath)) {
205
206
  // WI-9.10: genuine content read — routed through the per-invocation asset
206
207
  // memo (D6). No write to this same path happens later in this invocation,
@@ -208,16 +209,13 @@ async function readRelatedLessons(ctx, stash, ref, parsedRef, sourceName, itemRe
208
209
  related.set(derivedLessonRef, { ref: derivedLessonRef, content: ctx.readAsset(derivedLessonPath) });
209
210
  }
210
211
  try {
211
- // Chunk-5 flip F5f (Step 6 readers) dual-arm the distill_invoked filter on
212
- // [item_ref, durable, bare] so an event keyed under EITHER grammar resolves
213
- // once the writers emit item_ref. Dormant: item_ref NULL through improve
214
- // today, so the key set is [durable] byte-identically. // Chunk-8: [item_ref].
215
- const distillInvokedKeys = new Set(improveStateReadRefs(ref, sourceName, legacyBareState ?? false, itemRef));
212
+ // Match events using the candidate's single durable state key.
213
+ const distillInvokedKeys = new Set(improveStateReadRefs(ref, itemRef));
216
214
  const feedbackEvents = readEvents({ type: "distill_invoked" }).events.filter((event) => event.ref !== undefined && distillInvokedKeys.has(event.ref));
217
215
  for (const event of feedbackEvents) {
218
- const lessonRef = typeof event.metadata?.lessonRef === "string" ? event.metadata.lessonRef : undefined;
219
- if (lessonRef?.startsWith("lesson:"))
220
- candidateRefs.add(lessonRef);
216
+ const proposalRef = typeof event.metadata?.proposalRef === "string" ? event.metadata.proposalRef : undefined;
217
+ if (proposalRef && lenientRefType(proposalRef) === "lesson")
218
+ candidateRefs.add(proposalRef);
221
219
  }
222
220
  }
223
221
  catch {
@@ -225,7 +223,7 @@ async function readRelatedLessons(ctx, stash, ref, parsedRef, sourceName, itemRe
225
223
  }
226
224
  for (const candidateRef of candidateRefs) {
227
225
  try {
228
- const filePath = await findAssetFilePath(durableImproveRef(candidateRef, sourceName), stash);
226
+ const filePath = await findAssetFilePath(durableImproveRef(candidateRef), stash);
229
227
  if (!filePath || !fs.existsSync(filePath))
230
228
  continue;
231
229
  const content = ctx.readAsset(filePath);
@@ -245,7 +243,7 @@ async function readRelatedLessons(ctx, stash, ref, parsedRef, sourceName, itemRe
245
243
  if (!hasRelatedSkillSource(content, ref))
246
244
  continue;
247
245
  const lessonName = fileName.slice(0, -3);
248
- const lessonRef = `lesson:${lessonName}`;
246
+ const lessonRef = conceptIdFromTypeName("lesson", lessonName);
249
247
  if (!related.has(lessonRef)) {
250
248
  related.set(lessonRef, { ref: lessonRef, content });
251
249
  }
@@ -295,58 +293,22 @@ async function readRelatedLessons(ctx, stash, ref, parsedRef, sourceName, itemRe
295
293
  /**
296
294
  * Returns true only when `stdout` is a recognised AKM proposal-skip signal.
297
295
  *
298
- * Two accepted forms:
299
- * 1. Structured JSON: `{ skipped: true }` or `{ reason: "<known-skip-reason>" }`
300
- * 2. Legacy text: any line matching `/proposal skipped/i`
301
- *
302
- * The previous regex `/cooldown/i` was intentionally broadened to avoid
303
- * false-positives on real agent error messages that incidentally contain the
304
- * word "cooldown" (e.g. "rate limit cooldown exceeded"). Only the tightly
305
- * scoped forms above are treated as legitimate skip signals.
296
+ * Accepted forms are structured JSON: `{ skipped: true }` or
297
+ * `{ reason: "<known-skip-reason>" }`.
306
298
  */
307
299
  function isStructuredCooldownSignal(stdout) {
308
300
  try {
309
301
  const parsed = JSON.parse(stdout.trim());
310
302
  if (parsed?.skipped === true)
311
303
  return true;
312
- if (typeof parsed?.reason === "string" &&
313
- // WI-6.4 vocabulary (fingerprint_match / rejection_backoff) plus the
314
- // legacy tokens — old agent payloads may still carry the retired names.
315
- [
316
- "fingerprint_match",
317
- "rejection_backoff",
318
- "duplicate_pending",
319
- "content_hash_match",
320
- "cooldown",
321
- "below_threshold",
322
- ].includes(parsed.reason))
304
+ if (typeof parsed?.reason === "string" && ["fingerprint_match", "rejection_backoff"].includes(parsed.reason))
323
305
  return true;
324
306
  }
325
307
  catch {
326
308
  // Non-JSON stdout is never a structured cooldown signal.
327
309
  }
328
- // Legacy text signal emitted by older proposal output lines.
329
- return /proposal skipped/i.test(stdout);
310
+ return false;
330
311
  }
331
- /**
332
- * Fallback payload parser for reflect agent stdout (R-6 / #375).
333
- *
334
- * When the agent does not emit valid JSON (old-style agents, SDK mode without
335
- * structured output support), this function attempts to recover a proposal
336
- * payload from the raw markdown output. The parser is deliberately strict —
337
- * it requires the content to have a complete proposal structure (frontmatter
338
- * with required fields or a full heading + body).
339
- *
340
- * Strictness rationale: The previous implementation accepted any markdown
341
- * starting with `#` or `---`, which admitted malformed / hallucinated content
342
- * as valid proposals. Anthropic agent best practices recommend structured
343
- * output when the SDK supports it; this tighter fallback is the safety net.
344
- *
345
- * For SDK runners, structured output (tool-call schema) should be used
346
- * instead of this fallback. That wiring is tracked separately (full SDK
347
- * structured-output integration); for now this tighter parser applies to all
348
- * modes and is the primary R-6 deliverable.
349
- */
350
312
  /**
351
313
  * Best-effort asset type for a maybe-ref string, in the 0.9.0 `[bundle//]conceptId`
352
314
  * grammar (`""` when it does not parse). Replaces the pre-0.9.0 `ref.split(":")[0]`
@@ -364,55 +326,6 @@ function lenientRefType(ref) {
364
326
  return "";
365
327
  }
366
328
  }
367
- function fallbackPayloadFromRawContent(stdout, ref, sdkRunner = false) {
368
- if (!ref)
369
- return undefined;
370
- const trimmed = stripMarkdownFences(stdout).trim();
371
- if (!trimmed)
372
- return undefined;
373
- const targetType = lenientRefType(ref);
374
- if (!looksLikeAssetContent(trimmed, sdkRunner, targetType))
375
- return undefined;
376
- return { ref, content: trimmed };
377
- }
378
- /**
379
- * Determine whether raw agent output looks like a valid asset payload (R-6 / #375).
380
- *
381
- * Tightened from the previous `startsWith("#") || startsWith("---")`:
382
- *
383
- * - YAML frontmatter (`---`): must contain a `description:` field (the only
384
- * required frontmatter key in v1 spec). This eliminates empty `---\n---\n`
385
- * blocks and pure delimiter sequences as valid payloads.
386
- * - Heading start (`#`): must have at least 3 non-blank lines after the heading,
387
- * to ensure there is actual body content and not just a title stub.
388
- * - For SDK runners: additionally requires `when_to_use:` for
389
- * lesson types (full structured output will replace this in a future PR).
390
- */
391
- function looksLikeAssetContent(value, sdkRunner = false, targetType) {
392
- if (value.startsWith("---")) {
393
- // YAML frontmatter must contain at least a description field.
394
- const fmEnd = value.indexOf("\n---", 4);
395
- if (fmEnd === -1)
396
- return false;
397
- const fmBlock = value.slice(0, fmEnd + 4);
398
- const hasDescription = /^description\s*:/m.test(fmBlock);
399
- if (!hasDescription)
400
- return false;
401
- // In SDK mode, lesson assets additionally require a when_to_use field.
402
- // Use the target ref type rather than frontmatter type: (which is non-standard).
403
- if (sdkRunner && targetType === "lesson") {
404
- return /^when_to_use\s*:/m.test(fmBlock);
405
- }
406
- return true;
407
- }
408
- if (value.startsWith("#")) {
409
- // Heading + at least 2 non-blank lines (heading + at least one body line).
410
- // This rejects pure title stubs (`# Title\n`) but accepts minimal valid content.
411
- const lines = value.split("\n").filter((l) => l.trim().length > 0);
412
- return lines.length >= 2;
413
- }
414
- return false;
415
- }
416
329
  /**
417
330
  * Split a markdown blob into `[frontmatterText, bodyText]`.
418
331
  *
@@ -824,9 +737,8 @@ function parseDirectReflectOutput(raw, mode, targetRef) {
824
737
  *
825
738
  * Returns an {@link AgentRunResult}-shaped object so it can slot into the same
826
739
  * dispatch loop as agent-based runners. Production calls extract the selected
827
- * direct-LLM contract and normalize it to proposal JSON in `stdout`; legacy
828
- * unit callers that omit `outputMode` retain raw stdout. Errors are captured
829
- * into the result rather than thrown.
740
+ * direct-LLM contract and normalize it to proposal JSON in `stdout`. Errors
741
+ * are captured into the result rather than thrown.
830
742
  */
831
743
  export async function runReflectViaLlm(opts) {
832
744
  const start = Date.now();
@@ -875,24 +787,13 @@ export async function runReflectViaLlm(opts) {
875
787
  exitCode,
876
788
  reason,
877
789
  error: msg,
878
- ...(opts.outputMode ? { parsed: { outputMode: opts.outputMode, repairAttempts } } : {}),
790
+ parsed: { outputMode: opts.outputMode, repairAttempts },
879
791
  };
880
792
  };
881
793
  try {
882
794
  if (opts.signal?.aborted)
883
795
  throw new Error("Reflect request aborted");
884
796
  const stdout = await call(messages);
885
- // Preserve the old raw-response seam for direct unit callers. Production
886
- // akmReflect always sets outputMode and receives a normalized payload.
887
- if (!opts.outputMode) {
888
- return {
889
- ok: true,
890
- stdout,
891
- stderr: "",
892
- durationMs: Date.now() - start,
893
- exitCode: 0,
894
- };
895
- }
896
797
  let payload;
897
798
  let acceptedOutput = stdout;
898
799
  try {
@@ -1112,6 +1013,7 @@ function createReflectProposal(args) {
1112
1013
  : basePayloadFrontmatter;
1113
1014
  const createInput = {
1114
1015
  ref: payload.ref,
1016
+ ...(options.target ? { target: options.target } : {}),
1115
1017
  source: "reflect",
1116
1018
  sourceRun: `reflect-${Date.now()}`,
1117
1019
  payload: {
@@ -1173,12 +1075,11 @@ function createReflectProposal(args) {
1173
1075
  /**
1174
1076
  * Resolve the agent's proposal payload from a successful run: the file-write
1175
1077
  * contract path (read `lastDraftPath`, extract self-rated confidence) or the
1176
- * legacy JSON-stdout path (`parseAgentProposalPayload`, with the raw-content
1177
- * fallback and cooldown-signal reclassification). Returns the payload or a
1178
- * terminal failure envelope. Extracted verbatim from `akmReflect`.
1078
+ * JSON-stdout path used by direct LLM runners. Returns the payload or a terminal
1079
+ * failure envelope.
1179
1080
  */
1180
1081
  function resolveReflectPayload(args) {
1181
- const { result, lastDraftPath, sensitiveValues, options, runnerSpec, engineName, emitReflectFailed } = args;
1082
+ const { result, lastDraftPath, sensitiveValues, options, engineName, emitReflectFailed } = args;
1182
1083
  // 6. Resolve the proposal content.
1183
1084
  //
1184
1085
  // Path A (file-write contract — preferred for agent/sdk runners on long
@@ -1187,9 +1088,7 @@ function resolveReflectPayload(args) {
1187
1088
  // payload. The `EXCESSIVE_EXPANSION`/schema-shape gates downstream still
1188
1089
  // apply — they validate content, not transport.
1189
1090
  //
1190
- // Path B (legacy JSON stdout): the agent inlined the proposal body in
1191
- // JSON on stdout. Falls through to `parseAgentProposalPayload`. Also the
1192
- // path used by the LLM HTTP runner, which cannot honour file-write.
1091
+ // Path B (JSON stdout): the direct LLM runner cannot honour file-write.
1193
1092
  const draftFileExists = lastDraftPath !== undefined && fs.existsSync(lastDraftPath) && fs.statSync(lastDraftPath).size > 0;
1194
1093
  const draftSignaled = stdoutSignalsDraftWritten(result.stdout);
1195
1094
  if (draftSignaled && lastDraftPath && !draftFileExists) {
@@ -1236,10 +1135,6 @@ function resolveReflectPayload(args) {
1236
1135
  return { payload: parseAgentProposalPayload(result.stdout ?? "") };
1237
1136
  }
1238
1137
  catch (err) {
1239
- const fallback = fallbackPayloadFromRawContent(result.stdout ?? "", options.ref, runnerSpec.kind === "sdk");
1240
- if (fallback) {
1241
- return { payload: fallback };
1242
- }
1243
1138
  // Reclassify cooldown/skip messages that arrive as stdout text instead of
1244
1139
  // valid proposal JSON. These are legitimate skip signals, not parse failures,
1245
1140
  // and should not pollute reflectFailedActions or recentErrors injection.
@@ -1292,11 +1187,17 @@ function resolveReflectRunner(options) {
1292
1187
  runnerSpec = processRunner;
1293
1188
  }
1294
1189
  else {
1295
- const defaultEngine = config.defaults?.engine;
1190
+ const { config: engineConfig, fallbackEngineName } = withEngineFallback(config);
1191
+ const defaultEngine = engineConfig.defaults?.engine;
1192
+ // Announced, never silent — same contract as the workflow freeze boundary
1193
+ // and the task runner. Only this arm can select the synthesized engine.
1194
+ const engineAnnouncement = fallbackAnnouncement(fallbackEngineName, defaultEngine);
1195
+ if (engineAnnouncement)
1196
+ warn(engineAnnouncement);
1296
1197
  if (!defaultEngine) {
1297
- throw new ConfigError("reflect requires --engine or defaults.engine.", "INVALID_CONFIG_FILE");
1198
+ throw new ConfigError(`reflect ${NO_ENGINE_MESSAGE_SUFFIX} ${NO_ENGINE_REMEDY}`, "INVALID_CONFIG_FILE");
1298
1199
  }
1299
- runnerSpec = resolveEngine(defaultEngine, config);
1200
+ runnerSpec = resolveEngine(defaultEngine, engineConfig);
1300
1201
  }
1301
1202
  if (options.eventSource === "improve" && !runnerIsLlm(runnerSpec)) {
1302
1203
  throw new ConfigError(`Unattended improve requires an LLM engine for reflect; engine "${runnerSpec.engine ?? options.engine ?? "unknown"}" is tool-capable.`, "INVALID_CONFIG_FILE", "Set defaults.llmEngine or improve.strategies.<name>.processes.reflect.engine to an LLM engine.");
@@ -1335,7 +1236,7 @@ async function resolveReflectSource(options, stash, emitReflectFailed) {
1335
1236
  schemaVersion: 2,
1336
1237
  ok: false,
1337
1238
  reason: "unsupported_type",
1338
- error: `Reflect refused: asset type "${parsedRef.type}" is not supported by reflect (only markdown-canonical types are allowed: ${[...REFLECT_ALLOWED_TYPES].sort().join(", ")}). Use \`akm propose\` or edit the file directly.`,
1239
+ error: `Reflect refused: asset type "${parsedRef.type}" is not supported by reflect (only markdown-canonical types are allowed: ${[...REFLECT_ALLOWED_TYPES].sort().join(", ")}). Use \`akm proposal new\` or edit the file directly.`,
1339
1240
  ref: options.ref,
1340
1241
  exitCode: null,
1341
1242
  },
@@ -1347,10 +1248,9 @@ async function resolveReflectSource(options, stash, emitReflectFailed) {
1347
1248
  }
1348
1249
  else {
1349
1250
  try {
1350
- // Chunk-5 flip F5f — resolve the source asset by item_ref when the planner
1351
- // supplied one (the index entry carries it), else the pre-flip durable ref.
1352
- // Dormant: item_ref NULL today, so this reduces to the durable ref.
1353
- const qualifiedRef = options.itemRef ?? durableImproveRef(options.ref, options.sourceName);
1251
+ // Resolve the source by item_ref when planning supplied one, otherwise
1252
+ // use the input conceptId.
1253
+ const qualifiedRef = options.itemRef ?? durableImproveRef(options.ref);
1354
1254
  const localFilePath = await findAssetFilePath(qualifiedRef, stash);
1355
1255
  if (localFilePath && fs.existsSync(localFilePath)) {
1356
1256
  assetContent = fs.readFileSync(localFilePath, "utf8");
@@ -1420,7 +1320,7 @@ async function runReflectRefineIterations(args) {
1420
1320
  // Issue A (#reflect-pipeline file-write contract): when the runner can
1421
1321
  // touch the filesystem, instruct the agent to write the proposal body
1422
1322
  // to a tmp file instead of inlining it in JSON. Avoids parse failures
1423
- // on long bodies (e.g. knowledge:systems/KOKORO_USAGE_GUIDE 8.4KB).
1323
+ // on long bodies (e.g. knowledge/systems/KOKORO_USAGE_GUIDE 8.4KB).
1424
1324
  ...(iterDraftPath ? { draftFilePath: iterDraftPath } : {}),
1425
1325
  ...(outputMode ? { outputMode } : {}),
1426
1326
  });
@@ -1448,10 +1348,10 @@ async function runReflectRefineIterations(args) {
1448
1348
  ...(options.signal ? { signal: options.signal } : {}),
1449
1349
  priorDraft,
1450
1350
  iteration: iter,
1451
- ...(outputMode === "json_schema"
1351
+ ...(spec.connection.supportsJsonSchema
1452
1352
  ? { responseSchema: options.ref ? REFLECT_JSON_SCHEMA : REFLECT_UNSCOPED_JSON_SCHEMA }
1453
1353
  : {}),
1454
- ...(outputMode ? { outputMode } : {}),
1354
+ outputMode: spec.connection.supportsJsonSchema ? "json_schema" : "framed_markdown",
1455
1355
  ...(options.ref ? { targetRef: options.ref } : {}),
1456
1356
  allowRepair: repairAttempts === 0,
1457
1357
  chat: options.chat,
@@ -1534,9 +1434,8 @@ function emitReflectInvokedAndBuildFailureEmitter(options) {
1534
1434
  // attempt regardless of downstream success/failure.
1535
1435
  appendEvent({
1536
1436
  eventType: "reflect_invoked",
1537
- // Chunk-5 flip F5f — key on item_ref when the planner resolved one, else the
1538
- // pre-flip source-qualified durable ref (dormant: item_ref NULL today).
1539
- ...(options.ref ? { ref: options.itemRef ?? durableImproveRef(options.ref, options.sourceName) } : {}),
1437
+ // Key on item_ref when planning supplied one, otherwise the conceptId.
1438
+ ...(options.ref ? { ref: options.itemRef ?? durableImproveRef(options.ref) } : {}),
1540
1439
  metadata: {
1541
1440
  ...(options.task ? { task: options.task } : {}),
1542
1441
  ...(options.engine ? { engine: options.engine } : {}),
@@ -1583,11 +1482,9 @@ export async function akmReflect(options = {}) {
1583
1482
  // 4. Build the shared prompt inputs — feedback, hints, lessons, rejected
1584
1483
  // proposals. These are stable across refinement iterations; only the
1585
1484
  // `priorDraft` field changes per-iteration (R-1 / #372).
1586
- const feedback = readRecentFeedback(options.ref ? durableImproveRef(options.ref, options.sourceName) : undefined, options.ref && options.legacyBareState ? bareImproveRef(options.ref) : undefined);
1485
+ const feedback = readRecentFeedback(options.ref ? (options.itemRef ?? durableImproveRef(options.ref)) : undefined);
1587
1486
  const schemaHints = buildSchemaHints(parsedRef?.type ?? "", assetContent);
1588
- const relatedLessons = options.ref && parsedRef
1589
- ? await readRelatedLessons(assetCtx, stash, options.ref, parsedRef, options.sourceName, options.itemRef, options.legacyBareState)
1590
- : [];
1487
+ const relatedLessons = options.ref && parsedRef ? await readRelatedLessons(assetCtx, stash, options.ref, parsedRef, options.itemRef) : [];
1591
1488
  // Reflexion-style verbal-RL: inject rejected proposals so the agent avoids
1592
1489
  // reproducing proposals that have already been reviewed and refused.
1593
1490
  const rejectedProposals = readRejectedProposals(stash, options.ref);
@@ -1603,7 +1500,7 @@ export async function akmReflect(options = {}) {
1603
1500
  });
1604
1501
  // Track every draft file path we synthesize so cleanup can remove them on
1605
1502
  // every return path (success and failure). Mirrors propose's unlink pattern
1606
- // in `src/commands/propose.ts:215-226` but generalised to N refinement
1503
+ // in `src/commands/proposal/propose.ts` but generalised to N refinement
1607
1504
  // iterations. Always called via {@link cleanupDrafts} below.
1608
1505
  const draftPathsToCleanup = [];
1609
1506
  // Best-effort unlink: tolerate already-deleted files (we may have unlinked
@@ -1668,7 +1565,6 @@ export async function akmReflect(options = {}) {
1668
1565
  lastDraftPath,
1669
1566
  sensitiveValues,
1670
1567
  options,
1671
- runnerSpec,
1672
1568
  engineName,
1673
1569
  emitReflectFailed,
1674
1570
  });
@@ -1686,8 +1582,8 @@ export async function akmReflect(options = {}) {
1686
1582
  payload = { ...payload, content: redactSensitiveText(payload.content, sensitiveValues) };
1687
1583
  // 6b. Validate payload.ref === options.ref (R-3 / #366).
1688
1584
  // A hallucinating agent can silently retarget proposals to a different ref.
1689
- // This guard normalises both refs through parseRefInput (dual-grammar) so origin-prefix
1690
- // differences do not cause false positives, then rejects mismatches.
1585
+ // Parse both current refs so an optional bundle prefix does not cause a false
1586
+ // positive, then reject genuine concept mismatches.
1691
1587
  // References: CRITIC (arXiv:2305.11738), CoVe (arXiv:2309.11495).
1692
1588
  if (options.ref) {
1693
1589
  try {
@@ -235,132 +235,21 @@ export function computeSalience(inputs) {
235
235
  const rankScore = Math.min(1, Math.max(0, rawRankScore));
236
236
  return { encoding, outcome, retrieval, rankScore, encodingSource };
237
237
  }
238
+ // ── state.db persistence ─────────────────────────────────────────────────────
239
+ //
240
+ // The three sub-scores live in state.db::asset_salience. Raw SQL now lives in
241
+ // storage/repositories/salience-repository.ts (#672 part 2) — extracted
242
+ // verbatim, only relocated behind the repository boundary. Re-exported here so
243
+ // existing importers of this module resolve unchanged. Migrations live in
244
+ // state-db.ts (migration 009).
245
+ export { getAllRankScores, getAssetSalience, getConsecutiveNoOps, recordNoOp, resetConsecutiveNoOps, upsertAssetSalience, } from "../../storage/repositories/salience-repository.js";
238
246
  /**
239
247
  * Does this row carry a genuine content-derived `encoding_salience` (#644)?
240
248
  *
241
- * Returns true when the provenance flag is `"content"`. For legacy rows
242
- * (`encoding_source === null`, written before migration 015) we apply a
243
- * conservative heuristic: treat the stored value as content-derived only when it
244
- * does NOT equal the pure type-weight stub for the asset's type — because before
245
- * the #644 fix every run overwrote real scores with the stub, a value that still
246
- * differs from the stub must have been content-written and never re-clobbered.
247
- * When the type cannot be determined (no `type` given) a null-provenance row is
248
- * treated as a stub (the safe default).
249
- */
250
- export function isContentEncodingRow(row, type) {
251
- if (row.encoding_source === "content")
252
- return true;
253
- if (row.encoding_source === "type-stub")
254
- return false;
255
- // Legacy NULL provenance: differ-from-stub heuristic.
256
- if (!type)
257
- return false;
258
- const stub = DEFAULT_TYPE_ENCODING_WEIGHTS[type] ?? DEFAULT_ENCODING_SALIENCE;
259
- return Math.abs(row.encoding_salience - stub) > 1e-9;
260
- }
261
- /**
262
- * Upsert salience scores for one asset into state.db.
263
- *
264
- * Idempotent: safe to call every run; updates the outcome / retrieval / rank
265
- * columns on conflict.
266
- *
267
- * #644 — encoding provenance guard: the `encoding_salience` + `encoding_source`
268
- * columns are NOT lowered from a real content-derived score to a type-weight
269
- * stub. When the stored row is `encoding_source = 'content'` and the incoming
270
- * vector is a `type-stub` fallback, the stored encoding score and its provenance
271
- * are preserved (only the other sub-scores and `rank_score` advance). A `content`
272
- * write always wins; a `type-stub` write only seeds a row that has no content
273
- * score yet. This stops the improve loop's type-weight fallback re-asserting the
274
- * stub over a distill-written score on every run.
275
- *
276
- * NOTE: when the guard preserves the stored encoding score, the incoming
277
- * `vector.rankScore` (computed from the stub encoding) is still written. Callers
278
- * that want the rank_score to reflect the preserved content score should pass the
279
- * stored content score back in as `inputs.encodingSalience` to `computeSalience`
280
- * — which the improve loop does. The guard here is the defensive backstop.
281
- */
282
- export function upsertAssetSalience(db, ref, vector, now) {
283
- const ts = now ?? Date.now();
284
- db.prepare(`INSERT INTO asset_salience
285
- (asset_ref, encoding_salience, outcome_salience, retrieval_salience, rank_score, consecutive_no_ops, updated_at, encoding_source)
286
- VALUES (?, ?, ?, ?, ?, 0, ?, ?)
287
- ON CONFLICT(asset_ref) DO UPDATE SET
288
- -- #644: never lower a real content-derived score to a type-weight stub.
289
- -- Keep the stored encoding score + provenance when the stored row is
290
- -- 'content' and the incoming write is a 'type-stub' fallback.
291
- encoding_salience = CASE
292
- WHEN asset_salience.encoding_source = 'content' AND excluded.encoding_source = 'type-stub'
293
- THEN asset_salience.encoding_salience
294
- ELSE excluded.encoding_salience
295
- END,
296
- encoding_source = CASE
297
- WHEN asset_salience.encoding_source = 'content' AND excluded.encoding_source = 'type-stub'
298
- THEN asset_salience.encoding_source
299
- ELSE excluded.encoding_source
300
- END,
301
- outcome_salience = excluded.outcome_salience,
302
- retrieval_salience = excluded.retrieval_salience,
303
- rank_score = excluded.rank_score,
304
- updated_at = excluded.updated_at`).run(ref, vector.encoding, vector.outcome, vector.retrieval, vector.rankScore, ts, vector.encodingSource ?? "type-stub");
305
- }
306
- /**
307
- * Load the salience row for one asset, or undefined if not yet computed.
308
- */
309
- export function getAssetSalience(db, ref) {
310
- const row = db
311
- .prepare(`SELECT asset_ref, encoding_salience, outcome_salience, retrieval_salience,
312
- rank_score, consecutive_no_ops, updated_at, encoding_source
313
- FROM asset_salience WHERE asset_ref = ?`)
314
- .get(ref);
315
- // Bun SQLite returns null (not undefined) when no row found.
316
- return row == null ? undefined : row;
317
- }
318
- /**
319
- * Load ALL rank scores from the asset_salience table (full-stash query).
320
- *
321
- * Used by the forgetting-safety report (plan §WS-1 step 7) to compute stash-wide
322
- * rank positions rather than pool-relative positions. Returns an empty Map when the
323
- * table is empty (first WS-1 run = no pre-existing rows).
324
- *
325
- * Order is unspecified; callers must sort before assigning 1-indexed positions.
326
- */
327
- export function getAllRankScores(db) {
328
- const rows = db.prepare("SELECT asset_ref, rank_score FROM asset_salience").all();
329
- const result = new Map();
330
- for (const row of rows) {
331
- result.set(row.asset_ref, row.rank_score);
332
- }
333
- return result;
334
- }
335
- // ── Plasticity helpers ────────────────────────────────────────────────────────
336
- /**
337
- * Increment `consecutive_no_ops` for an asset. Called after a no-op reflect/distill.
338
- * Has NO effect on `rank_score` — the plasticity counter only dampens consolidation
339
- * selection, not retrieval ranking. See plan §WS-1 step 8.
340
- *
341
- * Invariant: recordNoOp must never originate rank_score semantics. If the asset has
342
- * no salience row yet (persistence's best-effort try/catch may have swallowed an
343
- * error), we do nothing — a no-op counter is meaningless without a rank_score row,
344
- * and a synthetic INSERT would fabricate a rank_score=0 entry that could produce
345
- * false catastrophic-forgetting signals in buildRankChangeReport.
346
- */
347
- export function recordNoOp(db, ref) {
348
- db.prepare(`UPDATE asset_salience SET consecutive_no_ops = consecutive_no_ops + 1, updated_at = ? WHERE asset_ref = ?`).run(Date.now(), ref);
349
- // If changes === 0 the asset has no salience row yet — leave the table unchanged.
350
- }
351
- /**
352
- * Reset `consecutive_no_ops` to 0 when an asset produces an accepted change.
353
- * Call after a successful proposal acceptance or detected mutation.
354
- */
355
- export function resetConsecutiveNoOps(db, ref) {
356
- db.prepare(`UPDATE asset_salience SET consecutive_no_ops = 0, updated_at = ? WHERE asset_ref = ?`).run(Date.now(), ref);
357
- }
358
- /**
359
- * Return the `consecutive_no_ops` count for one asset. 0 when unknown.
249
+ * Unknown provenance is not treated as content-derived.
360
250
  */
361
- export function getConsecutiveNoOps(db, ref) {
362
- const row = db.prepare(`SELECT consecutive_no_ops FROM asset_salience WHERE asset_ref = ?`).get(ref);
363
- return row?.consecutive_no_ops ?? 0;
251
+ export function isContentEncodingRow(row) {
252
+ return row.encoding_source === "content";
364
253
  }
365
254
  // ── Consolidation-selection dampener constants ────────────────────────────────
366
255
  //