akm-cli 0.9.0-rc.1 → 0.9.0-rc.13

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 (587) hide show
  1. package/CHANGELOG.md +1190 -52
  2. package/README.md +62 -37
  3. package/SECURITY.md +46 -31
  4. package/dist/akm +162 -38
  5. package/dist/akm-migrate +44 -0
  6. package/dist/assets/backends/schtasks-template.xml +2 -1
  7. package/dist/assets/hints/cli-hints-full.md +268 -118
  8. package/dist/assets/hints/cli-hints-short.md +87 -24
  9. package/dist/assets/{profiles → improve-strategies}/catchup.json +3 -1
  10. package/dist/assets/{profiles → improve-strategies}/consolidate.json +3 -1
  11. package/dist/assets/{profiles → improve-strategies}/default.json +6 -7
  12. package/dist/assets/improve-strategies/frequent.json +15 -0
  13. package/dist/assets/{profiles → improve-strategies}/graph-refresh.json +4 -2
  14. package/dist/assets/{profiles → improve-strategies}/memory-focus.json +4 -1
  15. package/dist/assets/{profiles → improve-strategies}/proactive-maintenance.json +5 -5
  16. package/dist/assets/{profiles → improve-strategies}/quick.json +4 -2
  17. package/dist/assets/improve-strategies/reflect-distill.json +30 -0
  18. package/dist/assets/{profiles → improve-strategies}/thorough.json +1 -1
  19. package/dist/assets/prompts/consolidate-system.md +5 -5
  20. package/dist/assets/prompts/extract-session.md +2 -6
  21. package/dist/assets/prompts/memory-infer-user.md +2 -3
  22. package/dist/assets/prompts/reflect-llm-framed-contract.md +11 -0
  23. package/dist/assets/prompts/reflect-llm-schema-contract.md +3 -0
  24. package/dist/assets/prompts/reflect-output-repair.md +3 -0
  25. package/dist/assets/stash-skeleton/README.md +38 -10
  26. package/dist/assets/stash-skeleton/facts/conventions/assets/agent.md +8 -0
  27. package/dist/assets/stash-skeleton/facts/conventions/assets/command.md +8 -0
  28. package/dist/assets/stash-skeleton/facts/conventions/assets/fact.md +14 -1
  29. package/dist/assets/stash-skeleton/facts/conventions/assets/knowledge.md +13 -1
  30. package/dist/assets/stash-skeleton/facts/conventions/assets/lesson.md +9 -1
  31. package/dist/assets/stash-skeleton/facts/conventions/assets/memory.md +11 -0
  32. package/dist/assets/stash-skeleton/facts/conventions/assets/script.md +9 -0
  33. package/dist/assets/stash-skeleton/facts/conventions/assets/skill.md +9 -0
  34. package/dist/assets/stash-skeleton/facts/conventions/assets/workflow.md +8 -0
  35. package/dist/assets/stash-skeleton/facts/conventions/backlinks.md +100 -0
  36. package/dist/assets/stash-skeleton/facts/conventions/domains.md +64 -0
  37. package/dist/assets/stash-skeleton/facts/conventions/organization.md +136 -0
  38. package/dist/assets/tasks/core/extract.yml +3 -2
  39. package/dist/assets/tasks/core/improve.yml +2 -1
  40. package/dist/assets/tasks/core/index-refresh.yml +1 -0
  41. package/dist/assets/tasks/core/sync.yml +1 -0
  42. package/dist/assets/tasks/core/version-check.yml +2 -1
  43. package/dist/assets/tasks/improve/akm-graph-refresh-weekly.yml +5 -0
  44. package/dist/assets/tasks/improve/akm-improve-catchup.yml +8 -0
  45. package/dist/assets/tasks/improve/akm-improve-consolidate.yml +5 -0
  46. package/dist/assets/tasks/improve/akm-improve-frequent.yml +5 -0
  47. package/dist/assets/tasks/improve/akm-improve-nightly.yml +5 -0
  48. package/dist/assets/templates/html/health.html +5 -4
  49. package/dist/assets/workflows/workflow-template.md +31 -15
  50. package/dist/cli/invocation.js +279 -0
  51. package/dist/cli/parse-args.js +5 -90
  52. package/dist/cli/retired-commands.js +78 -0
  53. package/dist/cli/shared.js +158 -48
  54. package/dist/cli-node.mjs +2 -1
  55. package/dist/cli.js +747 -293
  56. package/dist/commands/agent/agent-dispatch.js +19 -18
  57. package/dist/commands/agent/agent-support.js +0 -24
  58. package/dist/commands/agent/contribute-cli.js +43 -97
  59. package/dist/commands/completions.js +80 -23
  60. package/dist/commands/config-cli.js +44 -281
  61. package/dist/commands/env/env-binding.js +13 -9
  62. package/dist/commands/env/env-cli.js +76 -159
  63. package/dist/commands/env/env.js +12 -163
  64. package/dist/commands/env/marker-path.js +6 -0
  65. package/dist/commands/env/secret-cli.js +45 -61
  66. package/dist/commands/env/secret.js +32 -62
  67. package/dist/commands/feedback-cli.js +179 -85
  68. package/dist/commands/health/accept-rate.js +58 -0
  69. package/dist/commands/health/advisories.js +7 -8
  70. package/dist/commands/health/checks.js +279 -94
  71. package/dist/commands/health/html-report.js +197 -578
  72. package/dist/commands/health/improve-metrics.js +277 -246
  73. package/dist/commands/health/llm-usage.js +19 -19
  74. package/dist/commands/health/md-report.js +16 -7
  75. package/dist/commands/health/metrics.js +67 -32
  76. package/dist/commands/health/renderers.js +47 -0
  77. package/dist/commands/health/report-view-model.js +508 -0
  78. package/dist/commands/health/stash-exposure.js +1 -1
  79. package/dist/commands/health/surfaces.js +16 -56
  80. package/dist/commands/health/task-runs.js +3 -67
  81. package/dist/{migrate-storage-node.mjs → commands/health/types-checks.js} +1 -5
  82. package/dist/commands/health/types-improve.js +29 -0
  83. package/dist/{output/text/save.js → commands/health/types-metrics.js} +1 -2
  84. package/dist/commands/health/types-result.js +7 -0
  85. package/dist/commands/health/types-runs.js +4 -0
  86. package/dist/commands/health/types-session-log.js +4 -0
  87. package/dist/commands/health/types-windows.js +4 -0
  88. package/dist/commands/health/types.js +26 -21
  89. package/dist/commands/health/windows.js +2 -3
  90. package/dist/commands/health.js +296 -167
  91. package/dist/commands/improve/anti-collapse.js +5 -5
  92. package/dist/commands/improve/autonomy-gate.js +68 -0
  93. package/dist/commands/improve/collapse-detector.js +65 -52
  94. package/dist/commands/improve/consolidate/chunking.js +9 -7
  95. package/dist/commands/improve/consolidate/eligibility.js +1 -23
  96. package/dist/commands/improve/consolidate/merge.js +4 -0
  97. package/dist/commands/improve/consolidate.js +454 -1354
  98. package/dist/commands/improve/content-hash.js +39 -0
  99. package/dist/commands/improve/distill/content-repair.js +4 -10
  100. package/dist/commands/improve/distill/promote-memory.js +89 -64
  101. package/dist/commands/improve/distill/quality-gate.js +118 -42
  102. package/dist/commands/improve/distill-guards.js +1 -1
  103. package/dist/commands/improve/distill-promotion-policy.js +33 -888
  104. package/dist/commands/improve/distill.js +607 -363
  105. package/dist/commands/improve/eligibility.js +165 -79
  106. package/dist/commands/improve/extract-cli.js +35 -126
  107. package/dist/commands/improve/extract-prompt.js +6 -35
  108. package/dist/commands/improve/extract.js +640 -391
  109. package/dist/commands/improve/feedback-valence.js +2 -12
  110. package/dist/commands/improve/improve-cli.js +134 -135
  111. package/dist/commands/improve/improve-result-file.js +30 -50
  112. package/dist/commands/improve/improve-run-types.js +4 -0
  113. package/dist/commands/improve/improve-strategies.js +135 -0
  114. package/dist/commands/improve/improve.js +904 -701
  115. package/dist/commands/improve/locks.js +64 -111
  116. package/dist/commands/improve/loop-stages.js +1110 -923
  117. package/dist/commands/improve/memory/derived-ref.js +124 -0
  118. package/dist/commands/improve/memory/memory-belief.js +79 -7
  119. package/dist/commands/improve/memory/memory-contradiction-detect.js +49 -52
  120. package/dist/commands/improve/memory/memory-improve.js +25 -37
  121. package/dist/commands/improve/outcome-loop.js +25 -88
  122. package/dist/commands/improve/preparation.js +1034 -813
  123. package/dist/commands/improve/proactive-maintenance.js +34 -9
  124. package/dist/commands/improve/proposal-envelope.js +31 -0
  125. package/dist/commands/improve/reflect.js +983 -794
  126. package/dist/commands/improve/run-context.js +119 -0
  127. package/dist/commands/improve/salience.js +24 -127
  128. package/dist/commands/improve/session-asset.js +7 -3
  129. package/dist/commands/improve/shared.js +14 -34
  130. package/dist/commands/improve/source-identity.js +28 -0
  131. package/dist/commands/improve/triage.js +20 -17
  132. package/dist/commands/lint/base-linter.js +340 -313
  133. package/dist/commands/lint/env-key-rules.js +31 -47
  134. package/dist/commands/lint/index.js +185 -30
  135. package/dist/commands/{events.js → log.js} +28 -38
  136. package/dist/commands/migrate-cli.js +54 -0
  137. package/dist/commands/migration-tool.js +55 -0
  138. package/dist/commands/observability-cli.js +70 -208
  139. package/dist/commands/proposal/diff-format.js +50 -0
  140. package/dist/commands/proposal/drain-policies.js +0 -6
  141. package/dist/commands/proposal/drain.js +91 -40
  142. package/dist/commands/proposal/proposal-cli.js +134 -132
  143. package/dist/commands/proposal/proposal-types.js +56 -0
  144. package/dist/commands/proposal/proposal.js +83 -65
  145. package/dist/commands/proposal/propose-cli.js +88 -0
  146. package/dist/commands/proposal/propose.js +105 -88
  147. package/dist/commands/proposal/repository.js +1303 -278
  148. package/dist/commands/proposal/validators/proposal-quality-validators.js +16 -6
  149. package/dist/commands/proposal/validators/proposal-validators.js +61 -12
  150. package/dist/commands/proposal/validators/proposals.js +6 -8
  151. package/dist/commands/read/curate.js +78 -73
  152. package/dist/commands/read/knowledge.js +510 -13
  153. package/dist/commands/read/registry-search.js +2 -2
  154. package/dist/commands/read/remember-cli.js +84 -15
  155. package/dist/commands/read/search-cli.js +203 -96
  156. package/dist/commands/read/search.js +126 -94
  157. package/dist/commands/read/show.js +226 -250
  158. package/dist/commands/registry-cli.js +34 -60
  159. package/dist/commands/remember.js +18 -57
  160. package/dist/commands/sources/add-cli.js +104 -49
  161. package/dist/commands/sources/bundle-cli.js +166 -0
  162. package/dist/commands/sources/bundle-config-ops.js +63 -0
  163. package/dist/commands/sources/info.js +27 -15
  164. package/dist/commands/sources/init.js +30 -40
  165. package/dist/commands/sources/installed-stashes.js +469 -172
  166. package/dist/commands/sources/schema-repair.js +10 -9
  167. package/dist/commands/sources/self-update.js +182 -121
  168. package/dist/commands/sources/source-add.js +169 -178
  169. package/dist/commands/sources/source-clone.js +144 -41
  170. package/dist/commands/sources/source-manage.js +94 -59
  171. package/dist/commands/sources/sources-cli.js +64 -205
  172. package/dist/commands/sources/stash-cli.js +91 -54
  173. package/dist/commands/sources/stash-skeleton.js +1 -1
  174. package/dist/commands/tasks/tasks-cli.js +106 -104
  175. package/dist/commands/tasks/tasks.js +445 -262
  176. package/dist/commands/workflow-cli.js +75 -228
  177. package/dist/core/action-contributors.js +1 -1
  178. package/dist/core/activation-policy.js +49 -0
  179. package/dist/core/adapter/adapters/agent-skills-adapter.js +181 -0
  180. package/dist/core/adapter/adapters/akm-adapter.js +528 -0
  181. package/dist/core/adapter/adapters/akm-lint.js +392 -0
  182. package/dist/core/adapter/adapters/akm-metadata.js +387 -0
  183. package/dist/core/adapter/adapters/akm-task-adapter.js +149 -0
  184. package/dist/core/adapter/adapters/akm-workflow-adapter.js +180 -0
  185. package/dist/core/adapter/adapters/claude-adapter.js +61 -0
  186. package/dist/core/adapter/adapters/dotenv-adapter.js +187 -0
  187. package/dist/core/adapter/adapters/generic-files-adapter.js +119 -0
  188. package/dist/core/adapter/adapters/index.js +80 -0
  189. package/dist/core/adapter/adapters/llm-wiki-adapter.js +419 -0
  190. package/dist/core/adapter/adapters/okf-adapter.js +391 -0
  191. package/dist/core/adapter/adapters/opencode-adapter.js +68 -0
  192. package/dist/core/adapter/adapters/shared.js +286 -0
  193. package/dist/core/adapter/adapters/tool-dir-shared.js +217 -0
  194. package/dist/core/adapter/adapters/website-snapshot-adapter.js +155 -0
  195. package/dist/core/adapter/bundle-adapter.js +4 -0
  196. package/dist/core/adapter/detect-adapter.js +17 -0
  197. package/dist/core/adapter/recognize-match.js +44 -0
  198. package/dist/core/adapter/registry.js +56 -0
  199. package/dist/core/adapter/types.js +4 -0
  200. package/dist/core/asset/akm-markdown.js +30 -0
  201. package/dist/core/asset/asset-placement.js +243 -0
  202. package/dist/core/asset/asset-ref.js +110 -79
  203. package/dist/core/asset/asset-serialize.js +20 -0
  204. package/dist/core/asset/frontmatter.js +28 -12
  205. package/dist/core/asset/markdown.js +40 -51
  206. package/dist/core/asset/resolve-ref.js +274 -0
  207. package/dist/core/asset/stash-meta.js +2 -2
  208. package/dist/core/bundle-id.js +51 -0
  209. package/dist/core/common.js +281 -86
  210. package/dist/core/config/config-io.js +42 -128
  211. package/dist/core/config/config-schema.js +233 -855
  212. package/dist/core/config/config-sources.js +162 -39
  213. package/dist/core/config/config-types.js +16 -11
  214. package/dist/core/config/config-version.js +29 -0
  215. package/dist/core/config/config-walker.js +126 -37
  216. package/dist/core/config/config.js +154 -331
  217. package/dist/core/config/deep-merge.js +41 -0
  218. package/dist/core/config/engine-semantics.js +28 -0
  219. package/dist/core/config/experimental.js +21 -0
  220. package/dist/core/config/schema/embedding.js +38 -0
  221. package/dist/core/config/schema/engines.js +116 -0
  222. package/dist/core/config/schema/experimental.js +47 -0
  223. package/dist/core/config/schema/feedback.js +31 -0
  224. package/dist/core/config/schema/improve-processes.js +389 -0
  225. package/dist/core/config/schema/improve.js +94 -0
  226. package/dist/core/config/schema/index-config.js +176 -0
  227. package/dist/core/config/schema/output.js +18 -0
  228. package/dist/core/config/schema/primitives.js +94 -0
  229. package/dist/core/config/schema/search.js +30 -0
  230. package/dist/core/config/schema/setup.js +18 -0
  231. package/dist/core/config/schema/sources-bundles.js +169 -0
  232. package/dist/core/config/schema/workflow.js +29 -0
  233. package/dist/core/env-secret-ref.js +155 -20
  234. package/dist/core/errors.js +17 -15
  235. package/dist/core/events-types.js +4 -0
  236. package/dist/core/events.js +46 -128
  237. package/dist/core/extra-params.js +62 -0
  238. package/dist/core/file-change.js +17 -0
  239. package/dist/core/file-lock.js +202 -57
  240. package/dist/core/fs-txn.js +392 -0
  241. package/dist/core/git-message.js +59 -0
  242. package/dist/core/improve-result.js +167 -0
  243. package/dist/core/lesson-lint.js +1 -17
  244. package/dist/core/logs-db.js +1 -1
  245. package/dist/core/maintenance-barrier.js +135 -0
  246. package/dist/core/migration-operation.js +44 -0
  247. package/dist/core/mutation-target.js +78 -0
  248. package/dist/core/paths.js +22 -25
  249. package/dist/core/platform.js +10 -0
  250. package/dist/core/recognition-util.js +128 -0
  251. package/dist/core/redaction.js +392 -0
  252. package/dist/core/standards/resolve-standards-context.js +36 -65
  253. package/dist/core/standards/resolve-stash-standards.js +2 -2
  254. package/dist/core/standards/resolve-type-conventions.js +5 -5
  255. package/dist/core/state/migrations.js +242 -11
  256. package/dist/core/state-db.js +98 -10
  257. package/dist/core/structured.js +1 -1
  258. package/dist/core/subprocess.js +303 -0
  259. package/dist/core/text-truncation.js +9 -5
  260. package/dist/core/time.js +20 -0
  261. package/dist/core/type-presentation.js +130 -0
  262. package/dist/core/warn.js +0 -3
  263. package/dist/core/write-source.js +834 -118
  264. package/dist/indexer/bundle-identity-guard.js +92 -0
  265. package/dist/indexer/db/graph-db.js +1 -25
  266. package/dist/indexer/db/llm-cache.js +1 -1
  267. package/dist/indexer/ensure-index.js +30 -9
  268. package/dist/indexer/graph/graph-boost.js +9 -30
  269. package/dist/indexer/graph/graph-extraction.js +41 -27
  270. package/dist/indexer/graph/graph-types.js +4 -0
  271. package/dist/indexer/index-writer-lock.js +93 -49
  272. package/dist/indexer/index-written-assets.js +100 -53
  273. package/dist/indexer/indexer.js +746 -329
  274. package/dist/indexer/init.js +18 -25
  275. package/dist/indexer/installations.js +142 -0
  276. package/dist/indexer/passes/dir-staleness.js +18 -10
  277. package/dist/indexer/passes/memory-inference.js +25 -15
  278. package/dist/indexer/passes/metadata.js +412 -243
  279. package/dist/indexer/scan/doc-to-entry.js +160 -0
  280. package/dist/indexer/scan/drain-dir.js +134 -0
  281. package/dist/indexer/search/db-search.js +292 -108
  282. package/dist/indexer/search/fts-query.js +64 -0
  283. package/dist/indexer/search/ranking-contributors.js +145 -25
  284. package/dist/indexer/search/ranking-types.js +4 -0
  285. package/dist/indexer/search/ranking.js +28 -71
  286. package/dist/indexer/search/search-attribution.js +67 -0
  287. package/dist/indexer/search/search-fields.js +18 -3
  288. package/dist/indexer/search/search-hit-enrichers.js +30 -40
  289. package/dist/indexer/search/search-source.js +157 -111
  290. package/dist/indexer/search/semantic-status.js +4 -1
  291. package/dist/indexer/usage/usage-events.js +10 -30
  292. package/dist/indexer/walk/file-context.js +3 -45
  293. package/dist/indexer/walk/matchers.js +42 -73
  294. package/dist/indexer/walk/path-resolver.js +11 -5
  295. package/dist/indexer/walk/walker.js +42 -14
  296. package/dist/integrations/agent/builder-shared.js +7 -0
  297. package/dist/integrations/agent/builders.js +5 -58
  298. package/dist/integrations/agent/config.js +3 -143
  299. package/dist/integrations/agent/detect.js +17 -2
  300. package/dist/integrations/agent/engine-resolution.js +231 -0
  301. package/dist/integrations/agent/index.js +1 -2
  302. package/dist/integrations/agent/model-aliases.js +8 -3
  303. package/dist/integrations/agent/profiles.js +6 -99
  304. package/dist/integrations/agent/prompts.js +46 -18
  305. package/dist/integrations/agent/runner-dispatch.js +78 -13
  306. package/dist/integrations/agent/runner.js +76 -208
  307. package/dist/integrations/agent/spawn.js +48 -279
  308. package/dist/integrations/harnesses/aider/agent-builder.js +9 -8
  309. package/dist/integrations/harnesses/aider/index.js +2 -12
  310. package/dist/integrations/harnesses/amazonq/agent-builder.js +10 -16
  311. package/dist/integrations/harnesses/amazonq/index.js +3 -17
  312. package/dist/integrations/harnesses/claude/agent-builder.js +2 -3
  313. package/dist/integrations/harnesses/claude/config-import.js +1 -3
  314. package/dist/integrations/harnesses/claude/index.js +1 -14
  315. package/dist/integrations/harnesses/claude/session-log.js +27 -75
  316. package/dist/integrations/harnesses/codex/agent-builder.js +8 -7
  317. package/dist/integrations/harnesses/codex/index.js +2 -13
  318. package/dist/integrations/harnesses/copilot/agent-builder.js +9 -9
  319. package/dist/integrations/harnesses/copilot/index.js +1 -13
  320. package/dist/integrations/harnesses/gemini/agent-builder.js +8 -9
  321. package/dist/integrations/harnesses/gemini/index.js +1 -13
  322. package/dist/integrations/harnesses/ids.js +24 -0
  323. package/dist/integrations/harnesses/index.js +31 -33
  324. package/dist/integrations/harnesses/opencode/agent-builder.js +23 -5
  325. package/dist/integrations/harnesses/opencode/config-import.js +1 -3
  326. package/dist/integrations/harnesses/opencode/index.js +1 -18
  327. package/dist/integrations/harnesses/opencode/session-log.js +67 -125
  328. package/dist/integrations/harnesses/opencode-sdk/harness.js +3 -17
  329. package/dist/integrations/harnesses/opencode-sdk/sdk-runner.js +274 -191
  330. package/dist/integrations/harnesses/openhands/agent-builder.js +12 -10
  331. package/dist/integrations/harnesses/openhands/index.js +2 -12
  332. package/dist/integrations/harnesses/pi/agent-builder.js +11 -18
  333. package/dist/integrations/harnesses/pi/index.js +3 -16
  334. package/dist/integrations/harnesses/shared.js +17 -0
  335. package/dist/integrations/harnesses/types.js +38 -34
  336. package/dist/integrations/lockfile.js +211 -24
  337. package/dist/integrations/session-logs/index.js +24 -40
  338. package/dist/integrations/session-logs/provider-base.js +113 -0
  339. package/dist/llm/client.js +182 -110
  340. package/dist/llm/embedders/deterministic.js +2 -2
  341. package/dist/llm/embedders/remote.js +21 -9
  342. package/dist/llm/feature-gate.js +17 -57
  343. package/dist/llm/graph-extract.js +12 -13
  344. package/dist/llm/index-passes.js +8 -42
  345. package/dist/llm/memory-infer.js +144 -1
  346. package/dist/llm/metadata-enhance.js +45 -30
  347. package/dist/llm/structured-call.js +16 -8
  348. package/dist/llm/usage-persist.js +30 -5
  349. package/dist/llm/usage-telemetry.js +59 -6
  350. package/dist/output/cli-hints.js +1 -2
  351. package/dist/output/command-registry.js +27 -0
  352. package/dist/output/context.js +22 -7
  353. package/dist/output/format-exempt.js +80 -0
  354. package/dist/output/generic-render.js +251 -0
  355. package/dist/output/html-render.js +11 -16
  356. package/dist/output/render-registry.js +57 -0
  357. package/dist/output/renderers.js +15 -281
  358. package/dist/output/shapes/curate.js +10 -1
  359. package/dist/output/shapes/events.js +12 -7
  360. package/dist/output/shapes/helpers.js +58 -84
  361. package/dist/output/shapes/passthrough.js +8 -40
  362. package/dist/output/shapes/proposal/producer.js +15 -7
  363. package/dist/output/shapes/registry.js +12 -6
  364. package/dist/output/shapes.js +0 -9
  365. package/dist/output/text/{init.js → bundle-create.js} +3 -1
  366. package/dist/output/text/bundle-show.js +7 -0
  367. package/dist/output/text/command-format.js +562 -0
  368. package/dist/output/text/env.js +1 -3
  369. package/dist/output/text/events.js +8 -7
  370. package/dist/output/text/helpers.js +15 -1375
  371. package/dist/output/text/proposal/producer.js +4 -2
  372. package/dist/output/text/proposal-format.js +202 -0
  373. package/dist/output/text/registry-commands.js +1 -2
  374. package/dist/output/text/registry.js +12 -6
  375. package/dist/output/text/show-directives.js +117 -0
  376. package/dist/output/text/show-format.js +103 -0
  377. package/dist/output/text/sync.js +5 -0
  378. package/dist/output/text/workflow-format.js +332 -0
  379. package/dist/output/text/workflow.js +1 -2
  380. package/dist/output/text.js +10 -19
  381. package/dist/registry/factory.js +4 -6
  382. package/dist/registry/origin-resolve.js +16 -27
  383. package/dist/registry/providers/skills-sh.js +3 -3
  384. package/dist/registry/providers/static-index.js +15 -25
  385. package/dist/registry/resolve.js +43 -94
  386. package/dist/registry/semver.js +43 -0
  387. package/dist/runtime.js +81 -12
  388. package/dist/scripts/akm-migrate.js +35529 -0
  389. package/dist/setup/detect.js +5 -7
  390. package/dist/setup/detected-engines.js +136 -0
  391. package/dist/setup/engine-config.js +100 -0
  392. package/dist/setup/registry-stash-loader.js +3 -3
  393. package/dist/setup/semantic-assets.js +12 -9
  394. package/dist/setup/setup.js +444 -208
  395. package/dist/setup/steps/connection-shared.js +120 -0
  396. package/dist/setup/steps/connection.js +108 -305
  397. package/dist/setup/steps/platforms.js +13 -12
  398. package/dist/setup/steps/semantic.js +15 -3
  399. package/dist/setup/steps/sources.js +21 -15
  400. package/dist/setup/steps/stashdir.js +6 -4
  401. package/dist/setup/steps/tasks.js +236 -119
  402. package/dist/setup/steps.js +3 -2
  403. package/dist/sources/freshness.js +39 -0
  404. package/dist/sources/provider-factory.js +11 -17
  405. package/dist/sources/providers/filesystem.js +2 -3
  406. package/dist/sources/providers/git-install.js +278 -34
  407. package/dist/sources/providers/git-provider.js +54 -56
  408. package/dist/sources/providers/git-stash.js +420 -91
  409. package/dist/sources/providers/git.js +2 -2
  410. package/dist/sources/providers/npm.js +16 -19
  411. package/dist/sources/providers/provider-utils.js +47 -22
  412. package/dist/sources/providers/sync-from-ref.js +3 -9
  413. package/dist/sources/providers/website.js +2 -2
  414. package/dist/sources/resolve.js +11 -10
  415. package/dist/sources/snapshot-fetchers/types.js +4 -0
  416. package/dist/sources/{website-ingest.js → snapshot-fetchers/website-ingest.js} +110 -41
  417. package/dist/storage/database.js +60 -4
  418. package/dist/storage/engines/sqlite-migrations.js +156 -5
  419. package/dist/storage/locations.js +1 -2
  420. package/dist/storage/repositories/canaries-repository.js +1 -1
  421. package/dist/storage/repositories/events-repository.js +51 -11
  422. package/dist/storage/repositories/improve-runs-repository.js +6 -32
  423. package/dist/storage/repositories/index-connection.js +79 -0
  424. package/dist/storage/repositories/index-db.js +4 -3
  425. package/dist/storage/repositories/index-entries-repository.js +863 -0
  426. package/dist/{indexer/db/entry-mapper.js → storage/repositories/index-entry-mapper.js} +19 -2
  427. package/dist/storage/repositories/index-entry-types.js +4 -0
  428. package/dist/storage/repositories/index-fts-repository.js +167 -0
  429. package/dist/storage/repositories/index-llm-cache-repository.js +108 -0
  430. package/dist/storage/repositories/index-meta-repository.js +49 -0
  431. package/dist/{indexer/db/schema.js → storage/repositories/index-schema.js} +226 -100
  432. package/dist/storage/repositories/index-sql.js +12 -0
  433. package/dist/storage/repositories/index-utility-repository.js +356 -0
  434. package/dist/storage/repositories/index-vec-repository.js +250 -0
  435. package/dist/storage/repositories/outcome-repository.js +119 -0
  436. package/dist/storage/repositories/proposals-repository.js +317 -75
  437. package/dist/storage/repositories/registry-cache.js +1 -1
  438. package/dist/storage/repositories/salience-repository.js +172 -0
  439. package/dist/storage/repositories/task-history-repository.js +110 -3
  440. package/dist/storage/repositories/workflow-runs-repository.js +68 -35
  441. package/dist/tasks/backends/cron.js +169 -46
  442. package/dist/tasks/backends/exec-utils.js +76 -3
  443. package/dist/tasks/backends/index.js +6 -9
  444. package/dist/tasks/backends/launchd.js +292 -55
  445. package/dist/tasks/backends/schtasks.js +557 -70
  446. package/dist/tasks/backends/types.js +4 -0
  447. package/dist/tasks/command-executable.js +93 -0
  448. package/dist/tasks/embedded.js +56 -38
  449. package/dist/tasks/parser.js +156 -64
  450. package/dist/tasks/resolve-akm-bin.js +144 -51
  451. package/dist/tasks/runner.js +377 -209
  452. package/dist/tasks/schedule.js +108 -19
  453. package/dist/tasks/scheduler-invocation.js +296 -0
  454. package/dist/tasks/schema.js +1 -1
  455. package/dist/tasks/task-id.js +35 -0
  456. package/dist/tasks/validator.js +30 -16
  457. package/dist/workflows/authoring/authoring.js +96 -148
  458. package/dist/workflows/authoring/scope-key.js +1 -1
  459. package/dist/workflows/cli.js +0 -20
  460. package/dist/workflows/concurrency-policy.js +15 -0
  461. package/dist/workflows/exec/brief.js +25 -59
  462. package/dist/workflows/exec/frozen-judge.js +47 -0
  463. package/dist/workflows/exec/native-executor.js +157 -94
  464. package/dist/workflows/exec/report.js +365 -200
  465. package/dist/workflows/exec/run-workflow.js +46 -40
  466. package/dist/workflows/exec/scheduler.js +12 -41
  467. package/dist/workflows/exec/step-work.js +239 -205
  468. package/dist/workflows/exec/workflow-engine-gate.js +67 -0
  469. package/dist/workflows/ir/compile.js +141 -283
  470. package/dist/workflows/ir/freeze.js +233 -0
  471. package/dist/workflows/ir/plan-hash.js +40 -5
  472. package/dist/workflows/ir/schema.js +537 -1
  473. package/dist/workflows/parser.js +878 -306
  474. package/dist/workflows/program/expressions.js +20 -208
  475. package/dist/workflows/program/schema.js +7 -10
  476. package/dist/workflows/renderer.js +99 -121
  477. package/dist/workflows/resource-limits.js +22 -0
  478. package/dist/workflows/runtime/checkin.js +1 -1
  479. package/dist/workflows/runtime/plan-classifier.js +131 -0
  480. package/dist/workflows/runtime/runs.js +200 -113
  481. package/dist/workflows/runtime/unit-checkin.js +1 -1
  482. package/dist/workflows/runtime/unit-phases.js +20 -0
  483. package/dist/workflows/runtime/workflow-asset-loader.js +235 -97
  484. package/dist/workflows/schema.js +1 -11
  485. package/dist/workflows/validate-summary.js +4 -26
  486. package/dist/workflows/validator.js +52 -30
  487. package/docs/README.md +42 -78
  488. package/docs/migration/README.md +8 -0
  489. package/docs/migration/release-notes/0.6.0.md +1 -1
  490. package/docs/migration/release-notes/0.7.0.md +9 -8
  491. package/docs/migration/release-notes/0.9.0.md +158 -14
  492. package/docs/migration/v0.7-to-v0.8.md +46 -47
  493. package/docs/migration/v0.8-to-v0.9.md +844 -0
  494. package/docs/reference/README.md +12 -0
  495. package/docs/reference/data-and-telemetry.md +333 -0
  496. package/package.json +21 -17
  497. package/schemas/akm-asset-envelope.json +93 -0
  498. package/schemas/akm-config.json +4636 -0
  499. package/schemas/akm-task.json +87 -0
  500. package/{dist/schemas → schemas}/akm-workflow.json +127 -82
  501. package/dist/akm-migrate-storage +0 -38
  502. package/dist/assets/help/help-accept.md +0 -12
  503. package/dist/assets/help/help-improve.md +0 -84
  504. package/dist/assets/help/help-proposals.md +0 -17
  505. package/dist/assets/help/help-propose.md +0 -17
  506. package/dist/assets/help/help-reject.md +0 -11
  507. package/dist/assets/profiles/frequent.json +0 -13
  508. package/dist/assets/profiles/recombine-only.json +0 -21
  509. package/dist/assets/profiles/reflect-distill.json +0 -30
  510. package/dist/assets/profiles/synthesize.json +0 -15
  511. package/dist/assets/prompts/procedural-system.md +0 -44
  512. package/dist/assets/prompts/recombine-system.md +0 -40
  513. package/dist/assets/prompts/staleness-detect-system.md +0 -6
  514. package/dist/assets/tasks/core/backup.yml +0 -4
  515. package/dist/assets/tasks/graph-refresh-weekly.yml +0 -10
  516. package/dist/assets/templates/html/default.html +0 -78
  517. package/dist/assets/templates/html/vendor/echarts.min.js +0 -45
  518. package/dist/assets/wiki/index-template.md +0 -12
  519. package/dist/assets/wiki/ingest-workflow-template.md +0 -83
  520. package/dist/assets/wiki/log-template.md +0 -8
  521. package/dist/assets/wiki/schema-template.md +0 -61
  522. package/dist/cli/config-migrate.js +0 -150
  523. package/dist/cli/config-validate.js +0 -39
  524. package/dist/commands/graph/graph-cli.js +0 -124
  525. package/dist/commands/graph/graph.js +0 -487
  526. package/dist/commands/improve/calibration.js +0 -161
  527. package/dist/commands/improve/dedup.js +0 -482
  528. package/dist/commands/improve/extract-watch.js +0 -140
  529. package/dist/commands/improve/hot-probation.js +0 -45
  530. package/dist/commands/improve/improve-auto-accept.js +0 -276
  531. package/dist/commands/improve/improve-profiles.js +0 -168
  532. package/dist/commands/improve/procedural.js +0 -398
  533. package/dist/commands/improve/recombine.js +0 -818
  534. package/dist/commands/improve/schema-similarity-gate.js +0 -168
  535. package/dist/commands/lint/agent-linter.js +0 -44
  536. package/dist/commands/lint/command-linter.js +0 -44
  537. package/dist/commands/lint/default-linter.js +0 -16
  538. package/dist/commands/lint/fact-linter.js +0 -39
  539. package/dist/commands/lint/knowledge-linter.js +0 -16
  540. package/dist/commands/lint/memory-linter.js +0 -61
  541. package/dist/commands/lint/registry.js +0 -41
  542. package/dist/commands/lint/skill-linter.js +0 -45
  543. package/dist/commands/lint/task-linter.js +0 -50
  544. package/dist/commands/lint/workflow-linter.js +0 -81
  545. package/dist/commands/proposal/legacy-import.js +0 -115
  546. package/dist/commands/sources/history.js +0 -196
  547. package/dist/commands/tasks/default-tasks.js +0 -186
  548. package/dist/commands/wiki-cli.js +0 -292
  549. package/dist/core/asset/asset-registry.js +0 -76
  550. package/dist/core/asset/asset-spec.js +0 -316
  551. package/dist/core/config/config-migration.js +0 -602
  552. package/dist/core/deep-merge.js +0 -38
  553. package/dist/core/eval/rank-metrics.js +0 -113
  554. package/dist/core/ripgrep/install.js +0 -163
  555. package/dist/core/ripgrep/resolve.js +0 -81
  556. package/dist/indexer/db/db.js +0 -1414
  557. package/dist/indexer/manifest.js +0 -170
  558. package/dist/indexer/passes/metadata-contributors.js +0 -31
  559. package/dist/indexer/usage/unmigrated-vaults-guard.js +0 -94
  560. package/dist/integrations/harnesses/opencode-sdk/index.js +0 -25
  561. package/dist/llm/call-ai.js +0 -62
  562. package/dist/llm/memory-infer-impl.js +0 -138
  563. package/dist/output/shapes/distill.js +0 -14
  564. package/dist/output/shapes/history.js +0 -11
  565. package/dist/output/text/distill.js +0 -6
  566. package/dist/output/text/enable-disable.js +0 -8
  567. package/dist/output/text/history.js +0 -6
  568. package/dist/output/text/wiki.js +0 -16
  569. package/dist/registry/build-index.js +0 -386
  570. package/dist/schemas/akm-config.json +0 -14225
  571. package/dist/scripts/migrate-storage.js +0 -13169
  572. package/dist/scripts/migrations/import-fs-improve-runs-to-db.js +0 -10169
  573. package/dist/scripts/migrations/v16-to-v17.js +0 -141
  574. package/dist/setup/legacy-config.js +0 -106
  575. package/dist/storage/repositories/consolidation-repository.js +0 -38
  576. package/dist/storage/repositories/recombine-repository.js +0 -213
  577. package/dist/wiki/wiki-templates.js +0 -15
  578. package/dist/wiki/wiki.js +0 -1012
  579. package/dist/workflows/authoring/workflow-program-template.yaml +0 -31
  580. package/dist/workflows/db.js +0 -350
  581. package/dist/workflows/exec/watch.js +0 -116
  582. package/dist/workflows/program/parser.js +0 -760
  583. package/dist/workflows/program/project.js +0 -105
  584. package/docs/data-and-telemetry.md +0 -227
  585. package/docs/migration/release-notes/0.9.0-beta.60.md +0 -19
  586. /package/dist/sources/{wiki-fetchers → snapshot-fetchers}/registry.js +0 -0
  587. /package/dist/sources/{wiki-fetchers → snapshot-fetchers}/youtube.js +0 -0
