akm-cli 0.9.0-beta.9 → 0.9.0-rc.1

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 (381) hide show
  1. package/CHANGELOG.md +715 -0
  2. package/README.md +12 -4
  3. package/dist/akm +38 -0
  4. package/dist/akm-migrate-storage +38 -0
  5. package/dist/assets/help/help-improve.md +9 -6
  6. package/dist/assets/hints/cli-hints-full.md +6 -5
  7. package/dist/assets/profiles/default.json +9 -4
  8. package/dist/assets/profiles/frequent.json +1 -1
  9. package/dist/assets/profiles/memory-focus.json +1 -1
  10. package/dist/assets/profiles/proactive-maintenance.json +25 -0
  11. package/dist/assets/profiles/quick.json +1 -1
  12. package/dist/assets/profiles/recombine-only.json +21 -0
  13. package/dist/assets/profiles/reflect-distill.json +30 -0
  14. package/dist/assets/profiles/synthesize.json +15 -0
  15. package/dist/assets/profiles/thorough.json +1 -1
  16. package/dist/assets/prompts/consolidate-system.md +23 -0
  17. package/dist/assets/prompts/contradiction-judge.md +33 -0
  18. package/dist/assets/prompts/distill-knowledge-system.md +22 -0
  19. package/dist/assets/prompts/distill-lesson-system.md +36 -0
  20. package/dist/assets/prompts/extract-session.md +11 -3
  21. package/dist/assets/prompts/graph-extract-system.md +1 -0
  22. package/dist/assets/prompts/graph-extract-user-prompt.md +1 -1
  23. package/dist/assets/prompts/memory-infer-system.md +1 -0
  24. package/dist/assets/prompts/memory-infer-user.md +5 -0
  25. package/dist/assets/prompts/metadata-enhance-system.md +1 -0
  26. package/dist/assets/prompts/procedural-system.md +44 -0
  27. package/dist/assets/prompts/recombine-system.md +40 -0
  28. package/dist/assets/prompts/staleness-detect-system.md +6 -0
  29. package/dist/assets/prompts/validate-summary-judge.md +1 -0
  30. package/dist/assets/prompts/workflow-unit-preamble.md +26 -0
  31. package/dist/assets/stash-skeleton/facts/conventions/assets/agent.md +38 -0
  32. package/dist/assets/stash-skeleton/facts/conventions/assets/command.md +38 -0
  33. package/dist/assets/stash-skeleton/facts/conventions/assets/fact.md +39 -0
  34. package/dist/assets/stash-skeleton/facts/conventions/assets/knowledge.md +40 -0
  35. package/dist/assets/stash-skeleton/facts/conventions/assets/lesson.md +43 -0
  36. package/dist/assets/stash-skeleton/facts/conventions/assets/memory.md +38 -0
  37. package/dist/assets/stash-skeleton/facts/conventions/assets/script.md +43 -0
  38. package/dist/assets/stash-skeleton/facts/conventions/assets/skill.md +40 -0
  39. package/dist/assets/stash-skeleton/facts/conventions/assets/workflow.md +43 -0
  40. package/dist/assets/templates/html/health.html +281 -111
  41. package/dist/assets/wiki/ingest-workflow-template.md +45 -16
  42. package/dist/assets/wiki/schema-template.md +4 -4
  43. package/dist/cli/clack.js +56 -0
  44. package/dist/cli/config-migrate.js +7 -1
  45. package/dist/cli/confirm.js +1 -1
  46. package/dist/cli/parse-args.js +46 -1
  47. package/dist/cli/shared.js +28 -0
  48. package/dist/cli.js +25 -21
  49. package/dist/commands/agent/agent-dispatch.js +3 -2
  50. package/dist/commands/agent/agent-support.js +0 -7
  51. package/dist/commands/agent/contribute-cli.js +26 -7
  52. package/dist/commands/config-cli.js +26 -13
  53. package/dist/commands/env/child-env.js +47 -0
  54. package/dist/commands/env/env-binding.js +95 -0
  55. package/dist/commands/env/env-cli.js +228 -292
  56. package/dist/commands/env/env.js +14 -67
  57. package/dist/commands/env/secret-cli.js +140 -138
  58. package/dist/commands/feedback-cli.js +156 -155
  59. package/dist/commands/graph/graph-cli.js +5 -13
  60. package/dist/commands/graph/graph.js +3 -3
  61. package/dist/commands/health/advisories.js +151 -0
  62. package/dist/commands/health/checks.js +103 -16
  63. package/dist/commands/health/html-report.js +447 -81
  64. package/dist/commands/health/improve-metrics.js +771 -0
  65. package/dist/commands/health/llm-usage.js +65 -0
  66. package/dist/commands/health/md-report.js +103 -0
  67. package/dist/commands/health/metrics.js +278 -0
  68. package/dist/commands/health/stash-exposure.js +46 -0
  69. package/dist/commands/health/surfaces.js +216 -0
  70. package/dist/commands/health/task-runs.js +135 -0
  71. package/dist/commands/health/types.js +26 -0
  72. package/dist/commands/health/windows.js +195 -0
  73. package/dist/commands/health.js +91 -1091
  74. package/dist/commands/improve/anti-collapse.js +170 -0
  75. package/dist/commands/improve/calibration.js +161 -0
  76. package/dist/commands/improve/collapse-detector.js +421 -0
  77. package/dist/commands/improve/consolidate/chunking.js +141 -0
  78. package/dist/commands/improve/consolidate/eligibility.js +64 -0
  79. package/dist/commands/improve/consolidate/merge.js +145 -0
  80. package/dist/commands/improve/consolidate/sanitize.js +231 -0
  81. package/dist/commands/{lint.js → improve/consolidate/types.js} +1 -1
  82. package/dist/commands/improve/consolidate.js +1295 -1277
  83. package/dist/commands/improve/dedup.js +482 -0
  84. package/dist/commands/improve/distill/content-repair.js +202 -0
  85. package/dist/commands/improve/distill/promote-memory.js +229 -0
  86. package/dist/commands/improve/distill/quality-gate.js +236 -0
  87. package/dist/commands/improve/distill-guards.js +127 -0
  88. package/dist/commands/improve/distill-promotion-policy.js +826 -167
  89. package/dist/commands/improve/distill.js +228 -605
  90. package/dist/commands/improve/eligibility.js +434 -0
  91. package/dist/commands/improve/encoding-salience.js +205 -0
  92. package/dist/commands/improve/extract-cli.js +179 -59
  93. package/dist/commands/improve/extract-prompt.js +54 -3
  94. package/dist/commands/improve/extract-watch.js +140 -0
  95. package/dist/commands/improve/extract.js +409 -43
  96. package/dist/commands/improve/feedback-valence.js +54 -0
  97. package/dist/commands/improve/hot-probation.js +45 -0
  98. package/dist/commands/improve/improve-auto-accept.js +157 -10
  99. package/dist/commands/improve/improve-cli.js +115 -73
  100. package/dist/commands/improve/improve-profiles.js +28 -8
  101. package/dist/commands/improve/improve-result-file.js +15 -25
  102. package/dist/commands/improve/improve-session.js +58 -0
  103. package/dist/commands/improve/improve.js +485 -2764
  104. package/dist/commands/improve/locks.js +154 -0
  105. package/dist/commands/improve/loop-stages.js +1100 -0
  106. package/dist/commands/improve/memory/memory-belief.js +14 -15
  107. package/dist/commands/improve/memory/memory-contradiction-detect.js +83 -60
  108. package/dist/commands/improve/memory/memory-improve.js +27 -27
  109. package/dist/commands/improve/outcome-loop.js +270 -0
  110. package/dist/commands/improve/preparation.js +2002 -0
  111. package/dist/commands/improve/proactive-maintenance.js +37 -35
  112. package/dist/commands/improve/procedural.js +398 -0
  113. package/dist/commands/improve/recombine.js +818 -0
  114. package/dist/commands/improve/reflect-noise.js +0 -0
  115. package/dist/commands/improve/reflect.js +206 -45
  116. package/dist/commands/improve/salience.js +455 -0
  117. package/dist/commands/improve/schema-similarity-gate.js +168 -0
  118. package/dist/commands/improve/shared.js +51 -0
  119. package/dist/commands/improve/triage.js +93 -0
  120. package/dist/commands/lint/agent-linter.js +19 -24
  121. package/dist/commands/lint/base-linter.js +173 -60
  122. package/dist/commands/lint/command-linter.js +19 -24
  123. package/dist/commands/lint/env-key-rules.js +38 -1
  124. package/dist/commands/lint/fact-linter.js +39 -0
  125. package/dist/commands/lint/index.js +31 -13
  126. package/dist/commands/lint/memory-linter.js +1 -1
  127. package/dist/commands/lint/registry.js +7 -2
  128. package/dist/commands/lint/task-linter.js +3 -3
  129. package/dist/commands/lint/workflow-linter.js +26 -1
  130. package/dist/commands/observability-cli.js +4 -4
  131. package/dist/commands/proposal/drain-policies.js +13 -4
  132. package/dist/commands/proposal/drain.js +45 -51
  133. package/dist/commands/proposal/legacy-import.js +115 -0
  134. package/dist/commands/proposal/proposal-cli.js +24 -34
  135. package/dist/commands/proposal/proposal.js +2 -1
  136. package/dist/commands/proposal/propose.js +8 -3
  137. package/dist/commands/proposal/repository.js +829 -0
  138. package/dist/commands/proposal/validators/proposal-quality-validators.js +9 -8
  139. package/dist/commands/proposal/validators/proposals.js +93 -895
  140. package/dist/commands/read/curate.js +410 -111
  141. package/dist/commands/read/knowledge.js +10 -3
  142. package/dist/commands/read/remember-cli.js +133 -138
  143. package/dist/commands/read/search-cli.js +15 -8
  144. package/dist/commands/read/search.js +22 -11
  145. package/dist/commands/read/show.js +106 -14
  146. package/dist/commands/registry-cli.js +76 -87
  147. package/dist/commands/remember.js +11 -12
  148. package/dist/commands/sources/add-cli.js +91 -95
  149. package/dist/commands/sources/history.js +1 -1
  150. package/dist/commands/sources/init.js +66 -18
  151. package/dist/commands/sources/installed-stashes.js +11 -3
  152. package/dist/commands/sources/migration-help.js +7 -4
  153. package/dist/commands/sources/schema-repair.js +44 -46
  154. package/dist/commands/sources/self-update.js +2 -2
  155. package/dist/commands/sources/source-add.js +7 -3
  156. package/dist/commands/sources/sources-cli.js +3 -3
  157. package/dist/commands/sources/stash-cli.js +19 -39
  158. package/dist/commands/sources/stash-skeleton.js +57 -8
  159. package/dist/commands/tasks/default-tasks.js +15 -2
  160. package/dist/commands/tasks/tasks-cli.js +20 -29
  161. package/dist/commands/tasks/tasks.js +39 -11
  162. package/dist/commands/wiki-cli.js +23 -38
  163. package/dist/commands/workflow-cli.js +291 -13
  164. package/dist/core/asset/asset-registry.js +3 -1
  165. package/dist/core/asset/asset-spec.js +79 -5
  166. package/dist/core/asset/frontmatter.js +188 -167
  167. package/dist/core/asset/markdown.js +8 -0
  168. package/dist/core/authoring-rules.js +92 -0
  169. package/dist/core/common.js +4 -23
  170. package/dist/core/concurrent.js +10 -1
  171. package/dist/core/config/config-io.js +10 -1
  172. package/dist/core/config/config-migration.js +18 -40
  173. package/dist/core/config/config-schema.js +403 -62
  174. package/dist/core/config/config-types.js +3 -3
  175. package/dist/core/config/config.js +67 -22
  176. package/dist/core/deep-merge.js +38 -0
  177. package/dist/core/errors.js +1 -0
  178. package/dist/core/eval/rank-metrics.js +113 -0
  179. package/dist/core/events.js +4 -7
  180. package/dist/core/improve-types.js +47 -8
  181. package/dist/core/json-schema.js +142 -0
  182. package/dist/core/logs-db.js +14 -75
  183. package/dist/core/parse.js +36 -16
  184. package/dist/core/paths.js +18 -18
  185. package/dist/core/standards/resolve-standards-context.js +87 -0
  186. package/dist/core/standards/resolve-stash-standards.js +99 -0
  187. package/dist/core/standards/resolve-type-conventions.js +66 -0
  188. package/dist/core/state/migrations.js +770 -0
  189. package/dist/core/state-db.js +132 -1126
  190. package/dist/core/structured.js +69 -0
  191. package/dist/core/time.js +53 -0
  192. package/dist/core/warn.js +21 -0
  193. package/dist/core/write-source.js +37 -0
  194. package/dist/indexer/db/db.js +261 -770
  195. package/dist/indexer/db/entry-mapper.js +41 -0
  196. package/dist/indexer/db/graph-db.js +129 -86
  197. package/dist/indexer/db/llm-cache.js +2 -2
  198. package/dist/indexer/db/schema.js +516 -0
  199. package/dist/indexer/ensure-index.js +36 -92
  200. package/dist/indexer/feedback/utility-policy.js +75 -0
  201. package/dist/indexer/graph/graph-boost.js +51 -41
  202. package/dist/indexer/graph/graph-extraction.js +207 -4
  203. package/dist/indexer/index-writer-lock.js +18 -11
  204. package/dist/indexer/index-written-assets.js +105 -0
  205. package/dist/indexer/indexer.js +182 -204
  206. package/dist/indexer/passes/dir-staleness.js +114 -0
  207. package/dist/indexer/passes/memory-inference.js +13 -5
  208. package/dist/indexer/passes/metadata.js +20 -0
  209. package/dist/indexer/read-preflight.js +23 -0
  210. package/dist/indexer/search/db-search.js +89 -13
  211. package/dist/indexer/search/fts-query.js +51 -0
  212. package/dist/indexer/search/ranking-contributors.js +95 -9
  213. package/dist/indexer/search/ranking.js +79 -3
  214. package/dist/indexer/search/search-fields.js +6 -0
  215. package/dist/indexer/search/search-source.js +32 -21
  216. package/dist/indexer/search/semantic-status.js +4 -0
  217. package/dist/indexer/walk/matchers.js +48 -0
  218. package/dist/indexer/walk/walker.js +21 -13
  219. package/dist/integrations/agent/builders.js +41 -13
  220. package/dist/integrations/agent/config.js +20 -59
  221. package/dist/integrations/agent/detect.js +9 -0
  222. package/dist/integrations/agent/index.js +3 -19
  223. package/dist/integrations/agent/model-aliases.js +16 -2
  224. package/dist/integrations/agent/profiles.js +79 -6
  225. package/dist/integrations/agent/prompts.js +75 -9
  226. package/dist/integrations/agent/runner-dispatch.js +83 -0
  227. package/dist/integrations/agent/runner.js +13 -9
  228. package/dist/integrations/agent/spawn.js +206 -81
  229. package/dist/integrations/harnesses/aider/agent-builder.js +113 -0
  230. package/dist/integrations/harnesses/aider/index.js +58 -0
  231. package/dist/integrations/harnesses/aider/result-extractor.js +53 -0
  232. package/dist/integrations/harnesses/amazonq/agent-builder.js +153 -0
  233. package/dist/integrations/harnesses/amazonq/index.js +59 -0
  234. package/dist/integrations/harnesses/amazonq/result-extractor.js +48 -0
  235. package/dist/integrations/harnesses/claude/agent-builder.js +46 -7
  236. package/dist/integrations/harnesses/claude/index.js +27 -23
  237. package/dist/integrations/harnesses/claude/result-extractor.js +52 -0
  238. package/dist/integrations/harnesses/claude/session-log.js +10 -0
  239. package/dist/integrations/harnesses/codex/agent-builder.js +137 -0
  240. package/dist/integrations/harnesses/codex/index.js +63 -0
  241. package/dist/integrations/harnesses/codex/result-extractor.js +73 -0
  242. package/dist/integrations/harnesses/copilot/agent-builder.js +122 -0
  243. package/dist/integrations/harnesses/copilot/index.js +60 -0
  244. package/dist/integrations/harnesses/copilot/result-extractor.js +151 -0
  245. package/dist/integrations/harnesses/gemini/agent-builder.js +121 -0
  246. package/dist/integrations/harnesses/gemini/index.js +60 -0
  247. package/dist/integrations/harnesses/gemini/result-extractor.js +121 -0
  248. package/dist/integrations/harnesses/index.js +28 -7
  249. package/dist/integrations/harnesses/opencode/agent-builder.js +1 -1
  250. package/dist/integrations/harnesses/opencode/index.js +17 -16
  251. package/dist/integrations/harnesses/opencode/session-log.js +173 -3
  252. package/dist/integrations/harnesses/opencode-sdk/harness.js +65 -0
  253. package/dist/integrations/harnesses/opencode-sdk/index.js +10 -34
  254. package/dist/integrations/harnesses/opencode-sdk/sdk-runner.js +642 -71
  255. package/dist/integrations/harnesses/openhands/agent-builder.js +126 -0
  256. package/dist/integrations/harnesses/openhands/index.js +58 -0
  257. package/dist/integrations/harnesses/openhands/result-extractor.js +103 -0
  258. package/dist/integrations/harnesses/pi/agent-builder.js +104 -0
  259. package/dist/integrations/harnesses/pi/index.js +58 -0
  260. package/dist/integrations/harnesses/pi/result-extractor.js +135 -0
  261. package/dist/integrations/harnesses/types.js +8 -0
  262. package/dist/integrations/session-logs/index.js +40 -11
  263. package/dist/llm/call-ai.js +2 -2
  264. package/dist/llm/client.js +34 -11
  265. package/dist/llm/embedder.js +67 -4
  266. package/dist/llm/embedders/cache.js +3 -1
  267. package/dist/llm/embedders/deterministic.js +66 -0
  268. package/dist/llm/embedders/local.js +73 -3
  269. package/dist/llm/feature-gate.js +16 -15
  270. package/dist/llm/graph-extract.js +67 -44
  271. package/dist/llm/memory-infer-impl.js +138 -0
  272. package/dist/llm/memory-infer.js +1 -127
  273. package/dist/llm/metadata-enhance.js +44 -31
  274. package/dist/llm/structured-call.js +49 -0
  275. package/dist/migrate-storage-node.mjs +8 -0
  276. package/dist/output/context.js +5 -5
  277. package/dist/output/renderers.js +87 -15
  278. package/dist/output/shapes/curate.js +14 -2
  279. package/dist/output/shapes/helpers.js +0 -3
  280. package/dist/output/shapes/passthrough.js +6 -1
  281. package/dist/output/text/helpers.js +241 -2
  282. package/dist/output/text/workflow.js +4 -1
  283. package/dist/registry/providers/skills-sh.js +21 -147
  284. package/dist/registry/providers/static-index.js +15 -157
  285. package/dist/registry/resolve.js +27 -9
  286. package/dist/runtime.js +25 -1
  287. package/dist/schemas/akm-config.json +14225 -0
  288. package/dist/schemas/akm-workflow.json +328 -0
  289. package/dist/scripts/migrate-storage.js +2743 -8390
  290. package/dist/scripts/migrations/import-fs-improve-runs-to-db.js +1652 -607
  291. package/dist/setup/detect.js +9 -0
  292. package/dist/setup/legacy-config.js +106 -0
  293. package/dist/setup/prompt.js +57 -0
  294. package/dist/setup/providers.js +14 -0
  295. package/dist/setup/registry-stash-loader.js +12 -0
  296. package/dist/setup/semantic-assets.js +124 -0
  297. package/dist/setup/setup.js +52 -1614
  298. package/dist/setup/steps/connection.js +734 -0
  299. package/dist/setup/steps/output.js +31 -0
  300. package/dist/setup/steps/platforms.js +124 -0
  301. package/dist/setup/steps/semantic.js +27 -0
  302. package/dist/setup/steps/sources.js +222 -0
  303. package/dist/setup/steps/stashdir.js +42 -0
  304. package/dist/setup/steps/tasks.js +152 -0
  305. package/dist/sources/include.js +6 -2
  306. package/dist/sources/providers/filesystem.js +0 -1
  307. package/dist/sources/providers/git-install.js +210 -0
  308. package/dist/sources/providers/git-provider.js +234 -0
  309. package/dist/sources/providers/git-stash.js +248 -0
  310. package/dist/sources/providers/git.js +10 -661
  311. package/dist/sources/providers/npm.js +2 -6
  312. package/dist/sources/providers/provider-utils.js +13 -7
  313. package/dist/sources/providers/sync-from-ref.js +9 -1
  314. package/dist/sources/providers/website.js +9 -5
  315. package/dist/sources/website-ingest.js +187 -29
  316. package/dist/sources/wiki-fetchers/registry.js +53 -0
  317. package/dist/sources/wiki-fetchers/youtube.js +239 -0
  318. package/dist/storage/database.js +45 -10
  319. package/dist/storage/managed-db.js +82 -0
  320. package/dist/storage/repositories/canaries-repository.js +107 -0
  321. package/dist/storage/repositories/consolidation-repository.js +38 -0
  322. package/dist/storage/repositories/embeddings-repository.js +72 -0
  323. package/dist/storage/repositories/events-repository.js +187 -0
  324. package/dist/storage/repositories/extract-sessions-repository.js +96 -0
  325. package/dist/storage/repositories/improve-runs-repository.js +146 -0
  326. package/dist/storage/repositories/index-db.js +14 -8
  327. package/dist/storage/repositories/proposals-repository.js +220 -0
  328. package/dist/storage/repositories/recombine-repository.js +213 -0
  329. package/dist/storage/repositories/registry-cache.js +93 -0
  330. package/dist/storage/repositories/registry-index-cache-repository.js +46 -0
  331. package/dist/storage/repositories/task-history-repository.js +93 -0
  332. package/dist/storage/repositories/workflow-runs-repository.js +189 -1
  333. package/dist/storage/sqlite-pragmas.js +146 -0
  334. package/dist/tasks/backends/cron.js +1 -1
  335. package/dist/tasks/backends/index.js +9 -0
  336. package/dist/tasks/backends/launchd.js +1 -1
  337. package/dist/tasks/backends/schtasks.js +1 -1
  338. package/dist/tasks/{resolveAkmBin.js → resolve-akm-bin.js} +2 -2
  339. package/dist/tasks/runner.js +15 -13
  340. package/dist/text-import-hook.mjs +1 -1
  341. package/dist/wiki/wiki.js +52 -11
  342. package/dist/workflows/authoring/authoring.js +123 -10
  343. package/dist/workflows/authoring/workflow-program-template.yaml +31 -0
  344. package/dist/workflows/cli.js +5 -0
  345. package/dist/workflows/db.js +138 -4
  346. package/dist/workflows/exec/brief.js +484 -0
  347. package/dist/workflows/exec/native-executor.js +975 -0
  348. package/dist/workflows/exec/param-secrets.js +115 -0
  349. package/dist/workflows/exec/report.js +1295 -0
  350. package/dist/workflows/exec/run-workflow.js +596 -0
  351. package/dist/workflows/exec/scheduler.js +100 -0
  352. package/dist/workflows/exec/step-work.js +1156 -0
  353. package/dist/workflows/exec/unit-writer.js +23 -0
  354. package/dist/workflows/exec/watch.js +116 -0
  355. package/dist/workflows/exec/worktree.js +171 -0
  356. package/dist/workflows/ir/compile.js +388 -0
  357. package/dist/workflows/ir/params.js +54 -0
  358. package/dist/workflows/ir/plan-hash.js +33 -0
  359. package/dist/workflows/ir/schema.js +4 -0
  360. package/dist/workflows/parser.js +3 -1
  361. package/dist/workflows/program/expressions.js +369 -0
  362. package/dist/workflows/program/parser.js +760 -0
  363. package/dist/workflows/program/project.js +105 -0
  364. package/dist/workflows/program/schema.js +54 -0
  365. package/dist/workflows/renderer.js +82 -5
  366. package/dist/workflows/runtime/agent-identity.js +59 -14
  367. package/dist/workflows/runtime/runs.js +248 -153
  368. package/dist/workflows/runtime/unit-checkin.js +45 -0
  369. package/dist/workflows/runtime/workflow-asset-loader.js +188 -0
  370. package/dist/workflows/validate-summary.js +26 -10
  371. package/dist/workflows/validator.js +1 -1
  372. package/docs/README.md +69 -18
  373. package/docs/data-and-telemetry.md +7 -5
  374. package/docs/migration/release-notes/0.7.0.md +1 -1
  375. package/docs/migration/release-notes/0.9.0-beta.60.md +19 -0
  376. package/docs/migration/release-notes/0.9.0.md +39 -0
  377. package/package.json +10 -10
  378. package/dist/assets/tasks/core/update-stashes.yml +0 -4
  379. package/dist/commands/db-cli.js +0 -23
  380. package/dist/indexer/db/db-backup.js +0 -376
  381. package/dist/indexer/passes/staleness-detect.js +0 -488