@@ -0,0 +1,172 @@
1
+ // This Source Code Form is subject to the terms of the Mozilla Public
2
+ // License, v. 2.0. If a copy of the MPL was not distributed with this
3
+ // file, You can obtain one at https://mozilla.org/MPL/2.0/.
4
+ /**
5
+ * Upsert salience scores for one asset into state.db.
6
+ *
7
+ * Idempotent: safe to call every run; updates the outcome / retrieval / rank
8
+ * columns on conflict.
9
+ *
10
+ * #644 — encoding provenance guard: the `encoding_salience` + `encoding_source`
11
+ * columns are NOT lowered from a real content-derived score to a type-weight
12
+ * stub. When the stored row is `encoding_source = 'content'` and the incoming
13
+ * vector is a `type-stub` fallback, the stored encoding score and its provenance
14
+ * are preserved (only the other sub-scores and `rank_score` advance). A `content`
15
+ * write always wins; a `type-stub` write only seeds a row that has no content
16
+ * score yet. This stops the improve loop's type-weight fallback re-asserting the
17
+ * stub over a distill-written score on every run.
18
+ *
19
+ * NOTE: when the guard preserves the stored encoding score, the incoming
20
+ * `vector.rankScore` (computed from the stub encoding) is still written. Callers
21
+ * that want the rank_score to reflect the preserved content score should pass the
22
+ * stored content score back in as `inputs.encodingSalience` to `computeSalience`
23
+ * — which the improve loop does. The guard here is the defensive backstop.
24
+ */
25
+ export function upsertAssetSalience(db, ref, vector, now) {
26
+ const ts = now ?? Date.now();
27
+ db.prepare(`INSERT INTO asset_salience
28
+ (asset_ref, encoding_salience, outcome_salience, retrieval_salience, rank_score, consecutive_no_ops, updated_at, encoding_source)
29
+ VALUES (?, ?, ?, ?, ?, 0, ?, ?)
30
+ ON CONFLICT(asset_ref) DO UPDATE SET
31
+ -- #644: never lower a real content-derived score to a type-weight stub.
32
+ -- Keep the stored encoding score + provenance when the stored row is
33
+ -- 'content' and the incoming write is a 'type-stub' fallback.
34
+ encoding_salience = CASE
35
+ WHEN asset_salience.encoding_source = 'content' AND excluded.encoding_source = 'type-stub'
36
+ THEN asset_salience.encoding_salience
37
+ ELSE excluded.encoding_salience
38
+ END,
39
+ encoding_source = CASE
40
+ WHEN asset_salience.encoding_source = 'content' AND excluded.encoding_source = 'type-stub'
41
+ THEN asset_salience.encoding_source
42
+ ELSE excluded.encoding_source
43
+ END,
44
+ outcome_salience = excluded.outcome_salience,
45
+ retrieval_salience = excluded.retrieval_salience,
46
+ rank_score = excluded.rank_score,
47
+ updated_at = excluded.updated_at`).run(ref, vector.encoding, vector.outcome, vector.retrieval, vector.rankScore, ts, vector.encodingSource ?? "type-stub");
48
+ }
49
+ /**
50
+ * Load the salience row for one asset, or undefined if not yet computed.
51
+ */
52
+ export function getAssetSalience(db, ref) {
53
+ const row = db
54
+ .prepare(`SELECT asset_ref, encoding_salience, outcome_salience, retrieval_salience,
55
+ rank_score, consecutive_no_ops, updated_at, encoding_source
56
+ FROM asset_salience WHERE asset_ref = ?`)
57
+ .get(ref);
58
+ // Bun SQLite returns null (not undefined) when no row found.
59
+ return row == null ? undefined : row;
60
+ }
61
+ /**
62
+ * Load ALL rank scores from the asset_salience table (full-stash query).
63
+ *
64
+ * Used by the forgetting-safety report (plan §WS-1 step 7) to compute stash-wide
65
+ * rank positions rather than pool-relative positions. Returns an empty Map when the
66
+ * table is empty (first WS-1 run = no pre-existing rows).
67
+ *
68
+ * Order is unspecified; callers must sort before assigning 1-indexed positions.
69
+ */
70
+ export function getAllRankScores(db) {
71
+ const rows = db.prepare("SELECT asset_ref, rank_score FROM asset_salience").all();
72
+ const result = new Map();
73
+ for (const row of rows) {
74
+ result.set(row.asset_ref, row.rank_score);
75
+ }
76
+ return result;
77
+ }
78
+ // ── Plasticity helpers ────────────────────────────────────────────────────────
79
+ /**
80
+ * Increment `consecutive_no_ops` for an asset. Called after a no-op reflect/distill.
81
+ * Has NO effect on `rank_score` — the plasticity counter only dampens consolidation
82
+ * selection, not retrieval ranking. See plan §WS-1 step 8.
83
+ *
84
+ * Invariant: recordNoOp must never originate rank_score semantics. If the asset has
85
+ * no salience row yet (persistence's best-effort try/catch may have swallowed an
86
+ * error), we do nothing — a no-op counter is meaningless without a rank_score row,
87
+ * and a synthetic INSERT would fabricate a rank_score=0 entry that could produce
88
+ * false catastrophic-forgetting signals in buildRankChangeReport.
89
+ */
90
+ export function recordNoOp(db, ref) {
91
+ db.prepare(`UPDATE asset_salience SET consecutive_no_ops = consecutive_no_ops + 1, updated_at = ? WHERE asset_ref = ?`).run(Date.now(), ref);
92
+ // If changes === 0 the asset has no salience row yet — leave the table unchanged.
93
+ }
94
+ /**
95
+ * Reset `consecutive_no_ops` to 0 when an asset produces an accepted change.
96
+ * Call after a successful proposal acceptance or detected mutation.
97
+ */
98
+ export function resetConsecutiveNoOps(db, ref) {
99
+ db.prepare(`UPDATE asset_salience SET consecutive_no_ops = 0, updated_at = ? WHERE asset_ref = ?`).run(Date.now(), ref);
100
+ }
101
+ /**
102
+ * Return the `consecutive_no_ops` count for one asset. 0 when unknown.
103
+ */
104
+ export function getConsecutiveNoOps(db, ref) {
105
+ const row = db.prepare(`SELECT consecutive_no_ops FROM asset_salience WHERE asset_ref = ?`).get(ref);
106
+ return row?.consecutive_no_ops ?? 0;
107
+ }
108
+ // ── New in #672 part 2 ────────────────────────────────────────────────────────
109
+ /**
110
+ * Load the `retrieval_salience` column for the top `limit` assets ordered by
111
+ * `rank_score` descending.
112
+ *
113
+ * Absorbs the health read formerly inlined in `commands/health/metrics.ts`
114
+ * (`computeDegradationMetrics`'s corpus-diversity Gini calculation) — same
115
+ * query, now parameterised on `limit` instead of a hardcoded 100. This is new
116
+ * behavior (a named, parameterised repository entry point), not a verbatim
117
+ * move; callers that need fail-open behaviour on a missing table (pre-WS-1
118
+ * installs) must wrap the call in their own try/catch, matching the existing
119
+ * call site.
120
+ */
121
+ export function getTopRetrievalSalience(db, limit) {
122
+ return db
123
+ .prepare(`SELECT retrieval_salience FROM asset_salience ORDER BY rank_score DESC LIMIT ?`)
124
+ .all(limit);
125
+ }
126
+ /** List every `asset_salience` ref with its current `missing_since` marker. */
127
+ export function listAssetSalienceMissingState(db) {
128
+ return db.prepare(`SELECT asset_ref, missing_since FROM asset_salience`).all();
129
+ }
130
+ /**
131
+ * Stamp `missing_since = now` for the given refs, but ONLY where it is
132
+ * currently NULL — a ref already stamped keeps its original timestamp so the
133
+ * grace window measures from first sighting, not last. Refs with no row at
134
+ * all are silently skipped (0 rows affected). Returns the number of rows
135
+ * actually stamped.
136
+ */
137
+ export function stampAssetSalienceMissing(db, refs, now) {
138
+ if (refs.length === 0)
139
+ return 0;
140
+ const stmt = db.prepare(`UPDATE asset_salience SET missing_since = ? WHERE asset_ref = ? AND missing_since IS NULL`);
141
+ let changed = 0;
142
+ for (const ref of refs)
143
+ changed += Number(stmt.run(now, ref).changes);
144
+ return changed;
145
+ }
146
+ /**
147
+ * Clear `missing_since` for refs that resolved again. Returns the number of
148
+ * rows actually cleared.
149
+ */
150
+ export function clearAssetSalienceMissing(db, refs) {
151
+ if (refs.length === 0)
152
+ return 0;
153
+ const stmt = db.prepare(`UPDATE asset_salience SET missing_since = NULL WHERE asset_ref = ? AND missing_since IS NOT NULL`);
154
+ let changed = 0;
155
+ for (const ref of refs)
156
+ changed += Number(stmt.run(ref).changes);
157
+ return changed;
158
+ }
159
+ /**
160
+ * Delete `asset_salience` rows whose `missing_since` is older than
161
+ * `cutoffMs`. A single DELETE — SQLite runs it as one implicit transaction.
162
+ * Returns the number of rows deleted.
163
+ */
164
+ export function deleteAssetSalienceMissingBefore(db, cutoffMs) {
165
+ return Number(db.prepare(`DELETE FROM asset_salience WHERE missing_since IS NOT NULL AND missing_since < ?`).run(cutoffMs)
166
+ .changes);
167
+ }
168
+ /** Count `asset_salience` rows currently marked missing (the live backlog size). */
169
+ export function countAssetSalienceMissing(db) {
170
+ const row = db.prepare(`SELECT COUNT(*) AS n FROM asset_salience WHERE missing_since IS NOT NULL`).get();
171
+ return row.n;
172
+ }
@@ -1,6 +1,110 @@
1
1
  // This Source Code Form is subject to the terms of the Mozilla Public
2
2
  // License, v. 2.0. If a copy of the MPL was not distributed with this
3
3
  // file, You can obtain one at https://mozilla.org/MPL/2.0/.
4
+ function metadataError(message) {
5
+ throw new Error(`invalid task_history metadata_json: ${message}`);
6
+ }
7
+ function isRecord(value) {
8
+ return typeof value === "object" && value !== null && !Array.isArray(value);
9
+ }
10
+ function validateDetail(value) {
11
+ if (value === undefined || value === null)
12
+ return;
13
+ if (!isRecord(value))
14
+ metadataError("detail must be an object or null");
15
+ const allowed = new Set(["runId", "reason", "error", "exitCode"]);
16
+ const unknown = Object.keys(value).filter((key) => !allowed.has(key));
17
+ if (unknown.length > 0)
18
+ metadataError(`unknown detail fields: ${unknown.sort().join(", ")}`);
19
+ for (const field of ["runId", "reason", "error"]) {
20
+ if (value[field] !== undefined && typeof value[field] !== "string")
21
+ metadataError(`detail.${field} must be a string`);
22
+ }
23
+ if (value.exitCode !== undefined && value.exitCode !== null && typeof value.exitCode !== "number") {
24
+ metadataError("detail.exitCode must be a number or null");
25
+ }
26
+ }
27
+ /** Decode supported historical and current task-history metadata. */
28
+ export function decodeTaskHistoryMetadata(input) {
29
+ let parsed = input;
30
+ if (typeof input === "string") {
31
+ try {
32
+ parsed = JSON.parse(input);
33
+ }
34
+ catch {
35
+ metadataError("not valid JSON");
36
+ }
37
+ }
38
+ if (!isRecord(parsed))
39
+ metadataError("root must be an object");
40
+ if (parsed.metadataVersion === undefined || parsed.metadataVersion === 1) {
41
+ const allowed = new Set(["metadataVersion", "durationMs", "detail", "profile"]);
42
+ const unknown = Object.keys(parsed).filter((key) => !allowed.has(key));
43
+ if (unknown.length > 0)
44
+ metadataError(`unknown v1 fields: ${unknown.sort().join(", ")}`);
45
+ if (parsed.durationMs !== undefined && typeof parsed.durationMs !== "number") {
46
+ metadataError("durationMs must be a number");
47
+ }
48
+ if (parsed.profile !== undefined && typeof parsed.profile !== "string") {
49
+ metadataError("profile must be a string");
50
+ }
51
+ validateDetail(parsed.detail);
52
+ return {
53
+ metadataVersion: 1,
54
+ durationMs: parsed.durationMs ?? 0,
55
+ detail: parsed.detail ?? null,
56
+ ...(parsed.profile !== undefined ? { legacyProfile: parsed.profile } : {}),
57
+ };
58
+ }
59
+ if (parsed.metadataVersion === 2) {
60
+ const allowed = new Set(["metadataVersion", "durationMs", "detail", "engine"]);
61
+ const unknown = Object.keys(parsed).filter((key) => !allowed.has(key));
62
+ if (unknown.length > 0)
63
+ metadataError(`unknown v2 fields: ${unknown.sort().join(", ")}`);
64
+ if (typeof parsed.durationMs !== "number")
65
+ metadataError("durationMs must be a number");
66
+ if (!("detail" in parsed))
67
+ metadataError("detail is required in v2");
68
+ if (parsed.engine !== undefined && parsed.engine !== null && typeof parsed.engine !== "string") {
69
+ metadataError("engine must be a string or null");
70
+ }
71
+ validateDetail(parsed.detail);
72
+ return {
73
+ metadataVersion: 2,
74
+ durationMs: parsed.durationMs,
75
+ detail: parsed.detail ?? null,
76
+ ...(parsed.engine !== undefined ? { engine: parsed.engine } : {}),
77
+ };
78
+ }
79
+ metadataError(`unsupported metadataVersion: ${String(parsed.metadataVersion)}`);
80
+ }
81
+ /**
82
+ * Atomically reserve one task-attempt identity.
83
+ *
84
+ * The existing unique `(task_id, started_at)` index arbitrates concurrent
85
+ * processes: exactly one caller receives `true` for a candidate timestamp.
86
+ * Callers can advance by one millisecond and retry without a schema change.
87
+ */
88
+ export function reserveTaskHistoryAttempt(db, row) {
89
+ const result = db
90
+ .prepare(`INSERT OR IGNORE INTO task_history
91
+ (task_id, status, started_at, completed_at, failed_at, log_path,
92
+ target_kind, target_ref, metadata_json)
93
+ VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?)`)
94
+ .run(row.task_id, row.status, row.started_at, row.completed_at ?? null, row.failed_at ?? null, row.log_path ?? null, row.target_kind ?? null, row.target_ref ?? null, row.metadata_json);
95
+ return Number(result.changes) === 1;
96
+ }
97
+ /** Finalize a row previously created by {@link reserveTaskHistoryAttempt}. */
98
+ export function finalizeTaskHistoryAttempt(db, row) {
99
+ const result = db
100
+ .prepare(`UPDATE task_history
101
+ SET status = ?, completed_at = ?, failed_at = ?, log_path = ?,
102
+ target_kind = ?, target_ref = ?, metadata_json = ?
103
+ WHERE task_id = ? AND started_at = ?
104
+ AND status = 'active' AND completed_at IS NULL`)
105
+ .run(row.status, row.completed_at ?? null, row.failed_at ?? null, row.log_path ?? null, row.target_kind ?? null, row.target_ref ?? null, row.metadata_json, row.task_id, row.started_at);
106
+ return Number(result.changes) === 1;
107
+ }
4
108
  /**
5
109
  * Upsert a task history row.
6
110
  */