@@ -24,27 +24,30 @@
24
24
  import fs from "node:fs";
25
25
  import os from "node:os";
26
26
  import path from "node:path";
27
- import { assertNever } from "../../core/assert.js";
28
27
  import { parseAssetRef } from "../../core/asset/asset-ref.js";
29
28
  import { assembleAssetFromString, serializeFrontmatter } from "../../core/asset/asset-serialize.js";
30
29
  import { parseFrontmatter } from "../../core/asset/frontmatter.js";
31
30
  import { stripMarkdownFences } from "../../core/asset/markdown.js";
31
+ import { DESCRIPTION_MAX_CHARS, requiresDescription } from "../../core/authoring-rules.js";
32
32
  import { resolveStashDir } from "../../core/common.js";
33
- import { loadConfig } from "../../core/config/config.js";
33
+ import { getImproveProcessConfig, loadConfig } from "../../core/config/config.js";
34
34
  import { ConfigError, UsageError } from "../../core/errors.js";
35
35
  import { appendEvent, readEvents } from "../../core/events.js";
36
36
  import { lintLessonContent } from "../../core/lesson-lint.js";
37
+ import { resolveStandardsContext } from "../../core/standards/resolve-standards-context.js";
38
+ import { warn } from "../../core/warn.js";
37
39
  import { lookup } from "../../indexer/indexer.js";