@@ -24,7 +128,7 @@ export function getTaskHistory(db, taskId) {
24
128
  return db
25
129
  .prepare(`SELECT id, task_id, status, started_at, completed_at, failed_at, log_path,
26
130
  target_kind, target_ref, metadata_json
27
- FROM task_history WHERE task_id = ? ORDER BY started_at DESC LIMIT 1`)
131
+ FROM task_history WHERE task_id = ? ORDER BY started_at DESC, id DESC LIMIT 1`)
28
132
  .get(taskId);
29
133
  }
30
134
  /**
@@ -34,7 +138,7 @@ export function getTaskHistoryRuns(db, taskId, limit = 50) {
34
138
  return db
35
139
  .prepare(`SELECT id, task_id, status, started_at, completed_at, failed_at, log_path,
36
140
  target_kind, target_ref, metadata_json
37
- FROM task_history WHERE task_id = ? ORDER BY started_at DESC LIMIT ?`)
141
+ FROM task_history WHERE task_id = ? ORDER BY started_at DESC, id DESC LIMIT ?`)
38
142
  .all(taskId, limit);
39
143
  }
40
144
  /**
@@ -64,10 +168,13 @@ export function queryTaskHistory(db, options = {}) {
64
168
  params.push(options.targetRef);
65
169
  }
66
170
  const where = conditions.length > 0 ? `WHERE ${conditions.join(" AND ")}` : "";
171
+ const limit = options.limit !== undefined ? "LIMIT ?" : "";
172
+ if (options.limit !== undefined)
173
+ params.push(options.limit);
67
174
  return db
68
175
  .prepare(`SELECT task_id, status, started_at, completed_at, failed_at, log_path,
69
176
  target_kind, target_ref, metadata_json
70
- FROM task_history ${where} ORDER BY started_at DESC`)
177
+ FROM task_history ${where} ORDER BY started_at DESC, id DESC ${limit}`)
71
178
  .all(...params);
72
179
  }
73
180
  /**
@@ -1,13 +1,15 @@
1
1
  // This Source Code Form is subject to the terms of the Mozilla Public
2
2
  // License, v. 2.0. If a copy of the MPL was not distributed with this
3
3
  // file, You can obtain one at https://mozilla.org/MPL/2.0/.
4
- import { closeWorkflowDatabase, openWorkflowDatabase } from "../../workflows/db.js";
4
+ import { openStateDatabase, withImmediateTransaction } from "../../core/state-db.js";
5
5
  import { resolveStorageLocations } from "../locations.js";
6
6
  /**
7
7
  * Repository owning every raw SQL statement against `workflow_runs` and
8
8
  * `workflow_run_steps`. It is DB-location-agnostic: the lifecycle helper
9
- * {@link withWorkflowRunsRepo} binds it to {@link StorageLocations.workflowDb}
10
- * so a future storage move (#489) changes only `locations.ts`.
9
+ * {@link withWorkflowRunsRepo} binds it to {@link StorageLocations.stateDb}
10
+ * (the three-DB cutover folded workflow.db into state.db; the tables exist via
11
+ * state migration `020-three-db-cutover`) so a future storage move (#489)
12
+ * changes only `locations.ts`.
11
13
  *
12
14
  * ## Connection-lifetime contract (WS5)
13
15
  *
@@ -28,19 +30,28 @@ export class WorkflowRunsRepository {
28
30
  transaction(fn) {
29
31
  return this.db.transaction(fn)();
30
32
  }
33
+ immediateTransaction(fn) {
34
+ return withImmediateTransaction(this.db, () => fn(this.db));
35
+ }
31
36
  // ── reads (fully materialised) ─────────────────────────────────────────────
32
- findActiveRunForScope(workflowRef, scopeKey) {
37
+ findActiveRunForScope(workflowRefs, scopeKey) {
38
+ const refs = typeof workflowRefs === "string" ? [workflowRefs] : [...workflowRefs];
39
+ if (refs.length === 0)
40
+ return undefined;
33
41
  return this.db
34
- .prepare("SELECT id, current_step_id FROM workflow_runs WHERE workflow_ref = ? AND scope_key = ? AND status = 'active' ORDER BY updated_at DESC LIMIT 1")
35
- .get(workflowRef, scopeKey);
42
+ .prepare(`SELECT id, current_step_id FROM workflow_runs WHERE workflow_ref IN (${refs.map(() => "?").join(", ")}) AND scope_key = ? AND status = 'active' ORDER BY updated_at DESC, created_at DESC LIMIT 1`)
43
+ .get(...refs, scopeKey);
36
44
  }
37
45
  getRunById(runId) {
38
46
  return this.db.prepare("SELECT * FROM workflow_runs WHERE id = ?").get(runId);
39
47
  }
40
- getActiveRunRowForScope(workflowRef, scopeKey) {
48
+ getActiveRunRowForScope(workflowRefs, scopeKey) {
49
+ const refs = typeof workflowRefs === "string" ? [workflowRefs] : [...workflowRefs];
50
+ if (refs.length === 0)
51
+ return undefined;
41
52
  return this.db
42
- .prepare("SELECT * FROM workflow_runs WHERE workflow_ref = ? AND scope_key = ? AND status = 'active' ORDER BY updated_at DESC LIMIT 1")
43
- .get(workflowRef, scopeKey);
53
+ .prepare(`SELECT * FROM workflow_runs WHERE workflow_ref IN (${refs.map(() => "?").join(", ")}) AND scope_key = ? AND status = 'active' ORDER BY updated_at DESC, created_at DESC LIMIT 1`)
54
+ .get(...refs, scopeKey);
44
55
  }
45
56
  hasRun(runId) {
46
57
  const row = this.db.prepare("SELECT 1 FROM workflow_runs WHERE id = ? LIMIT 1").get(runId);
@@ -55,6 +66,10 @@ export class WorkflowRunsRepository {
55
66
  filters.push("workflow_ref = ?");
56
67
  params.push(filter.workflowRef);
57
68
  }
69
+ else if (filter.workflowRefs && filter.workflowRefs.length > 0) {
70
+ filters.push(`workflow_ref IN (${filter.workflowRefs.map(() => "?").join(", ")})`);
71
+ params.push(...filter.workflowRefs);
72
+ }
58
73
  if (filter.activeOnly) {
59
74
  // `activeOnly` means EXACTLY status='active' — a run currently
60
75
  // executable. A `blocked` run is NOT active (it is parked awaiting a
@@ -111,7 +126,9 @@ export class WorkflowRunsRepository {
111
126
  .run(runId, currentStepId);
112
127
  }
113
128
  markRunActive(runId, updatedAt) {
114
- this.db.prepare("UPDATE workflow_runs SET status = 'active', updated_at = ? WHERE id = ?").run(updatedAt, runId);
129
+ this.db
130
+ .prepare("UPDATE workflow_runs SET status = 'active', updated_at = ?, engine_lease_holder = NULL, engine_lease_until = NULL WHERE id = ?")
131
+ .run(updatedAt, runId);
115
132
  }
116
133
  updateStepCompletion(input) {
117
134
  this.db
@@ -127,6 +144,14 @@ export class WorkflowRunsRepository {
127
144
  WHERE id = ?`)
128
145
  .run(input.status, input.currentStepId, input.updatedAt, input.completedAt, input.checkinArmedAt, input.runId);
129
146
  }
147
+ markRunAbandoned(runId, updatedAt) {
148
+ const result = this.db
149
+ .prepare(`UPDATE workflow_runs
150
+ SET status = 'failed', updated_at = ?, completed_at = ?, checkin_armed_at = ?
151
+ WHERE id = ? AND status IN ('active', 'blocked')`)
152
+ .run(updatedAt, updatedAt, updatedAt, runId);
153
+ return Number(result.changes) === 1;
154
+ }
130
155
  rearmCheckin(runId, checkinArmedAt) {
131
156
  this.db.prepare("UPDATE workflow_runs SET checkin_armed_at = ? WHERE id = ?").run(checkinArmedAt, runId);
132
157
  }
@@ -137,10 +162,10 @@ export class WorkflowRunsRepository {
137
162
  * `insertRun`, so a run row never exists without its frozen plan. Read back
138
163
  * via {@link getRunById} (`plan_json` / `plan_hash` on the row).
139
164
  */
140
- setRunPlan(runId, planJson, planHash) {
165
+ setRunPlan(runId, planJson, planHash, planIrVersion = 3) {
141
166
  this.db
142
- .prepare("UPDATE workflow_runs SET plan_json = ?, plan_hash = ? WHERE id = ?")
143
- .run(planJson, planHash, runId);
167
+ .prepare("UPDATE workflow_runs SET plan_json = ?, plan_hash = ?, plan_ir_version = ? WHERE id = ?")
168
+ .run(planJson, planHash, planIrVersion, runId);
144
169
  }
145
170
  // ── engine run lease (migration 006 columns, R2 enforcement) ──────────────
146
171
  //
@@ -159,7 +184,8 @@ export class WorkflowRunsRepository {
159
184
  const result = this.db
160
185
  .prepare(`UPDATE workflow_runs
161
186
  SET engine_lease_holder = ?, engine_lease_until = ?
162
- WHERE id = ? AND (engine_lease_holder IS NULL OR engine_lease_until IS NULL OR engine_lease_until < ?)`)
187
+ WHERE id = ? AND status = 'active'
188
+ AND (engine_lease_holder IS NULL OR engine_lease_until IS NULL OR engine_lease_until < ?)`)
163
189
  .run(holder, until, runId, now);
164
190
  return Number(result.changes) > 0;
165
191
  }
@@ -170,18 +196,18 @@ export class WorkflowRunsRepository {
170
196
  */
171
197
  renewEngineLease(runId, holder, until) {
172
198
  const result = this.db
173
- .prepare("UPDATE workflow_runs SET engine_lease_until = ? WHERE id = ? AND engine_lease_holder = ?")
199
+ .prepare("UPDATE workflow_runs SET engine_lease_until = ? WHERE id = ? AND engine_lease_holder = ? AND status = 'active'")
174
200
  .run(until, runId, holder);
175
201
  return Number(result.changes) > 0;
176
202
  }
177
203
  /**
178
- * Clear the lease — only while `holder` still owns it, so a crashed-then-
179
- * recovered invocation can never release a lease another engine has since
180
- * claimed. Releasing an already-lost lease is a harmless no-op.
204
+ * Clear the lease only while `holder` still owns a non-failed run. Failed
205
+ * runs retain the final holder/expiry for forensics until explicit resume.
206
+ * Releasing an already-lost lease is a harmless no-op.
181
207
  */
182
208
  releaseEngineLease(runId, holder) {
183
209
  this.db
184
- .prepare("UPDATE workflow_runs SET engine_lease_holder = NULL, engine_lease_until = NULL WHERE id = ? AND engine_lease_holder = ?")
210
+ .prepare("UPDATE workflow_runs SET engine_lease_holder = NULL, engine_lease_until = NULL WHERE id = ? AND engine_lease_holder = ? AND status <> 'failed'")
185
211
  .run(runId, holder);
186
212
  }
187
213
  // ── unit rows (migration 004) ──────────────────────────────────────────────
@@ -238,15 +264,16 @@ export class WorkflowRunsRepository {
238
264
  insertUnit(input) {
239
265
  this.db
240
266
  .prepare(`INSERT INTO workflow_run_units (
241
- run_id, unit_id, step_id, node_id, parent_unit_id, phase, runner, model,
267
+ run_id, unit_id, step_id, node_id, parent_unit_id, phase, runner, engine, model,
242
268
  status, input_hash, worktree_path, started_at, claim_holder, claim_expires_at
243
- ) VALUES (?, ?, ?, ?, ?, ?, ?, ?, 'running', ?, ?, ?, ?, ?)
269
+ ) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, 'running', ?, ?, ?, ?, ?)
244
270
  ON CONFLICT(run_id, unit_id) DO UPDATE SET