38
40
  import { runAgent, } from "../../integrations/agent/index.js";
39
41
  import { resolveProcessAgentProfile } from "../../integrations/agent/config.js";
40
42
  import { buildReflectPrompt, extractDraftConfidence, parseAgentProposalPayload, } from "../../integrations/agent/prompts.js";
41
- import { resolveImproveProcessRunnerFromProfile, runnerIsLlm, runnerSupportsFileWrite, } from "../../integrations/agent/runner.js";
43
+ import { resolveDefaultLlmRunner, resolveImproveProcessRunnerFromProfile, runnerIsLlm, runnerSupportsFileWrite, } from "../../integrations/agent/runner.js";
44
+ import { executeRunner } from "../../integrations/agent/runner-dispatch.js";
42
45
  import { runOpencodeSdk } from "../../integrations/harnesses/opencode-sdk/index.js";
43
46
  import { chatCompletion } from "../../llm/client.js";
44
47
  import { isLlmFeatureEnabled } from "../../llm/feature-gate.js";
45
48
  import { baseFailureFields, enoentHintMessage, isEnoentFailure, loadAgentConfigFromDisk, resolveAgentProfile, } from "../agent/agent-support.js";
46
- import { checkReflectSize } from "../proposal/validators/proposal-quality-validators.js";
47
- import { createProposal, isProposalSkipped, listProposals, } from "../proposal/validators/proposals.js";
49
+ import { createProposal, isProposalSkipped, listProposals, } from "../proposal/repository.js";
50
+ import { checkReflectSize, isValidDescription } from "../proposal/validators/proposal-quality-validators.js";
48
51
  import { deriveLessonRef, runLessonQualityJudge } from "./distill.js";