245
271
  step_id = excluded.step_id,
246
272
  node_id = excluded.node_id,
247
273
  parent_unit_id = excluded.parent_unit_id,
248
- phase = excluded.phase,
249
- runner = excluded.runner,
274
+ phase = excluded.phase,
275
+ runner = excluded.runner,
276
+ engine = excluded.engine,
250
277
  model = excluded.model,
251
278
  status = excluded.status,
252
279
  input_hash = excluded.input_hash,
@@ -261,7 +288,7 @@ export class WorkflowRunsRepository {
261
288
  finished_at = NULL,
262
289
  last_checkin_at = NULL,
263
290
  attempts = workflow_run_units.attempts + 1`)
264
- .run(input.runId, input.unitId, input.stepId, input.nodeId, input.parentUnitId, input.phase, input.runner, input.model, input.inputHash, input.worktreePath ?? null, input.startedAt, input.claimHolder ?? null, input.claimExpiresAt ?? null);
291
+ .run(input.runId, input.unitId, input.stepId, input.nodeId, input.parentUnitId, input.phase, input.runner, input.engine ?? null, input.model, input.inputHash, input.worktreePath ?? null, input.startedAt, input.claimHolder ?? null, input.claimExpiresAt ?? null);
265
292
  }
266
293
  /**
267
294
  * Stamp a `--status running` claim + heartbeat on a unit row (migration 009,
@@ -273,11 +300,13 @@ export class WorkflowRunsRepository {
273
300
  * marker set by {@link insertUnit}).
274
301
  */
275
302
  updateUnitClaim(runId, unitId, holder, expiresAt, lastCheckinAt) {
276
- this.db
303
+ const result = this.db
277
304
  .prepare(`UPDATE workflow_run_units
278
305
  SET status = 'running', last_checkin_at = ?, claim_holder = ?, claim_expires_at = ?
279
- WHERE run_id = ? AND unit_id = ?`)
280
- .run(lastCheckinAt, holder, expiresAt, runId, unitId);
306
+ WHERE run_id = ? AND unit_id = ?
307
+ AND EXISTS (SELECT 1 FROM workflow_runs WHERE id = ? AND status = 'active')`)
308
+ .run(lastCheckinAt, holder, expiresAt, runId, unitId, runId);
309
+ return Number(result.changes) === 1;
281
310
  }