49
52
  import { classifyReflectChange } from "./reflect-noise.js";
50
53
  const MAX_FEEDBACK_LINES = 10;
@@ -383,6 +386,101 @@ function splitFrontmatter(raw) {
383
386
  return { fmText: null, body: raw };
384
387
  return { fmText: m[1], body: m[2] };
385
388
  }
389
+ /**
390
+ * Strip an LLM-appended duplicate frontmatter block from a body string.
391
+ *
392
+ * When the LLM echoes the original source file verbatim after its rewrite,
393
+ * the resulting body contains a second `---...---` YAML block. We detect it
394
+ * by requiring BOTH a balanced fence (opening + closing `---`) AND YAML-like
395
+ * `key: value` content inside, so legitimate Markdown thematic breaks and
396
+ * code-fence examples are never truncated.
397
+ */
398
+ function stripAppendedFrontmatter(body) {
399
+ const fencePattern = /\n---\r?\n([\s\S]*?)\n---\r?\n/;
400
+ const match = body.match(fencePattern);
401
+ if (!match)
402
+ return body;
403
+ // Only strip when the captured block looks like YAML frontmatter.
404
+ if (!/^\w[\w-]*:/m.test(match[1]))
405
+ return body;
406
+ return body.slice(0, body.indexOf(match[0])).replace(/\s+$/, "");
407
+ }
408
+ /**
409
+ * #636 — deterministically derive a valid `description` from an asset's existing
410
+ * metadata when one is missing. Sources, in priority order: the `title:`
411
+ * frontmatter field, the first `# Heading` in the (proposed or source) body, and
412
+ * the first sentence of the opening body paragraph. The candidate is normalized
413
+ * (whitespace collapsed, trailing punctuation/markdown stripped, clamped to the
414
+ * description max) and only returned if it PASSES `isValidDescription` — so this
415
+ * never produces a heading-fragment, truncated, or otherwise gate-failing value.
416
+ * Returns `undefined` when nothing usable can be derived (caller leaves the
417
+ * proposal as-is rather than fabricating prose).
418
+ *
419
+ * This is intentionally deterministic and lives in the reflect proposal-build
420
+ * path — it does NOT touch the validators or the promote-time repair.
421
+ */
422
+ function deriveDescriptionFromAsset(title, proposedBody, sourceBody, targetRef) {
423
+ // Each candidate is tagged with its kind. A title or `# Heading` is a bare
424
+ // fragment ("Paged.js — Named Page") that reads poorly as a description even
425
+ // when it is long enough to pass the length gate, so for those we prefer the
426
+ // padded sentence form. A prose sentence is already a sentence, so it is used
427
+ // as-is (padding it would double-wrap an already-complete sentence).
428
+ const candidates = [];
429
+ // 1. title: frontmatter
430
+ if (typeof title === "string" && title.trim())
431
+ candidates.push({ text: title.trim(), kind: "fragment" });
432
+ // 2. first `# Heading` (proposed body first, then source body)
433
+ for (const body of [proposedBody, sourceBody]) {
434
+ const headingMatch = body.match(/^#{1,6}\s+(.+?)\s*$/m);
435
+ if (headingMatch?.[1])
436
+ candidates.push({ text: headingMatch[1].trim(), kind: "fragment" });
437
+ }
438
+ // 3. first sentence of the opening prose paragraph (skip headings, fences,
439
+ // list markers, blockquotes — those are not prose).
440
+ for (const body of [proposedBody, sourceBody]) {
441
+ const firstSentence = firstProseSentence(body);
442
+ if (firstSentence)
443
+ candidates.push({ text: firstSentence, kind: "prose" });
444
+ }
445
+ for (const { text, kind } of candidates) {
446
+ const normalized = normalizeDescriptionCandidate(text);
447
+ if (!normalized)
448
+ continue;
449
+ // For a title/heading fragment, try the padded sentence form FIRST so the
450
+ // result reads as a sentence rather than a bare fragment — a short but valid
451
+ // title like "Paged.js — Named Page" (21 chars) would otherwise be returned
452
+ // verbatim. Fall back to the bare form only if the padded form fails the
453
+ // gate. A prose candidate is already a sentence, so it is used as-is.
454
+ const variants = kind === "fragment" ? [`Reference notes on ${normalized}.`, normalized] : [normalized];
455
+ for (const v of variants) {
456
+ const clamped = v.length > DESCRIPTION_MAX_CHARS ? v.slice(0, DESCRIPTION_MAX_CHARS).trimEnd() : v;
457
+ if (isValidDescription(clamped, targetRef, { skipRefTailCheck: true }).ok)
458
+ return clamped;
459
+ }
460
+ }
461
+ return undefined;
462
+ }
463
+ /** Extract the first prose sentence from a markdown body, or `""` if none. */
464
+ function firstProseSentence(body) {
465
+ for (const rawLine of body.split(/\r?\n/)) {
466
+ const line = rawLine.trim();
467
+ if (!line)
468
+ continue;
469
+ if (/^(#{1,6}\s|```|~~~|[-*+]\s|\d+\.\s|>|\||<!--)/.test(line))
470
+ continue;
471
+ const sentenceMatch = line.match(/^(.+?[.!?])(\s|$)/);
472
+ return (sentenceMatch?.[1] ?? line).trim();
473
+ }
474
+ return "";
475
+ }
476
+ /** Normalize a description candidate: strip markdown markers, collapse space. */
477
+ function normalizeDescriptionCandidate(raw) {
478
+ return raw
479
+ .replace(/`/g, "")
480
+ .replace(/^[#>*\-\s]+/, "")
481
+ .replace(/\s+/g, " ")
482
+ .trim();
483
+ }
386
484
  /**
387
485
  * Reflect post-processor — enforces the safety rails described at the top of
388
486
  * this file:
@@ -408,7 +506,7 @@ function splitFrontmatter(raw) {
408
506
  * from `payload.frontmatter` so identity fields can be enforced. Size guard
409
507
  * is skipped because there is no source to compare against.
410
508
  */
411
- function sanitizeReflectPayload(payload, sourceContent, targetRef) {
509
+ export function sanitizeReflectPayload(payload, sourceContent, targetRef) {
412
510
  const warnings = [];
413
511
  const { fmText: sourceFmText, body: sourceBody } = sourceContent
414
512
  ? splitFrontmatter(sourceContent)
@@ -449,7 +547,35 @@ function sanitizeReflectPayload(payload, sourceContent, targetRef) {
449
547
  mergedFm[field] = sourceFm[field];
450
548
  }
451
549
  }
452
- const cleanedBody = rawLlmBody.replace(/^\s+/, "");
550
+ const cleanedBody = stripAppendedFrontmatter(rawLlmBody.replace(/^\s+/, ""));
551
+ // #636 — deterministic description fallback (reflect-side belt-and-suspenders).
552
+ // If the type requires a `description` and the merged frontmatter is still
553
+ // MISSING one (source had none AND the model didn't author one), derive a
554
+ // description DETERMINISTICALLY from the existing `title:` frontmatter or the
555
+ // first `# Heading` / opening body sentence — never free-form invention. This
556
+ // runs in the reflect proposal-build path, BEFORE the proposal is created, so
557
+ // the validator/promote path is left untouched (no gate fabricates content).
558
+ //
559
+ // Scope is the issue's target: a source asset that ALREADY carries frontmatter
560
+ // (e.g. scraped docs: `source`/`title`/`scraped`) but has a MISSING/empty
561
+ // `description`. We deliberately do NOT fire when:
562
+ // - the source has no frontmatter block at all (injecting one would be a
563
+ // structural change and would defeat the #580 no-op/cosmetic noise gate
564
+ // for a pure body echo), or
565
+ // - a present-but-otherwise-invalid description exists (too short, a heading
566
+ // fragment) — overwriting authored content is out of scope; the prompt
567
+ // instruction handles improving it instead.
568
+ const refType = targetRef.includes(":") ? (targetRef.split(":")[0] ?? "") : "";
569
+ const mergedDesc = mergedFm.description;
570
+ const descIsMissing = typeof mergedDesc !== "string" || mergedDesc.trim().length === 0;
571
+ const sourceHadFrontmatter = sourceFmText !== null && Object.keys(sourceFm).length > 0;
572
+ if (refType && requiresDescription(refType) && descIsMissing && sourceHadFrontmatter) {
573
+ const derived = deriveDescriptionFromAsset(mergedFm.title, cleanedBody, sourceBody, targetRef);
574
+ if (derived) {
575
+ mergedFm.description = derived;
576
+ warnings.push("Synthesized a deterministic `description` from title/heading (#636) — source and proposal lacked one.");
577
+ }
578
+ }
453
579
  // Size guard — only when source body is meaningfully large. The pure
454
580
  // predicate lives in `core/proposal-quality-validators` so the same check
455
581
  // also runs inside `runProposalValidators` on `proposal accept`.
@@ -673,7 +799,7 @@ export async function akmReflect(options = {}) {
673
799
  }
674
800
  else {
675
801
  const cfg = options.config ?? loadConfig();
676
- const reflectProcess = cfg.profiles?.improve?.default?.processes?.reflect;
802
+ const reflectProcess = getImproveProcessConfig(cfg, "reflect", options.improveProfile);
677
803
  // Resolve the runner from the improve profile's reflect entry when present.
678
804
  runnerSpec = resolveImproveProcessRunnerFromProfile(reflectProcess, cfg) ?? undefined;
679
805
  if (runnerSpec) {
@@ -705,6 +831,28 @@ export async function akmReflect(options = {}) {
705
831
  throw err;
706
832
  throw err;
707
833
  }
834
+ // P1.3 (meta-review 07, Chain G): unattended `akm improve` must never hand
835
+ // reflect a tool-capable runner. Agent-CLI/SDK runners have filesystem
836
+ // access, so a poisoned asset body flowing through the scheduled reflect
837
+ // prompt could steer an agent with tools; the tool-less LLM HTTP runner
838
+ // corrupts output text at worst (src/llm/call-ai.ts). An llm RunnerSpec
839
+ // resolved from the process block is honored; anything else — an agent/sdk
840
+ // spec, a resolved agent profile, or the default-agent fallback below — is
841
+ // pinned to `defaults.llm`, failing CLOSED when that is unset.
842
+ // `options.agentProfile` stays exempt: it is a direct-injection test seam
843
+ // the cron path (loop-stages) never sets.
844
+ if (options.eventSource === "improve" && !options.agentProfile && (!runnerSpec || !runnerIsLlm(runnerSpec))) {
845
+ const cfg = options.config ?? loadConfig();
846
+ const pinned = resolveDefaultLlmRunner(cfg, resolvedTimeoutMs);
847
+ if (!pinned) {
848
+ throw new ConfigError("Unattended improve pins reflect to the tool-less LLM runner, but the config resolves a tool-capable runner and no defaults.llm profile exists to pin to.", "LLM_NOT_CONFIGURED", 'Set processes.reflect.mode to "llm" on the active improve profile, or configure defaults.llm.');
849
+ }
850
+ warn(runnerSpec
851
+ ? `[akm] reflect: unattended improve resolved a tool-capable "${runnerSpec.kind}" runner — pinned to the tool-less LLM runner (07 Chain-G).`
852
+ : "[akm] reflect: unattended improve would have fallen back to an agent profile — pinned to the tool-less LLM runner (07 Chain-G).");
853
+ runnerSpec = pinned;
854
+ profile = undefined;
855
+ }
708
856
  // Ensure profile is set for agent/sdk runners that don't use runnerSpec
709
857
  if (!runnerSpec && !profile) {
710
858
  const agent = options.agentConfig ?? loadAgentConfigFromDisk();
@@ -726,6 +874,9 @@ export async function akmReflect(options = {}) {
726
874
  // Reflexion-style verbal-RL: inject rejected proposals so the agent avoids
727
875
  // reproducing proposals that have already been reviewed and refused.
728
876
  const rejectedProposals = readRejectedProposals(stash, options.ref);
877
+ // Standards "rulebook" for this target — wiki schema (wiki page) or stash
878
+ // convention/meta facts (non-wiki asset); empty when neither fires.
879
+ const standardsContext = resolveStandardsContext(options.ref, stash);
729
880
  // 5. Spawn the agent — with optional Self-Refine loop (R-1 / #372).
730
881
  //
731
882
  // maxRefineIters controls how many agent invocations are made:
@@ -794,6 +945,7 @@ export async function akmReflect(options = {}) {
794
945
  ...(schemaHints.length > 0 ? { schemaHints } : {}),
795
946
  ...(relatedLessons.length > 0 ? { relatedLessons } : {}),
796
947
  ...(options.task ? { task: options.task } : {}),
948
+ ...(standardsContext.trim() ? { standardsContext } : {}),
797
949
  ...(options.avoidPatterns && options.avoidPatterns.length > 0 ? { avoidPatterns: options.avoidPatterns } : {}),
798
950
  ...(rejectedProposals.length > 0 ? { rejectedProposals } : {}),
799
951
  // R-1: inject prior draft as self-critique target on iterations > 0
@@ -825,44 +977,39 @@ export async function akmReflect(options = {}) {
825
977
  iterResult = await runAgent(resolvedProfile, prompt, runOptions);
826
978
  }
827
979
  else if (runnerSpec) {
828
- // v2: dispatch through unified RunnerSpec
980
+ // v2: dispatch through the unified RunnerSpec seam (X3). The `agent` /
981
+ // `sdk` arms route to the default profile runners; the `llm` arm is
982
+ // reflect-specific (wraps `runReflectViaLlm` — its bespoke iteration
983
+ // shape) so it is supplied as the `llm` handler.
829
984
  const runOptions = {
830
985
  stdio: "captured",
831
986
  parseOutput: "text",
832
987
  ...(Object.keys(agentEnv).length > 0 ? { env: agentEnv } : {}),
833
988
  };
834
- switch (runnerSpec.kind) {
835
- case "llm":
836
- // LLM HTTP path — `draftFilePath` is accepted for type symmetry
837
- // (see `RunReflectViaLlmOptions.draftFilePath` docstring) but is
838
- // intentionally a no-op. The prompt builder above also did not
839
- // include the file-write contract for this kind, so the LLM is
840
- // still asked for JSON via stdout.
841
- iterResult = await runReflectViaLlm({
842
- prompt,
843
- connection: runnerSpec.connection,
844
- timeoutMs: runnerSpec.timeoutMs ?? (typeof resolvedTimeoutMs === "number" ? resolvedTimeoutMs : undefined),
845
- priorDraft,
846
- iteration: iter,
847
- responseSchema: REFLECT_JSON_SCHEMA,
848
- chat: options.chat,
849
- ...(maxTokensForLlm !== undefined ? { maxTokens: maxTokensForLlm } : {}),
850
- });
851
- break;
852
- case "sdk":
853
- iterResult = await runOpencodeSdk(runnerSpec.profile, prompt ?? "", runOptions);
854
- break;
855
- case "agent":
856
- iterResult = await runAgent(runnerSpec.profile, prompt, {
857
- ...runOptions,
858
- ...(runnerSpec.timeoutMs !== undefined ? { timeoutMs: runnerSpec.timeoutMs } : {}),
859
- });
860
- break;
861
- default:
862
- // Exhaustiveness arm (H1): a 4th RunnerSpec kind becomes a compile
863
- // error here instead of leaving `iterResult` unassigned at runtime.
864
- assertNever(runnerSpec);
865
- }
989
+ iterResult = await executeRunner(runnerSpec, prompt ?? "", runOptions, {
990
+ llm: async (spec) =>
991
+ // LLM HTTP path — `draftFilePath` is accepted for type symmetry
992
+ // (see `RunReflectViaLlmOptions.draftFilePath` docstring) but is
993
+ // intentionally a no-op. The prompt builder above also did not
994
+ // include the file-write contract for this kind, so the LLM is
995
+ // still asked for JSON via stdout.
996
+ runReflectViaLlm({
997
+ prompt,
998
+ connection: spec.connection,
999
+ timeoutMs: spec.timeoutMs ?? (typeof resolvedTimeoutMs === "number" ? resolvedTimeoutMs : undefined),
1000
+ priorDraft,
1001
+ iteration: iter,
1002
+ responseSchema: REFLECT_JSON_SCHEMA,
1003
+ chat: options.chat,
1004
+ ...(maxTokensForLlm !== undefined ? { maxTokens: maxTokensForLlm } : {}),
1005
+ }),
1006
+ // The `agent` arm (and only the agent arm — preserving prior behavior)
1007
+ // overlays `spec.timeoutMs` onto the base run options.
1008
+ runAgent: (profile, p, opts) => runAgent(profile, p, {
1009
+ ...opts,
1010
+ ...(runnerSpec.timeoutMs !== undefined ? { timeoutMs: runnerSpec.timeoutMs } : {}),
1011
+ }),
1012
+ });
866
1013
  }
867
1014
  else {
868
1015
  // Production path (v1): dispatch directly to the appropriate runner.
@@ -1047,7 +1194,8 @@ export async function akmReflect(options = {}) {
1047
1194
  // `profiles.improve.default.processes.reflect.qualityGate.enabled` or
1048
1195
  // `profiles.improve.default.processes.distill.qualityGate.enabled` (the
1049
1196
  // `lesson_quality_gate` flag name is the legacy alias still accepted by
1050
- // `isLlmFeatureEnabled`). Fail-open: any judge error passes through.
1197
+ // `isLlmFeatureEnabled`). Fail-CLOSED (07 P0-2): a judge error / no-LLM /
1198
+ // parse failure rejects the proposal rather than passing it through.
1051
1199
  // G-Eval (arXiv:2303.16634) — quality judgment before admission.
1052
1200
  const runtimeConfig = options.config ??
1053
1201
  (() => {
@@ -1151,8 +1299,19 @@ export async function akmReflect(options = {}) {
1151
1299
  // (new-asset proposals have nothing to diff against).
1152
1300
  if (assetContent !== undefined) {
1153
1301
  const changeKind = classifyReflectChange(assetContent, payload.content);
1154
- if (changeKind !== "substantive") {
1155
- const subreason = changeKind === "noop" ? "reflect_skipped_noop" : "reflect_skipped_cosmetic";
1302
+ // 'low-value' is config-gated (#639). DEFAULT OFF — absent = byte-identical
1303
+ // pre-#639 behaviour (low-value treated the same as substantive). Resolved
1304
+ // by the caller from the ACTIVE improve profile's
1305
+ // `processes.reflect.lowValueFilter.enabled` and passed via options, so the
1306
+ // running profile (not a hardcoded `profiles.improve.default`) decides.
1307
+ const lowValueFilterEnabled = options.lowValueFilter === true;
1308
+ const isDeferred = changeKind === "noop" || changeKind === "cosmetic" || (changeKind === "low-value" && lowValueFilterEnabled);
1309
+ if (isDeferred) {
1310
+ const subreason = changeKind === "noop"
1311
+ ? "reflect_skipped_noop"
1312
+ : changeKind === "low-value"
1313
+ ? "reflect_skipped_low_value"
1314
+ : "reflect_skipped_cosmetic";
1156
1315
  emitReflectFailed("no_change", subreason, options.ref, { changeKind });
1157
1316
  return {
1158
1317
  schemaVersion: 1,
@@ -1160,7 +1319,9 @@ export async function akmReflect(options = {}) {
1160
1319
  reason: "no_change",
1161
1320
  error: changeKind === "noop"
1162
1321
  ? `Reflect skipped: proposed content for ${payload.ref} is identical to the current asset (empty diff); no proposal created.`
1163
- : `Reflect skipped: proposed content for ${payload.ref} is a cosmetic-only reformat of the current asset (whitespace/fence/YAML-folding changes); no proposal created.`,
1322
+ : changeKind === "low-value"
1323
+ ? `Reflect skipped: proposed content for ${payload.ref} is a low-value prose micro-rewrite (few changed tokens, no structural changes); no proposal created.`
1324
+ : `Reflect skipped: proposed content for ${payload.ref} is a cosmetic-only reformat of the current asset (whitespace/fence/YAML-folding changes); no proposal created.`,
1164
1325
  ...(options.ref ? { ref: options.ref } : {}),
1165
1326
  exitCode: result.exitCode,
1166
1327
  };