282
311
  /**
283
312
  * Record a unit's terminal state (completed / failed / skipped).
@@ -310,20 +339,24 @@ export class WorkflowRunsRepository {
310
339
  }
311
340
  }
312
341
  /**
313
- * Open the workflow database (bound to {@link StorageLocations.workflowDb}),
314
- * run `fn` against a {@link WorkflowRunsRepository}, and close the connection
315
- * exactly once when `fn` settles.
342
+ * Open state.db (bound to {@link StorageLocations.stateDb}, the post-cutover
343
+ * home of the `workflow_runs` / `workflow_run_steps` / `workflow_run_units`
344
+ * tables), run `fn` against a {@link WorkflowRunsRepository}, and close the
345
+ * connection exactly once when `fn` settles.
316
346
  *
317
- * Generalises the former `withWorkflowDb` loan pattern in runs.ts. Repository
318
- * read methods fully materialise their results, so closing here never truncates
319
- * lazy iteration (WS5 connection-lifetime rule).
347
+ * Fresh-connection-per-call, mirroring the former workflow.db loan pattern:
348
+ * `openStateDatabase` acquires its own maintenance activity + asserts the
349
+ * current ledger, and the repository owns all table-scoped SQL, so the merge
350
+ * into state.db is a zero-SQL-rewrite repoint. Repository read methods fully
351
+ * materialise their results, so closing here never truncates lazy iteration
352
+ * (WS5 connection-lifetime rule).
320
353
  */
321
354
  export async function withWorkflowRunsRepo(fn) {
322
- const db = openWorkflowDatabase(resolveStorageLocations().workflowDb);
355
+ const db = openStateDatabase(resolveStorageLocations().stateDb);
323
356
  try {
324
357
  return await Promise.resolve(fn(new WorkflowRunsRepository(db)));
325
358
  }
326
359
  finally {
327
- closeWorkflowDatabase(db);
360
+ db.close();
328
361
  }
329
362
  }