akm-cli 0.9.0-rc.0 → 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 (598) hide show
  1. package/CHANGELOG.md +1283 -22
  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/prompts/workflow-unit-preamble.md +26 -0
  26. package/dist/assets/stash-skeleton/README.md +38 -10
  27. package/dist/assets/stash-skeleton/facts/conventions/assets/agent.md +8 -0
  28. package/dist/assets/stash-skeleton/facts/conventions/assets/command.md +8 -0
  29. package/dist/assets/stash-skeleton/facts/conventions/assets/fact.md +14 -1
  30. package/dist/assets/stash-skeleton/facts/conventions/assets/knowledge.md +13 -1
  31. package/dist/assets/stash-skeleton/facts/conventions/assets/lesson.md +9 -1
  32. package/dist/assets/stash-skeleton/facts/conventions/assets/memory.md +11 -0
  33. package/dist/assets/stash-skeleton/facts/conventions/assets/script.md +9 -0
  34. package/dist/assets/stash-skeleton/facts/conventions/assets/skill.md +9 -0
  35. package/dist/assets/stash-skeleton/facts/conventions/assets/workflow.md +8 -0
  36. package/dist/assets/stash-skeleton/facts/conventions/backlinks.md +100 -0
  37. package/dist/assets/stash-skeleton/facts/conventions/domains.md +64 -0
  38. package/dist/assets/stash-skeleton/facts/conventions/organization.md +136 -0
  39. package/dist/assets/tasks/core/extract.yml +3 -2
  40. package/dist/assets/tasks/core/improve.yml +2 -1
  41. package/dist/assets/tasks/core/index-refresh.yml +1 -0
  42. package/dist/assets/tasks/core/sync.yml +1 -0
  43. package/dist/assets/tasks/core/version-check.yml +2 -1
  44. package/dist/assets/tasks/improve/akm-graph-refresh-weekly.yml +5 -0
  45. package/dist/assets/tasks/improve/akm-improve-catchup.yml +8 -0
  46. package/dist/assets/tasks/improve/akm-improve-consolidate.yml +5 -0
  47. package/dist/assets/tasks/improve/akm-improve-frequent.yml +5 -0
  48. package/dist/assets/tasks/improve/akm-improve-nightly.yml +5 -0
  49. package/dist/assets/templates/html/health.html +5 -4
  50. package/dist/assets/workflows/workflow-template.md +31 -15
  51. package/dist/cli/invocation.js +279 -0
  52. package/dist/cli/parse-args.js +5 -90
  53. package/dist/cli/retired-commands.js +78 -0
  54. package/dist/cli/shared.js +158 -48
  55. package/dist/cli-node.mjs +2 -1
  56. package/dist/cli.js +747 -293
  57. package/dist/commands/agent/agent-dispatch.js +19 -18
  58. package/dist/commands/agent/agent-support.js +0 -24
  59. package/dist/commands/agent/contribute-cli.js +43 -97
  60. package/dist/commands/completions.js +80 -23
  61. package/dist/commands/config-cli.js +44 -281
  62. package/dist/commands/env/env-binding.js +99 -0
  63. package/dist/commands/env/env-cli.js +84 -224
  64. package/dist/commands/env/env.js +12 -163
  65. package/dist/commands/env/marker-path.js +6 -0
  66. package/dist/commands/env/secret-cli.js +45 -61
  67. package/dist/commands/env/secret.js +32 -62
  68. package/dist/commands/feedback-cli.js +179 -85
  69. package/dist/commands/health/accept-rate.js +58 -0
  70. package/dist/commands/health/advisories.js +7 -8
  71. package/dist/commands/health/checks.js +279 -94
  72. package/dist/commands/health/html-report.js +197 -578
  73. package/dist/commands/health/improve-metrics.js +277 -246
  74. package/dist/commands/health/llm-usage.js +19 -19
  75. package/dist/commands/health/md-report.js +16 -7
  76. package/dist/commands/health/metrics.js +67 -32
  77. package/dist/commands/health/renderers.js +47 -0
  78. package/dist/commands/health/report-view-model.js +508 -0
  79. package/dist/commands/health/stash-exposure.js +1 -1
  80. package/dist/commands/health/surfaces.js +16 -56
  81. package/dist/commands/health/task-runs.js +3 -67
  82. package/dist/{migrate-storage-node.mjs → commands/health/types-checks.js} +1 -5
  83. package/dist/commands/health/types-improve.js +29 -0
  84. package/dist/{output/text/save.js → commands/health/types-metrics.js} +1 -2
  85. package/dist/commands/health/types-result.js +7 -0
  86. package/dist/commands/health/types-runs.js +4 -0
  87. package/dist/commands/health/types-session-log.js +4 -0
  88. package/dist/commands/health/types-windows.js +4 -0
  89. package/dist/commands/health/types.js +26 -21
  90. package/dist/commands/health/windows.js +2 -3
  91. package/dist/commands/health.js +296 -167
  92. package/dist/commands/improve/anti-collapse.js +5 -5
  93. package/dist/commands/improve/autonomy-gate.js +68 -0
  94. package/dist/commands/improve/collapse-detector.js +65 -52
  95. package/dist/commands/improve/consolidate/chunking.js +9 -7
  96. package/dist/commands/improve/consolidate/eligibility.js +1 -23
  97. package/dist/commands/improve/consolidate/merge.js +4 -0
  98. package/dist/commands/improve/consolidate.js +454 -1354
  99. package/dist/commands/improve/content-hash.js +39 -0
  100. package/dist/commands/improve/distill/content-repair.js +4 -10
  101. package/dist/commands/improve/distill/promote-memory.js +89 -64
  102. package/dist/commands/improve/distill/quality-gate.js +118 -42
  103. package/dist/commands/improve/distill-guards.js +1 -1
  104. package/dist/commands/improve/distill-promotion-policy.js +33 -888
  105. package/dist/commands/improve/distill.js +607 -363
  106. package/dist/commands/improve/eligibility.js +165 -79
  107. package/dist/commands/improve/extract-cli.js +35 -126
  108. package/dist/commands/improve/extract-prompt.js +6 -35
  109. package/dist/commands/improve/extract.js +640 -391
  110. package/dist/commands/improve/feedback-valence.js +2 -12
  111. package/dist/commands/improve/improve-cli.js +134 -135
  112. package/dist/commands/improve/improve-result-file.js +30 -50
  113. package/dist/commands/improve/improve-run-types.js +4 -0
  114. package/dist/commands/improve/improve-strategies.js +135 -0
  115. package/dist/commands/improve/improve.js +904 -701
  116. package/dist/commands/improve/locks.js +64 -111
  117. package/dist/commands/improve/loop-stages.js +1110 -923
  118. package/dist/commands/improve/memory/derived-ref.js +124 -0
  119. package/dist/commands/improve/memory/memory-belief.js +79 -7
  120. package/dist/commands/improve/memory/memory-contradiction-detect.js +49 -52
  121. package/dist/commands/improve/memory/memory-improve.js +25 -37
  122. package/dist/commands/improve/outcome-loop.js +25 -88
  123. package/dist/commands/improve/preparation.js +1034 -813
  124. package/dist/commands/improve/proactive-maintenance.js +34 -9
  125. package/dist/commands/improve/proposal-envelope.js +31 -0
  126. package/dist/commands/improve/reflect.js +983 -794
  127. package/dist/commands/improve/run-context.js +119 -0
  128. package/dist/commands/improve/salience.js +24 -127
  129. package/dist/commands/improve/session-asset.js +7 -3
  130. package/dist/commands/improve/shared.js +14 -34
  131. package/dist/commands/improve/source-identity.js +28 -0
  132. package/dist/commands/improve/triage.js +20 -17
  133. package/dist/commands/lint/base-linter.js +340 -313
  134. package/dist/commands/lint/env-key-rules.js +31 -47
  135. package/dist/commands/lint/index.js +185 -30
  136. package/dist/commands/{events.js → log.js} +28 -38
  137. package/dist/commands/migrate-cli.js +54 -0
  138. package/dist/commands/migration-tool.js +55 -0
  139. package/dist/commands/observability-cli.js +70 -208
  140. package/dist/commands/proposal/diff-format.js +50 -0
  141. package/dist/commands/proposal/drain-policies.js +0 -6
  142. package/dist/commands/proposal/drain.js +91 -40
  143. package/dist/commands/proposal/proposal-cli.js +134 -132
  144. package/dist/commands/proposal/proposal-types.js +56 -0
  145. package/dist/commands/proposal/proposal.js +83 -65
  146. package/dist/commands/proposal/propose-cli.js +88 -0
  147. package/dist/commands/proposal/propose.js +105 -88
  148. package/dist/commands/proposal/repository.js +1303 -278
  149. package/dist/commands/proposal/validators/proposal-quality-validators.js +16 -6
  150. package/dist/commands/proposal/validators/proposal-validators.js +61 -12
  151. package/dist/commands/proposal/validators/proposals.js +6 -8
  152. package/dist/commands/read/curate.js +78 -73
  153. package/dist/commands/read/knowledge.js +510 -13
  154. package/dist/commands/read/registry-search.js +2 -2
  155. package/dist/commands/read/remember-cli.js +84 -15
  156. package/dist/commands/read/search-cli.js +203 -96
  157. package/dist/commands/read/search.js +126 -94
  158. package/dist/commands/read/show.js +226 -250
  159. package/dist/commands/registry-cli.js +34 -60
  160. package/dist/commands/remember.js +18 -57
  161. package/dist/commands/sources/add-cli.js +104 -49
  162. package/dist/commands/sources/bundle-cli.js +166 -0
  163. package/dist/commands/sources/bundle-config-ops.js +63 -0
  164. package/dist/commands/sources/info.js +27 -15
  165. package/dist/commands/sources/init.js +30 -40
  166. package/dist/commands/sources/installed-stashes.js +469 -172
  167. package/dist/commands/sources/migration-help.js +7 -4
  168. package/dist/commands/sources/schema-repair.js +10 -9
  169. package/dist/commands/sources/self-update.js +182 -121
  170. package/dist/commands/sources/source-add.js +169 -178
  171. package/dist/commands/sources/source-clone.js +144 -41
  172. package/dist/commands/sources/source-manage.js +94 -59
  173. package/dist/commands/sources/sources-cli.js +64 -205
  174. package/dist/commands/sources/stash-cli.js +91 -54
  175. package/dist/commands/sources/stash-skeleton.js +1 -1
  176. package/dist/commands/tasks/tasks-cli.js +106 -104
  177. package/dist/commands/tasks/tasks.js +445 -262
  178. package/dist/commands/workflow-cli.js +232 -121
  179. package/dist/core/action-contributors.js +1 -1
  180. package/dist/core/activation-policy.js +49 -0
  181. package/dist/core/adapter/adapters/agent-skills-adapter.js +181 -0
  182. package/dist/core/adapter/adapters/akm-adapter.js +528 -0
  183. package/dist/core/adapter/adapters/akm-lint.js +392 -0
  184. package/dist/core/adapter/adapters/akm-metadata.js +387 -0
  185. package/dist/core/adapter/adapters/akm-task-adapter.js +149 -0
  186. package/dist/core/adapter/adapters/akm-workflow-adapter.js +180 -0
  187. package/dist/core/adapter/adapters/claude-adapter.js +61 -0
  188. package/dist/core/adapter/adapters/dotenv-adapter.js +187 -0
  189. package/dist/core/adapter/adapters/generic-files-adapter.js +119 -0
  190. package/dist/core/adapter/adapters/index.js +80 -0
  191. package/dist/core/adapter/adapters/llm-wiki-adapter.js +419 -0
  192. package/dist/core/adapter/adapters/okf-adapter.js +391 -0
  193. package/dist/core/adapter/adapters/opencode-adapter.js +68 -0
  194. package/dist/core/adapter/adapters/shared.js +286 -0
  195. package/dist/core/adapter/adapters/tool-dir-shared.js +217 -0
  196. package/dist/core/adapter/adapters/website-snapshot-adapter.js +155 -0
  197. package/dist/core/adapter/bundle-adapter.js +4 -0
  198. package/dist/core/adapter/detect-adapter.js +17 -0
  199. package/dist/core/adapter/recognize-match.js +44 -0
  200. package/dist/core/adapter/registry.js +56 -0
  201. package/dist/core/adapter/types.js +4 -0
  202. package/dist/core/asset/akm-markdown.js +30 -0
  203. package/dist/core/asset/asset-placement.js +243 -0
  204. package/dist/core/asset/asset-ref.js +110 -79
  205. package/dist/core/asset/asset-serialize.js +20 -0
  206. package/dist/core/asset/frontmatter.js +28 -12
  207. package/dist/core/asset/markdown.js +40 -51
  208. package/dist/core/asset/resolve-ref.js +274 -0
  209. package/dist/core/asset/stash-meta.js +2 -2
  210. package/dist/core/bundle-id.js +51 -0
  211. package/dist/core/common.js +281 -86
  212. package/dist/core/config/config-io.js +42 -128
  213. package/dist/core/config/config-schema.js +233 -834
  214. package/dist/core/config/config-sources.js +162 -39
  215. package/dist/core/config/config-types.js +16 -11
  216. package/dist/core/config/config-version.js +29 -0
  217. package/dist/core/config/config-walker.js +126 -37
  218. package/dist/core/config/config.js +154 -331
  219. package/dist/core/config/deep-merge.js +41 -0
  220. package/dist/core/config/engine-semantics.js +28 -0
  221. package/dist/core/config/experimental.js +21 -0
  222. package/dist/core/config/schema/embedding.js +38 -0
  223. package/dist/core/config/schema/engines.js +116 -0
  224. package/dist/core/config/schema/experimental.js +47 -0
  225. package/dist/core/config/schema/feedback.js +31 -0
  226. package/dist/core/config/schema/improve-processes.js +389 -0
  227. package/dist/core/config/schema/improve.js +94 -0
  228. package/dist/core/config/schema/index-config.js +176 -0
  229. package/dist/core/config/schema/output.js +18 -0
  230. package/dist/core/config/schema/primitives.js +94 -0
  231. package/dist/core/config/schema/search.js +30 -0
  232. package/dist/core/config/schema/setup.js +18 -0
  233. package/dist/core/config/schema/sources-bundles.js +169 -0
  234. package/dist/core/config/schema/workflow.js +29 -0
  235. package/dist/core/env-secret-ref.js +155 -20
  236. package/dist/core/errors.js +17 -15
  237. package/dist/core/events-types.js +4 -0
  238. package/dist/core/events.js +46 -128
  239. package/dist/core/extra-params.js +62 -0
  240. package/dist/core/file-change.js +17 -0
  241. package/dist/core/file-lock.js +202 -57
  242. package/dist/core/fs-txn.js +392 -0
  243. package/dist/core/git-message.js +59 -0
  244. package/dist/core/improve-result.js +167 -0
  245. package/dist/core/json-schema.js +142 -0
  246. package/dist/core/lesson-lint.js +1 -17
  247. package/dist/core/logs-db.js +1 -1
  248. package/dist/core/maintenance-barrier.js +135 -0
  249. package/dist/core/migration-operation.js +44 -0
  250. package/dist/core/mutation-target.js +78 -0
  251. package/dist/core/paths.js +22 -25
  252. package/dist/core/platform.js +10 -0
  253. package/dist/core/recognition-util.js +128 -0
  254. package/dist/core/redaction.js +392 -0
  255. package/dist/core/standards/resolve-standards-context.js +36 -65
  256. package/dist/core/standards/resolve-stash-standards.js +2 -2
  257. package/dist/core/standards/resolve-type-conventions.js +5 -5
  258. package/dist/core/state/migrations.js +242 -11
  259. package/dist/core/state-db.js +98 -10
  260. package/dist/core/structured.js +1 -1
  261. package/dist/core/subprocess.js +303 -0
  262. package/dist/core/text-truncation.js +9 -5
  263. package/dist/core/time.js +20 -0
  264. package/dist/core/type-presentation.js +130 -0
  265. package/dist/core/warn.js +0 -3
  266. package/dist/core/write-source.js +834 -118
  267. package/dist/indexer/bundle-identity-guard.js +92 -0
  268. package/dist/indexer/db/graph-db.js +1 -25
  269. package/dist/indexer/db/llm-cache.js +1 -1
  270. package/dist/indexer/ensure-index.js +30 -9
  271. package/dist/indexer/graph/graph-boost.js +9 -30
  272. package/dist/indexer/graph/graph-extraction.js +41 -27
  273. package/dist/indexer/graph/graph-types.js +4 -0
  274. package/dist/indexer/index-writer-lock.js +93 -49
  275. package/dist/indexer/index-written-assets.js +100 -53
  276. package/dist/indexer/indexer.js +746 -329
  277. package/dist/indexer/init.js +18 -25
  278. package/dist/indexer/installations.js +142 -0
  279. package/dist/indexer/passes/dir-staleness.js +18 -10
  280. package/dist/indexer/passes/memory-inference.js +25 -15
  281. package/dist/indexer/passes/metadata.js +412 -243
  282. package/dist/indexer/scan/doc-to-entry.js +160 -0
  283. package/dist/indexer/scan/drain-dir.js +134 -0
  284. package/dist/indexer/search/db-search.js +292 -108
  285. package/dist/indexer/search/fts-query.js +64 -0
  286. package/dist/indexer/search/ranking-contributors.js +145 -25
  287. package/dist/indexer/search/ranking-types.js +4 -0
  288. package/dist/indexer/search/ranking.js +28 -71
  289. package/dist/indexer/search/search-attribution.js +67 -0
  290. package/dist/indexer/search/search-fields.js +18 -3
  291. package/dist/indexer/search/search-hit-enrichers.js +30 -40
  292. package/dist/indexer/search/search-source.js +157 -111
  293. package/dist/indexer/search/semantic-status.js +4 -1
  294. package/dist/indexer/usage/usage-events.js +10 -30
  295. package/dist/indexer/walk/file-context.js +3 -45
  296. package/dist/indexer/walk/matchers.js +42 -34
  297. package/dist/indexer/walk/path-resolver.js +11 -5
  298. package/dist/indexer/walk/walker.js +42 -14
  299. package/dist/integrations/agent/builder-shared.js +7 -0
  300. package/dist/integrations/agent/builders.js +5 -56
  301. package/dist/integrations/agent/config.js +3 -143
  302. package/dist/integrations/agent/detect.js +17 -2
  303. package/dist/integrations/agent/engine-resolution.js +231 -0
  304. package/dist/integrations/agent/index.js +1 -2
  305. package/dist/integrations/agent/model-aliases.js +16 -2
  306. package/dist/integrations/agent/profiles.js +36 -62
  307. package/dist/integrations/agent/prompts.js +46 -18
  308. package/dist/integrations/agent/runner-dispatch.js +93 -4
  309. package/dist/integrations/agent/runner.js +76 -208
  310. package/dist/integrations/agent/spawn.js +88 -196
  311. package/dist/integrations/harnesses/aider/agent-builder.js +114 -0
  312. package/dist/integrations/harnesses/aider/index.js +48 -0
  313. package/dist/integrations/harnesses/aider/result-extractor.js +53 -0
  314. package/dist/integrations/harnesses/amazonq/agent-builder.js +147 -0
  315. package/dist/integrations/harnesses/amazonq/index.js +45 -0
  316. package/dist/integrations/harnesses/amazonq/result-extractor.js +48 -0
  317. package/dist/integrations/harnesses/claude/agent-builder.js +46 -8
  318. package/dist/integrations/harnesses/claude/config-import.js +1 -3
  319. package/dist/integrations/harnesses/claude/index.js +24 -35
  320. package/dist/integrations/harnesses/claude/result-extractor.js +52 -0
  321. package/dist/integrations/harnesses/claude/session-log.js +27 -75
  322. package/dist/integrations/harnesses/codex/agent-builder.js +138 -0
  323. package/dist/integrations/harnesses/codex/index.js +52 -0
  324. package/dist/integrations/harnesses/codex/result-extractor.js +73 -0
  325. package/dist/integrations/harnesses/copilot/agent-builder.js +122 -0
  326. package/dist/integrations/harnesses/copilot/index.js +48 -0
  327. package/dist/integrations/harnesses/copilot/result-extractor.js +151 -0
  328. package/dist/integrations/harnesses/gemini/agent-builder.js +120 -0
  329. package/dist/integrations/harnesses/gemini/index.js +48 -0
  330. package/dist/integrations/harnesses/gemini/result-extractor.js +121 -0
  331. package/dist/integrations/harnesses/ids.js +24 -0
  332. package/dist/integrations/harnesses/index.js +54 -34
  333. package/dist/integrations/harnesses/opencode/agent-builder.js +23 -5
  334. package/dist/integrations/harnesses/opencode/config-import.js +1 -3
  335. package/dist/integrations/harnesses/opencode/index.js +14 -32
  336. package/dist/integrations/harnesses/opencode/session-log.js +67 -125
  337. package/dist/integrations/harnesses/opencode-sdk/harness.js +51 -0
  338. package/dist/integrations/harnesses/opencode-sdk/sdk-runner.js +681 -108
  339. package/dist/integrations/harnesses/openhands/agent-builder.js +128 -0
  340. package/dist/integrations/harnesses/openhands/index.js +48 -0
  341. package/dist/integrations/harnesses/openhands/result-extractor.js +103 -0
  342. package/dist/integrations/harnesses/pi/agent-builder.js +97 -0
  343. package/dist/integrations/harnesses/pi/index.js +45 -0
  344. package/dist/integrations/harnesses/pi/result-extractor.js +135 -0
  345. package/dist/integrations/harnesses/shared.js +17 -0
  346. package/dist/integrations/harnesses/types.js +43 -32
  347. package/dist/integrations/lockfile.js +211 -24
  348. package/dist/integrations/session-logs/index.js +36 -39
  349. package/dist/integrations/session-logs/provider-base.js +113 -0
  350. package/dist/llm/client.js +182 -110
  351. package/dist/llm/embedders/deterministic.js +2 -2
  352. package/dist/llm/embedders/remote.js +21 -9
  353. package/dist/llm/feature-gate.js +17 -57
  354. package/dist/llm/graph-extract.js +12 -13
  355. package/dist/llm/index-passes.js +8 -42
  356. package/dist/llm/memory-infer.js +144 -1
  357. package/dist/llm/metadata-enhance.js +45 -30
  358. package/dist/llm/structured-call.js +16 -8
  359. package/dist/llm/usage-persist.js +30 -5
  360. package/dist/llm/usage-telemetry.js +59 -6
  361. package/dist/output/cli-hints.js +1 -2
  362. package/dist/output/command-registry.js +27 -0
  363. package/dist/output/context.js +22 -7
  364. package/dist/output/format-exempt.js +80 -0
  365. package/dist/output/generic-render.js +251 -0
  366. package/dist/output/html-render.js +11 -16
  367. package/dist/output/render-registry.js +57 -0
  368. package/dist/output/renderers.js +14 -279
  369. package/dist/output/shapes/curate.js +10 -1
  370. package/dist/output/shapes/events.js +12 -7
  371. package/dist/output/shapes/helpers.js +58 -84
  372. package/dist/output/shapes/passthrough.js +11 -39
  373. package/dist/output/shapes/proposal/producer.js +15 -7
  374. package/dist/output/shapes/registry.js +12 -6
  375. package/dist/output/shapes.js +0 -9
  376. package/dist/output/text/{init.js → bundle-create.js} +3 -1
  377. package/dist/output/text/bundle-show.js +7 -0
  378. package/dist/output/text/command-format.js +562 -0
  379. package/dist/output/text/env.js +1 -3
  380. package/dist/output/text/events.js +8 -7
  381. package/dist/output/text/helpers.js +15 -1164
  382. package/dist/output/text/proposal/producer.js +4 -2
  383. package/dist/output/text/proposal-format.js +202 -0
  384. package/dist/output/text/registry-commands.js +1 -2
  385. package/dist/output/text/registry.js +12 -6
  386. package/dist/output/text/show-directives.js +117 -0
  387. package/dist/output/text/show-format.js +103 -0
  388. package/dist/output/text/sync.js +5 -0
  389. package/dist/output/text/workflow-format.js +332 -0
  390. package/dist/output/text/workflow.js +3 -2
  391. package/dist/output/text.js +10 -19
  392. package/dist/registry/factory.js +4 -6
  393. package/dist/registry/origin-resolve.js +16 -27
  394. package/dist/registry/providers/skills-sh.js +3 -3
  395. package/dist/registry/providers/static-index.js +15 -25
  396. package/dist/registry/resolve.js +43 -94
  397. package/dist/registry/semver.js +43 -0
  398. package/dist/runtime.js +81 -12
  399. package/dist/scripts/akm-migrate.js +35529 -0
  400. package/dist/setup/detect.js +5 -7
  401. package/dist/setup/detected-engines.js +136 -0
  402. package/dist/setup/engine-config.js +100 -0
  403. package/dist/setup/registry-stash-loader.js +3 -3
  404. package/dist/setup/semantic-assets.js +12 -9
  405. package/dist/setup/setup.js +444 -208
  406. package/dist/setup/steps/connection-shared.js +120 -0
  407. package/dist/setup/steps/connection.js +108 -305
  408. package/dist/setup/steps/platforms.js +13 -12
  409. package/dist/setup/steps/semantic.js +15 -3
  410. package/dist/setup/steps/sources.js +21 -15
  411. package/dist/setup/steps/stashdir.js +6 -4
  412. package/dist/setup/steps/tasks.js +236 -119
  413. package/dist/setup/steps.js +3 -2
  414. package/dist/sources/freshness.js +39 -0
  415. package/dist/sources/provider-factory.js +11 -17
  416. package/dist/sources/providers/filesystem.js +2 -3
  417. package/dist/sources/providers/git-install.js +278 -34
  418. package/dist/sources/providers/git-provider.js +54 -56
  419. package/dist/sources/providers/git-stash.js +420 -91
  420. package/dist/sources/providers/git.js +2 -2
  421. package/dist/sources/providers/npm.js +16 -19
  422. package/dist/sources/providers/provider-utils.js +47 -22
  423. package/dist/sources/providers/sync-from-ref.js +3 -9
  424. package/dist/sources/providers/website.js +2 -2
  425. package/dist/sources/resolve.js +11 -10
  426. package/dist/sources/snapshot-fetchers/types.js +4 -0
  427. package/dist/sources/{website-ingest.js → snapshot-fetchers/website-ingest.js} +110 -41
  428. package/dist/storage/database.js +60 -4
  429. package/dist/storage/engines/sqlite-migrations.js +156 -5
  430. package/dist/storage/locations.js +1 -2
  431. package/dist/storage/repositories/canaries-repository.js +1 -1
  432. package/dist/storage/repositories/events-repository.js +51 -11
  433. package/dist/storage/repositories/improve-runs-repository.js +6 -32
  434. package/dist/storage/repositories/index-connection.js +79 -0
  435. package/dist/storage/repositories/index-db.js +4 -3
  436. package/dist/storage/repositories/index-entries-repository.js +863 -0
  437. package/dist/{indexer/db/entry-mapper.js → storage/repositories/index-entry-mapper.js} +19 -2
  438. package/dist/storage/repositories/index-entry-types.js +4 -0
  439. package/dist/storage/repositories/index-fts-repository.js +167 -0
  440. package/dist/storage/repositories/index-llm-cache-repository.js +108 -0
  441. package/dist/storage/repositories/index-meta-repository.js +49 -0
  442. package/dist/{indexer/db/schema.js → storage/repositories/index-schema.js} +226 -100
  443. package/dist/storage/repositories/index-sql.js +12 -0
  444. package/dist/storage/repositories/index-utility-repository.js +356 -0
  445. package/dist/storage/repositories/index-vec-repository.js +250 -0
  446. package/dist/storage/repositories/outcome-repository.js +119 -0
  447. package/dist/storage/repositories/proposals-repository.js +317 -75
  448. package/dist/storage/repositories/registry-cache.js +1 -1
  449. package/dist/storage/repositories/salience-repository.js +172 -0
  450. package/dist/storage/repositories/task-history-repository.js +110 -3
  451. package/dist/storage/repositories/workflow-runs-repository.js +240 -19
  452. package/dist/tasks/backends/cron.js +169 -46
  453. package/dist/tasks/backends/exec-utils.js +76 -3
  454. package/dist/tasks/backends/index.js +6 -9
  455. package/dist/tasks/backends/launchd.js +292 -55
  456. package/dist/tasks/backends/schtasks.js +557 -70
  457. package/dist/tasks/backends/types.js +4 -0
  458. package/dist/tasks/command-executable.js +93 -0
  459. package/dist/tasks/embedded.js +56 -38
  460. package/dist/tasks/parser.js +156 -64
  461. package/dist/tasks/resolve-akm-bin.js +144 -51
  462. package/dist/tasks/runner.js +377 -209
  463. package/dist/tasks/schedule.js +108 -19
  464. package/dist/tasks/scheduler-invocation.js +296 -0
  465. package/dist/tasks/schema.js +1 -1
  466. package/dist/tasks/task-id.js +35 -0
  467. package/dist/tasks/validator.js +30 -16
  468. package/dist/text-import-hook.mjs +1 -1
  469. package/dist/workflows/authoring/authoring.js +104 -43
  470. package/dist/workflows/authoring/scope-key.js +1 -1
  471. package/dist/workflows/cli.js +0 -16
  472. package/dist/workflows/concurrency-policy.js +15 -0
  473. package/dist/workflows/exec/brief.js +450 -0
  474. package/dist/workflows/exec/frozen-judge.js +47 -0
  475. package/dist/workflows/exec/native-executor.js +1038 -0
  476. package/dist/workflows/exec/param-secrets.js +115 -0
  477. package/dist/workflows/exec/report.js +1460 -0
  478. package/dist/workflows/exec/run-workflow.js +602 -0
  479. package/dist/workflows/exec/scheduler.js +71 -0
  480. package/dist/workflows/exec/step-work.js +1190 -0
  481. package/dist/workflows/exec/unit-writer.js +23 -0
  482. package/dist/workflows/exec/workflow-engine-gate.js +67 -0
  483. package/dist/workflows/exec/worktree.js +171 -0
  484. package/dist/workflows/ir/compile.js +246 -0
  485. package/dist/workflows/ir/freeze.js +233 -0
  486. package/dist/workflows/ir/params.js +54 -0
  487. package/dist/workflows/ir/plan-hash.js +68 -0
  488. package/dist/workflows/ir/schema.js +540 -0
  489. package/dist/workflows/parser.js +878 -304
  490. package/dist/workflows/program/expressions.js +181 -0
  491. package/dist/workflows/program/schema.js +51 -0
  492. package/dist/workflows/renderer.js +100 -45
  493. package/dist/workflows/resource-limits.js +22 -0
  494. package/dist/workflows/runtime/agent-identity.js +59 -14
  495. package/dist/workflows/runtime/checkin.js +1 -1
  496. package/dist/workflows/runtime/plan-classifier.js +131 -0
  497. package/dist/workflows/runtime/runs.js +376 -119
  498. package/dist/workflows/runtime/unit-checkin.js +45 -0
  499. package/dist/workflows/runtime/unit-phases.js +20 -0
  500. package/dist/workflows/runtime/workflow-asset-loader.js +241 -40
  501. package/dist/workflows/schema.js +1 -11
  502. package/dist/workflows/validate-summary.js +2 -3
  503. package/dist/workflows/validator.js +52 -30
  504. package/docs/README.md +42 -78
  505. package/docs/migration/README.md +8 -0
  506. package/docs/migration/release-notes/0.6.0.md +1 -1
  507. package/docs/migration/release-notes/0.7.0.md +9 -8
  508. package/docs/migration/release-notes/0.9.0.md +158 -14
  509. package/docs/migration/v0.7-to-v0.8.md +46 -47
  510. package/docs/migration/v0.8-to-v0.9.md +844 -0
  511. package/docs/reference/README.md +12 -0
  512. package/docs/reference/data-and-telemetry.md +333 -0
  513. package/package.json +21 -17
  514. package/schemas/akm-asset-envelope.json +93 -0
  515. package/schemas/akm-config.json +4636 -0
  516. package/schemas/akm-task.json +87 -0
  517. package/schemas/akm-workflow.json +373 -0
  518. package/dist/akm-migrate-storage +0 -38
  519. package/dist/assets/help/help-accept.md +0 -12
  520. package/dist/assets/help/help-improve.md +0 -84
  521. package/dist/assets/help/help-proposals.md +0 -17
  522. package/dist/assets/help/help-propose.md +0 -17
  523. package/dist/assets/help/help-reject.md +0 -11
  524. package/dist/assets/profiles/frequent.json +0 -13
  525. package/dist/assets/profiles/recombine-only.json +0 -21
  526. package/dist/assets/profiles/reflect-distill.json +0 -30
  527. package/dist/assets/profiles/synthesize.json +0 -15
  528. package/dist/assets/prompts/procedural-system.md +0 -44
  529. package/dist/assets/prompts/recombine-system.md +0 -40
  530. package/dist/assets/prompts/staleness-detect-system.md +0 -6
  531. package/dist/assets/tasks/core/backup.yml +0 -4
  532. package/dist/assets/tasks/graph-refresh-weekly.yml +0 -10
  533. package/dist/assets/templates/html/default.html +0 -78
  534. package/dist/assets/templates/html/vendor/echarts.min.js +0 -45
  535. package/dist/assets/wiki/index-template.md +0 -12
  536. package/dist/assets/wiki/ingest-workflow-template.md +0 -83
  537. package/dist/assets/wiki/log-template.md +0 -8
  538. package/dist/assets/wiki/schema-template.md +0 -61
  539. package/dist/cli/config-migrate.js +0 -150
  540. package/dist/cli/config-validate.js +0 -39
  541. package/dist/commands/graph/graph-cli.js +0 -124
  542. package/dist/commands/graph/graph.js +0 -487
  543. package/dist/commands/improve/calibration.js +0 -161
  544. package/dist/commands/improve/dedup.js +0 -482
  545. package/dist/commands/improve/extract-watch.js +0 -140
  546. package/dist/commands/improve/hot-probation.js +0 -45
  547. package/dist/commands/improve/improve-auto-accept.js +0 -276
  548. package/dist/commands/improve/improve-profiles.js +0 -168
  549. package/dist/commands/improve/procedural.js +0 -398
  550. package/dist/commands/improve/recombine.js +0 -818
  551. package/dist/commands/improve/schema-similarity-gate.js +0 -168
  552. package/dist/commands/lint/agent-linter.js +0 -44
  553. package/dist/commands/lint/command-linter.js +0 -44
  554. package/dist/commands/lint/default-linter.js +0 -16
  555. package/dist/commands/lint/fact-linter.js +0 -39
  556. package/dist/commands/lint/knowledge-linter.js +0 -16
  557. package/dist/commands/lint/memory-linter.js +0 -61
  558. package/dist/commands/lint/registry.js +0 -41
  559. package/dist/commands/lint/skill-linter.js +0 -45
  560. package/dist/commands/lint/task-linter.js +0 -50
  561. package/dist/commands/lint/workflow-linter.js +0 -81
  562. package/dist/commands/proposal/legacy-import.js +0 -115
  563. package/dist/commands/sources/history.js +0 -196
  564. package/dist/commands/tasks/default-tasks.js +0 -186
  565. package/dist/commands/wiki-cli.js +0 -292
  566. package/dist/core/asset/asset-registry.js +0 -76
  567. package/dist/core/asset/asset-spec.js +0 -259
  568. package/dist/core/config/config-migration.js +0 -602
  569. package/dist/core/deep-merge.js +0 -38
  570. package/dist/core/eval/rank-metrics.js +0 -113
  571. package/dist/core/ripgrep/install.js +0 -163
  572. package/dist/core/ripgrep/resolve.js +0 -81
  573. package/dist/indexer/db/db.js +0 -1413
  574. package/dist/indexer/manifest.js +0 -170
  575. package/dist/indexer/passes/metadata-contributors.js +0 -31
  576. package/dist/indexer/usage/unmigrated-vaults-guard.js +0 -94
  577. package/dist/integrations/harnesses/opencode-sdk/index.js +0 -49
  578. package/dist/llm/call-ai.js +0 -62
  579. package/dist/llm/memory-infer-impl.js +0 -138
  580. package/dist/output/shapes/distill.js +0 -14
  581. package/dist/output/shapes/history.js +0 -11
  582. package/dist/output/text/distill.js +0 -6
  583. package/dist/output/text/enable-disable.js +0 -8
  584. package/dist/output/text/history.js +0 -6
  585. package/dist/output/text/wiki.js +0 -16
  586. package/dist/registry/build-index.js +0 -386
  587. package/dist/scripts/migrate-storage.js +0 -19108
  588. package/dist/scripts/migrations/import-fs-improve-runs-to-db.js +0 -9411
  589. package/dist/scripts/migrations/v16-to-v17.js +0 -141
  590. package/dist/setup/legacy-config.js +0 -106
  591. package/dist/storage/repositories/consolidation-repository.js +0 -38
  592. package/dist/storage/repositories/recombine-repository.js +0 -213
  593. package/dist/wiki/wiki-templates.js +0 -15
  594. package/dist/wiki/wiki.js +0 -1012
  595. package/dist/workflows/db.js +0 -215
  596. package/docs/data-and-telemetry.md +0 -226
  597. /package/dist/sources/{wiki-fetchers → snapshot-fetchers}/registry.js +0 -0
  598. /package/dist/sources/{wiki-fetchers → snapshot-fetchers}/youtube.js +0 -0
@@ -2,86 +2,57 @@
2
2
  // License, v. 2.0. If a copy of the MPL was not distributed with this
3
3
  // file, You can obtain one at https://mozilla.org/MPL/2.0/.
4
4
  /**
5
- * Dispatch resolver for the standards prompt seam — selects which of the two
6
- * standards features fires for a given write target, mutually exclusively:
5
+ * Dispatch resolver for the standards prompt seam.
7
6
  *
8
- * - **Feature A — wiki schema**: the target is a wiki page (a ref/path under
9
- * `wikis/<name>/`, NOT a `raw/` file and NOT a wiki infra file
10
- * `schema.md`/`index.md`/`log.md`). Returns that wiki's `schema.md` body.
11
- * - **Feature B — stash standards**: the target is any non-wiki asset.
12
- * Returns the concatenated `category: convention`/`meta` fact bodies.
13
- * - **Neither fires**: a wiki `raw/` file or a wiki infra file. Returns `""`.
14
- *
15
- * The two NEVER both fire. Both underlying readers degrade to `""` on
16
- * missing/malformed input and never throw, so this resolver never throws.
7
+ * The wiki `schema.md` injection (former "Feature A") was collapsed in chunk 4
8
+ * with the wiki asset-type death (plan §11 Chunk 4): LLM Wiki content is served
9
+ * by the `llm-wiki` adapter, which owns its own `schema.md` contract. What
10
+ * remains is **stash standards**: for any write target, return the concatenated
11
+ * `category: convention`/`meta` fact bodies plus the per-type SOFT conventions
12
+ * layer (#646), type-scoped to the write target. The underlying readers degrade
13
+ * to `""` on missing/malformed input and never throw, so this resolver never
14
+ * throws.
17
15
  */
18
- import { extractWikiNameFromRef, INDEX_MD, LOG_MD, loadWikiSchema, SCHEMA_MD } from "../../wiki/wiki.js";
16
+ import { typeNameFromConceptId } from "../asset/resolve-ref.js";
19
17
  import { resolveStashStandards } from "./resolve-stash-standards.js";
20
18
  import { resolveTypeConventions, typeConventionRef } from "./resolve-type-conventions.js";
21
- /** Wiki infra files that are not authored pages (relative to the wiki root). */
22
- const WIKI_INFRA_BASENAMES = new Set([SCHEMA_MD, INDEX_MD, LOG_MD]);
23
19
  /**
24
- * Extract the asset type from a canonical ref (`[origin//]type:name`) without
25
- * throwing. Returns `undefined` for refs that have no `type:` prefix. Kept local
26
- * and lenient — the per-type resolver validates the result against
27
- * `getAssetTypes()`, so a bogus prefix here simply yields no convention.
20
+ * Extract the asset type from a write-target ref without throwing. Returns
21
+ * `undefined` for refs that carry no recognizable type. Kept local and lenient —
22
+ * the per-type resolver validates the result against `placementTypes()`, so a
23
+ * bogus prefix here simply yields no convention.
28
24
  */
29
25
  function refType(ref) {
30
26
  if (!ref)
31
27
  return undefined;
32
28
  const body = ref.includes("//") ? ref.slice(ref.indexOf("//") + 2) : ref;
33
- const colon = body.indexOf(":");
34
- if (colon <= 0)
35
- return undefined;
36
- return body.slice(0, colon).trim() || undefined;
29
+ // 0.9.0 conceptId `<stash-subdir>/<name>`: delegate to the D-R2 reverse table
30
+ // so the leading stash subdir maps back to its asset type (the canonical path).
31
+ return typeNameFromConceptId(body)?.type;
37
32
  }
38
33
  /**
39
34
  * Resolve the standards context for a write target identified by its asset ref.
40
35
  *
41
- * @param ref Canonical asset ref of the write target (e.g. `skill:foo`,
42
- * `wiki:research/topics/x`). When undefined, the target is a
43
- * non-wiki authoring flow → stash standards.
36
+ * @param ref Canonical asset ref of the write target (e.g. `skills/foo`).
37
+ * When undefined, the target is a general authoring flow.
44
38
  * @param stashRoot Stash root directory.
45
39
  */
46
40
  export function resolveStandardsContext(ref, stashRoot) {
47
- const wikiName = ref ? extractWikiNameFromRef(ref) : undefined;
48
- if (!wikiName) {
49
- // Non-wiki asset target → Feature B (general stash standards) plus the
50
- // per-type SOFT conventions layer (#646), type-scoped to the write target.
51
- const general = resolveStashStandards(stashRoot);
52
- const type = refType(ref);
53
- // A non-empty body here guarantees `type` is a `getAssetTypes()`-validated
54
- // string (the resolver returns "" otherwise).
55
- const typeConventions = type ? resolveTypeConventions(stashRoot, type) : "";
56
- if (!typeConventions || !type)
57
- return general;
58
- // Soft, type-scoped guidance — clearly labeled and kept separate from the
59
- // HARD (validator-enforced) rules that `authoringRulesForType` injects
60
- // downstream. These facts are advice only; they never weaken the gate.
61
- const softSection = [
62
- `# ${typeConventionRef(type)} (soft per-type conventions — guidance, not enforced)`,
63
- typeConventions,
64
- ].join("\n");
65
- return general ? `${general}\n\n${softSection}` : softSection;
66
- }
67
- // Wiki target. Extract the page path after `wiki:<name>/`.
68
- const prefix = `wiki:${wikiName}/`;
69
- const pagePath = ref?.startsWith(prefix) ? ref.slice(prefix.length) : "";
70
- // `wiki:<name>` with no page, a `raw/` file, or a wiki infra file → neither
71
- // feature fires.
72
- if (!pagePath)
73
- return "";
74
- if (pagePath === "raw" || pagePath.startsWith("raw/"))
75
- return "";
76
- // Infra files (`schema`/`index`/`log`) are only special at the WIKI ROOT.
77
- // A nested page like `wiki:research/analysis/schema` is a genuine page and
78
- // must NOT be suppressed, so only check when the page is at root depth.
79
- if (!pagePath.includes("/")) {
80
- // Refs drop the `.md` extension; compare against both forms defensively.
81
- if (WIKI_INFRA_BASENAMES.has(pagePath) || WIKI_INFRA_BASENAMES.has(`${pagePath}.md`)) {
82
- return "";
83
- }
84
- }
85
- // A genuine wiki page → Feature A (that wiki's schema body).
86
- return loadWikiSchema(stashRoot, wikiName).body;
41
+ // General stash standards plus the per-type SOFT conventions layer (#646),
42
+ // type-scoped to the write target.
43
+ const general = resolveStashStandards(stashRoot);
44
+ const type = refType(ref);
45
+ // A non-empty body here guarantees `type` is a `placementTypes()`-validated
46
+ // string (the resolver returns "" otherwise).
47
+ const typeConventions = type ? resolveTypeConventions(stashRoot, type) : "";
48
+ if (!typeConventions || !type)
49
+ return general;
50
+ // Soft, type-scoped guidance — clearly labeled and kept separate from the
51
+ // HARD (validator-enforced) rules that `authoringRulesForType` injects
52
+ // downstream. These facts are advice only; they never weaken the gate.
53
+ const softSection = [
54
+ `# ${typeConventionRef(type)} (soft per-type conventions — guidance, not enforced)`,
55
+ typeConventions,
56
+ ].join("\n");
57
+ return general ? `${general}\n\n${softSection}` : softSection;
87
58
  }
@@ -53,14 +53,14 @@ function collectMarkdownFiles(dir) {
53
53
  return results;
54
54
  }
55
55
  /**
56
- * Derive a fact ref (`fact:conventions/naming`) from an absolute markdown path
56
+ * Derive a fact ref (`facts/conventions/naming`) from an absolute markdown path
57
57
  * relative to the facts root. Mirrors the canonical-name derivation in
58
58
  * `asset-spec.ts` (POSIX separators, `.md` stripped).
59
59
  */
60
60
  function toFactRef(factsRoot, absPath) {
61
61
  const rel = path.relative(factsRoot, absPath).split(path.sep).join("/");
62
62
  const name = rel.endsWith(".md") ? rel.slice(0, -3) : rel;
63
- return `fact:${name}`;
63
+ return `${FACTS_SUBDIR}/${name}`;
64
64
  }
65
65
  export function resolveStashStandards(stashRoot) {
66
66
  const factsRoot = path.join(stashRoot, FACTS_SUBDIR);
@@ -17,20 +17,20 @@
17
17
  * hard, validator-rejecting rules: a user editing or deleting one must never be
18
18
  * able to weaken the authoring contract the gate enforces (#645 boundary).
19
19
  *
20
- * Selection is by a `getAssetTypes()`-validated basename: only
20
+ * Selection is by a `placementTypes()`-validated basename: only
21
21
  * `facts/conventions/assets/<known-type>.md` resolves. Read directly from disk
22
22
  * (no index rebuild); any missing dir/file, unknown type, or read error degrades
23
23
  * to `""` and never throws.
24
24
  */
25
25
  import fs from "node:fs";
26
26
  import path from "node:path";
27
- import { getAssetTypes } from "../asset/asset-spec.js";
27
+ import { placementTypes } from "../asset/asset-placement.js";
28
28
  import { parseFrontmatter } from "../asset/frontmatter.js";
29
29
  /** Sub-path (under the stash root) for per-type SOFT convention facts. */
30
30
  export const TYPE_CONVENTIONS_SUBDIR = path.join("facts", "conventions", "assets");
31
- /** The `fact:` ref prefix for a per-type convention, e.g. `fact:conventions/assets/skill`. */
31
+ /** The slash conceptId for a per-type convention, e.g. `facts/conventions/assets/skill`. */
32
32
  export function typeConventionRef(type) {
33
- return `fact:conventions/assets/${type}`;
33
+ return `facts/conventions/assets/${type}`;
34
34
  }
35
35
  /**
36
36
  * Read the SOFT authoring-convention body for asset type `type`, if a stash
@@ -43,7 +43,7 @@ export function resolveTypeConventions(stashRoot, type) {
43
43
  if (!stashRoot || !type)
44
44
  return "";
45
45
  // Basename MUST be a known asset type — never resolve an arbitrary file.
46
- if (!getAssetTypes().includes(type))
46
+ if (!placementTypes().includes(type))
47
47
  return "";
48
48
  const abs = path.join(stashRoot, TYPE_CONVENTIONS_SUBDIR, `${type}.md`);
49
49
  let raw;
@@ -2,7 +2,7 @@
2
2
  // License, v. 2.0. If a copy of the MPL was not distributed with this
3
3
  // file, You can obtain one at https://mozilla.org/MPL/2.0/.
4
4
  import { runMigrations as runSqliteMigrations } from "../../storage/engines/sqlite-migrations.js";
5
- const MIGRATIONS = [
5
+ export const STATE_MIGRATIONS = [
6
6
  // ── Migration 001 — initial schema ──────────────────────────────────────────
7
7
  {
8
8
  id: "001-initial-schema",
@@ -348,12 +348,20 @@ const MIGRATIONS = [
348
348
  //
349
349
  // One-shot ledger for the legacy filesystem→SQLite proposal import (#578).
350
350
  //
351
- // Before 0.9.0 the proposal queue lived as per-uuid JSON directories under
352
- // `<stashDir>/.akm/proposals/` and the `proposals` table (created in 001) was
353
- // dead weight. 0.9.0 makes the table canonical; the first proposal operation
354
- // against a stash imports any legacy `proposal.json` files it finds (INSERT
355
- // OR IGNORE, so re-runs never duplicate) and records the stash here so later
356
- // invocations skip the directory walk entirely.
351
+ // VESTIGIAL as of the Chunk-8 fold: the legacy `proposal.json` import moved
352
+ // OUT of the live per-operation path and INTO the one-time migrator
353
+ // (`scripts/akm-migrate/migrate/legacy/proposal-fs-import.ts`, wired through
354
+ // `akm-migrate apply`),
355
+ // whose idempotency is INSERT OR IGNORE on the proposal UUID plus migrate-apply's
356
+ // own journal — it no longer reads or writes this ledger. The CREATE TABLE
357
+ // stays because the migration registry is APPEND-ONLY and checksum-sealed:
358
+ // removing a released fragment would make the schema_migrations ledger of an
359
+ // already-migrated rc database stop being an exact ordered prefix, and the
360
+ // runner would refuse to open it. The empty table is harmless.
361
+ //
362
+ // Original purpose (pre-fold): the first proposal operation against a stash
363
+ // imported any legacy `proposal.json` files (INSERT OR IGNORE) and recorded
364
+ // the stash here so later invocations skipped the directory walk.
357
365
  //
358
366
  // Indexed (query) columns:
359
367
  // stash_dir TEXT PK — absolute stash root the import ran against.
@@ -703,7 +711,7 @@ const MIGRATIONS = [
703
711
  // ── Migration 016 — collapse/churn detector (R5) ─────────────────────────────
704
712
  //
705
713
  // Longitudinal store-health history for the improve pipeline
706
- // (docs/design/improve-collapse-churn-detector-design.md).
714
+ // (docs/architecture/specs/improve-collapse-churn-detector-design.md).
707
715
  //
708
716
  // canary_queries — the fixed canary set, minted deterministically from the
709
717
  // live stash on first detector run and NEVER auto-refreshed (silent
@@ -712,7 +720,7 @@ const MIGRATIONS = [
712
720
  // rows stay interpretable. Tens of rows; never purged.
713
721
  //
714
722
  // improve_cycle_metrics — one row per qualifying improve cycle (a run where
715
- // consolidate processed ≥1 op or recombine evaluated ≥1 cluster). Every
723
+ // consolidate processed ≥1 op). Every
716
724
  // column is a scalar or a size-capped JSON blob (< 2 KB/row by
717
725
  // construction — the result_json lesson applied). Retention: 365 days via
718
726
  // purgeOldCycleMetrics. Trend queries drive the collapse/churn alert
@@ -756,6 +764,226 @@ const MIGRATIONS = [
756
764
  ON improve_cycle_metrics(ts);
757
765
  `,
758
766
  },
767
+ // Keep the historical profile column untouched. New 0.9 runs identify the
768
+ // selected improve strategy in this additive column.
769
+ {
770
+ id: "017-improve-run-strategy",
771
+ up: `
772
+ ALTER TABLE improve_runs ADD COLUMN strategy TEXT;
773
+ CREATE INDEX IF NOT EXISTS idx_improve_runs_strategy_started ON improve_runs(strategy, started_at);
774
+ `,
775
+ },
776
+ // ── Migration 018 — drop dead-lane schema (Chunk 7, WI-7.3) ──────────────────
777
+ //
778
+ // Drops the on-disk schema for three lanes deleted by the 0.9.0 bundle-adapter
779
+ // refactor. Append-only: migrations 007/010/014 above are left verbatim; this
780
+ // migration only removes what they created.
781
+ //
782
+ // - recombine_hypotheses (+ its last-seen index) — the whole-corpus
783
+ // cross-episodic synthesis pass (migration 014) was deleted in Chunk 7
784
+ // WI-7.1 (R28).
785
+ // - consolidation_judged — the judged-state cache (#581, migration 007) was
786
+ // deleted in Chunk 7 WI-7.3 (plan §5). This is a LIVE behavior change:
787
+ // every consolidate run now re-judges unchanged memories (more LLM calls)
788
+ // instead of skipping them — see the chunk-7 ledger.
789
+ // - asset_outcome.review_pressure (+ its DESC index) — the review-pressure
790
+ // lane (#613, migration 010) was deleted in Chunk 7 WI-7.2 (R21); this
791
+ // migration finishes the column/index drop the code-side deletion left
792
+ // pending. `retrieval_count`/`outcome_score` and their index are untouched.
793
+ {
794
+ id: "018-drop-dead-lane-schema",
795
+ up: `
796
+ DROP INDEX IF EXISTS idx_recombine_hypotheses_last_seen;
797
+ DROP TABLE IF EXISTS recombine_hypotheses;
798
+
799
+ DROP TABLE IF EXISTS consolidation_judged;
800
+
801
+ DROP INDEX IF EXISTS idx_asset_outcome_review_pressure;
802
+ ALTER TABLE asset_outcome DROP COLUMN review_pressure;
803
+ `,
804
+ },
805
+ // ── Migration 019 — proposal input fingerprints (Chunk 6, WI-6.4) ────────────
806
+ //
807
+ // Durable store for the §23.6 input fingerprints that replace the
808
+ // dedup/cooldown content-hash machinery (plan §4.5): one row per processed
809
+ // fingerprint (scheme version + source + target ref + target before-hash +
810
+ // reserved evidence/guidance/evaluator terms + engine/model-id term). A
811
+ // matching fingerprint skips re-processing the same inputs unless
812
+ // explicitly forced; rows are pruned with the proposal retention window.
813
+ // Rejection backoff (the retained cooldown) keeps reading the proposals
814
+ // table itself and needs no schema.
815
+ {
816
+ id: "019-proposal-fingerprints",
817
+ up: `
818
+ CREATE TABLE IF NOT EXISTS proposal_fingerprints (
819
+ stash_dir TEXT NOT NULL,
820
+ fingerprint TEXT NOT NULL,
821
+ ref TEXT NOT NULL,
822
+ source TEXT NOT NULL,
823
+ model_id TEXT NOT NULL DEFAULT '',
824
+ proposal_id TEXT,
825
+ created_at TEXT NOT NULL,
826
+ PRIMARY KEY (stash_dir, fingerprint)
827
+ );
828
+ CREATE INDEX IF NOT EXISTS idx_proposal_fingerprints_ref
829
+ ON proposal_fingerprints(stash_dir, ref);
830
+ `,
831
+ },
832
+ // ── Migration 020 — three-DB cutover baseline DDL (Chunk 8, WI-8.2) ───────────
833
+ //
834
+ // The state.db half of the three-DB merge (plan §3.2/§8, normative §11.4,
835
+ // chunk-8 cutover design §1). This migration is PURE,
836
+ // SEALABLE, IDEMPOTENT DDL ONLY — `CREATE TABLE IF NOT EXISTS` (+ indexes),
837
+ // never a DROP or a data move. The actual data movement (the workflow.db merge,
838
+ // the usage_events rescue from index.db, the full old-ref→item_ref re-key, and
839
+ // the workflow.db delete / index.db quarantine) is CODE — a journaled step of
840
+ // the migrate-apply flow (`scripts/akm-migrate/config-migrate.ts`
841
+ // `cutover-applied` phase), driven by
842
+ // `scripts/akm-migrate/migrate/legacy/three-db-cutover.ts`. See the no-DROP
843
+ // contract carve-out note in `src/core/state-db.ts`.
844
+ //
845
+ // The three workflow tables are the 10 pre-cutover workflow migrations
846
+ // (the frozen `scripts/akm-migrate/migrate/legacy/workflow-migrations-bodies.ts`
847
+ // base schema + 001–010) folded into one baseline at their FINAL post-010 shape — column
848
+ // lists, CHECK constraints, and indexes copied verbatim. `usage_events` mirrors
849
+ // index.db's former `ensureUsageEventsSchema` (`src/indexer/usage/usage-events.ts`),
850
+ // its new durable home. `legacy_state` mirrors `ensureLegacyStateTable`
851
+ // (`src/storage/repositories/index-entries-repository.ts`), the orphan
852
+ // quarantine archive re-homed from index.db (durable, auditable, purgeable).
853
+ // Nothing else — NO bindings/lifecycle tables (Tier B / deferred, §3.2).
854
+ {
855
+ id: "020-three-db-cutover",
856
+ up: `
857
+ -- ── workflow_runs (workflows/db.ts base + migrations 001/002/003/006/010) ──
858
+ CREATE TABLE IF NOT EXISTS workflow_runs (
859
+ id TEXT PRIMARY KEY,
860
+ workflow_ref TEXT NOT NULL,
861
+ workflow_entry_id INTEGER,
862
+ workflow_title TEXT NOT NULL,
863
+ status TEXT NOT NULL CHECK (status IN ('active', 'completed', 'blocked', 'failed')),
864
+ params_json TEXT NOT NULL DEFAULT '{}',
865
+ current_step_id TEXT,
866
+ created_at TEXT NOT NULL,
867
+ updated_at TEXT NOT NULL,
868
+ completed_at TEXT,
869
+ scope_key TEXT,
870
+ agent_harness TEXT,
871
+ agent_session_id TEXT,
872
+ checkin_armed_at TEXT,
873
+ plan_json TEXT,
874
+ plan_hash TEXT,
875
+ engine_lease_until TEXT,
876
+ engine_lease_holder TEXT,
877
+ plan_ir_version INTEGER
878
+ );
879
+ CREATE INDEX IF NOT EXISTS idx_workflow_runs_ref ON workflow_runs(workflow_ref);
880
+ CREATE INDEX IF NOT EXISTS idx_workflow_runs_status ON workflow_runs(status);
881
+ CREATE INDEX IF NOT EXISTS idx_workflow_runs_scope_ref_status
882
+ ON workflow_runs(scope_key, workflow_ref, status);
883
+ CREATE INDEX IF NOT EXISTS idx_workflow_runs_agent_session
884
+ ON workflow_runs(agent_harness, agent_session_id);
885
+
886
+ -- ── workflow_run_steps (base + migration 003 summary) ─────────────────────
887
+ CREATE TABLE IF NOT EXISTS workflow_run_steps (
888
+ run_id TEXT NOT NULL,
889
+ step_id TEXT NOT NULL,
890
+ step_title TEXT NOT NULL,
891
+ instructions TEXT NOT NULL,
892
+ completion_json TEXT,
893
+ sequence_index INTEGER NOT NULL,
894
+ status TEXT NOT NULL CHECK (status IN ('pending', 'completed', 'blocked', 'failed', 'skipped')),
895
+ notes TEXT,
896
+ evidence_json TEXT,
897
+ completed_at TEXT,
898
+ summary TEXT,
899
+ PRIMARY KEY (run_id, step_id),
900
+ FOREIGN KEY (run_id) REFERENCES workflow_runs(id) ON DELETE CASCADE
901
+ );
902
+ CREATE INDEX IF NOT EXISTS idx_workflow_run_steps_run_sequence
903
+ ON workflow_run_steps(run_id, sequence_index);
904
+
905
+ -- ── workflow_run_units (migration 004 + 005/007/008/009/010 columns) ──────
906
+ CREATE TABLE IF NOT EXISTS workflow_run_units (
907
+ run_id TEXT NOT NULL,
908
+ unit_id TEXT NOT NULL,
909
+ step_id TEXT,
910
+ node_id TEXT NOT NULL,
911
+ parent_unit_id TEXT,
912
+ phase TEXT,
913
+ runner TEXT,
914
+ model TEXT,
915
+ status TEXT NOT NULL CHECK (status IN ('pending', 'running', 'completed', 'failed', 'skipped')),
916
+ input_hash TEXT,
917
+ result_json TEXT,
918
+ tokens INTEGER,
919
+ failure_reason TEXT,
920
+ worktree_path TEXT,
921
+ started_at TEXT,
922
+ finished_at TEXT,
923
+ session_id TEXT,
924
+ last_checkin_at TEXT,
925
+ attempts INTEGER NOT NULL DEFAULT 1,
926
+ claim_holder TEXT,
927
+ claim_expires_at TEXT,
928
+ engine TEXT,
929
+ PRIMARY KEY (run_id, unit_id),
930
+ FOREIGN KEY (run_id) REFERENCES workflow_runs(id) ON DELETE CASCADE
931
+ );
932
+ CREATE INDEX IF NOT EXISTS idx_workflow_run_units_run_step
933
+ ON workflow_run_units(run_id, step_id);
934
+
935
+ -- ── usage_events (index.db ensureUsageEventsSchema — the durable new home) ─
936
+ CREATE TABLE IF NOT EXISTS usage_events (
937
+ id INTEGER PRIMARY KEY AUTOINCREMENT,
938
+ event_type TEXT NOT NULL,
939
+ query TEXT,
940
+ entry_id INTEGER,
941
+ entry_ref TEXT,
942
+ signal TEXT,
943
+ metadata TEXT,
944
+ source TEXT NOT NULL DEFAULT 'user',
945
+ created_at TEXT NOT NULL DEFAULT (datetime('now'))
946
+ );
947
+ CREATE INDEX IF NOT EXISTS idx_usage_events_entry ON usage_events(entry_id);
948
+ CREATE INDEX IF NOT EXISTS idx_usage_events_type ON usage_events(event_type);
949
+ CREATE INDEX IF NOT EXISTS idx_usage_events_ref ON usage_events(entry_ref);
950
+ CREATE INDEX IF NOT EXISTS idx_usage_events_source ON usage_events(source);
951
+
952
+ -- ── legacy_state (ensureLegacyStateTable — the orphan quarantine archive) ──
953
+ CREATE TABLE IF NOT EXISTS legacy_state (
954
+ surface TEXT NOT NULL,
955
+ old_ref TEXT NOT NULL,
956
+ row_count INTEGER NOT NULL DEFAULT 0,
957
+ reason TEXT NOT NULL,
958
+ quarantined_at TEXT NOT NULL DEFAULT (datetime('now')),
959
+ PRIMARY KEY (surface, old_ref)
960
+ );
961
+ `,
962
+ },
963
+ // ── Migration 021 — asset_salience / asset_outcome: missing_since (#733) ────
964
+ //
965
+ // Orphan-GC grace clock (Workstream C / #733,
966
+ // docs/architecture/specs/0.9.0-close-out-plan.md). Neither table carries a
967
+ // column that records when a row's ref STOPPED resolving against
968
+ // `entries.item_ref` — `updated_at` is bumped by improve itself on every
969
+ // touch, so it cannot double as a "went missing" timestamp.
970
+ //
971
+ // `missing_since` is stamped by `runOrphanStateGcPass`
972
+ // (src/commands/improve/loop-stages.ts) the first time a row's ref fails to
973
+ // resolve against the live index, cleared the moment the ref resolves
974
+ // again, and used to gate deletion once `STATE_GC_GRACE_MS` (7 days) has
975
+ // elapsed — and ONLY when `improve.stateGc.collect` is true (default
976
+ // false). Mirrors the additive ADD-COLUMN style of migration 011.
977
+ //
978
+ // NULL = never missing (the steady-state default for every existing row —
979
+ // both a fresh row and a pre-migration row read back NULL here).
980
+ {
981
+ id: "021-asset-state-missing-since",
982
+ up: `
983
+ ALTER TABLE asset_salience ADD COLUMN missing_since INTEGER DEFAULT NULL;
984
+ ALTER TABLE asset_outcome ADD COLUMN missing_since INTEGER DEFAULT NULL;
985
+ `,
986
+ },
759
987
  ];
760
988
  /**
761
989
  * Apply every pending migration in a single transaction per migration.
@@ -765,6 +993,9 @@ const MIGRATIONS = [
765
993
  *
766
994
  * Called automatically by `openStateDatabase()`.
767
995
  */
768
- export function runMigrations(db) {
769
- runSqliteMigrations(db, MIGRATIONS);
996
+ export function runMigrations(db, options) {
997
+ runSqliteMigrations(db, STATE_MIGRATIONS, {
998
+ applyPending: options?.applyPending,
999
+ generationMarker: options?.generationMarker,
1000
+ });
770
1001
  }
@@ -8,8 +8,8 @@
8
8
  * the managed-db open/loan wrappers, the `BEGIN IMMEDIATE` transaction helper,
9
9
  * and schema introspection. The table-specific query helpers live by domain in
10
10
  * `src/storage/repositories/*-repository.ts` (events, proposals, task-history,
11
- * improve-runs, extract-sessions, consolidation, recombine, embeddings,
12
- * canaries); importers reference those modules directly. The migration engine
11
+ * improve-runs, extract-sessions, consolidation, embeddings, canaries);
12
+ * importers reference those modules directly. The migration engine
13
13
  * lives in `./state/migrations`.
14
14
  *
15
15
  * The state DB replaces flat-file storage for data that is NON-REGENERABLE —
@@ -37,6 +37,21 @@
37
37
  * - CREATE INDEX IF NOT EXISTS …
38
38
  * - CREATE TABLE IF NOT EXISTS … (additive new tables)
39
39
  *
40
+ * ## Three-DB cutover carve-out (Chunk 8, migration `020-three-db-cutover`)
41
+ *
42
+ * The 0.9.0 three-DB merge folds workflow.db and index.db's durable rows
43
+ * (`usage_events`, `legacy_state`) into state.db. That migration is still pure
44
+ * additive DDL and DROPS NOTHING — it only `CREATE TABLE IF NOT EXISTS`es the
45
+ * merge-target tables at their final shape. The one-time, filesystem-derived,
46
+ * fail-closed DATA movement (the workflow.db merge, the usage_events rescue, the
47
+ * full old-ref→item_ref re-key, and the workflow.db unlink / index.db quarantine
48
+ * rename) is deliberately NOT a sealed SQL migration body: it is a journaled step
49
+ * of the migrate-apply coordinator (`scripts/akm-migrate/config-migrate.ts`
50
+ * `cutover-applied` phase →
51
+ * `scripts/akm-migrate/migrate/legacy/three-db-cutover.ts`). So the no-DROP
52
+ * contract here is intact — the physical workflow.db deletion happens outside
53
+ * the ledger DDL, under the backup-verified-restorable fail-closed gate.
54
+ *
40
55
  * ## Schema design: indexed columns vs. metadata_json
41
56
  *
42
57
  * Each table holds only the columns needed for indexed queries as first-class
@@ -55,9 +70,15 @@
55
70
  *
56
71
  * @module state-db
57
72
  */
73
+ import fs from "node:fs";
58
74
  import path from "node:path";
59
- import { openManagedDatabase, withManagedDb, withManagedDbAsync } from "../storage/managed-db.js";
75
+ import { openDatabase } from "../storage/database.js";
76
+ import { assertCurrentMigrationLedger, assertMigrationLedger } from "../storage/engines/sqlite-migrations.js";
77
+ import { openManagedDatabase, withManagedDb } from "../storage/managed-db.js";
78
+ import { acquireMaintenanceActivitySync } from "./maintenance-barrier.js";
79
+ import { assertNoPendingMigrationOperation } from "./migration-operation.js";
60
80
  import { getDataDir } from "./paths.js";
81
+ import { runMigrations, STATE_MIGRATIONS } from "./state/migrations.js";
61
82
  // ── Path helper ──────────────────────────────────────────────────────────────
62
83
  /**
63
84
  * Default path: `<dataDir>/state.db`.
@@ -96,7 +117,61 @@ export function getStateDbPath() {
96
117
  * narrow when a post-inference reindex overlapped a parallel event write.
97
118
  */
98
119
  export function openStateDatabase(dbPath) {
99
- return openManagedDatabase({ path: dbPath ?? getStateDbPath(), init: runMigrations });
120
+ const canonicalPath = getStateDbPath();
121
+ const resolvedPath = dbPath ?? canonicalPath;
122
+ const isCanonical = path.resolve(resolvedPath) === path.resolve(canonicalPath);
123
+ if (isCanonical)
124
+ assertNoPendingMigrationOperation();
125
+ const releaseActivity = isCanonical ? acquireMaintenanceActivitySync("state-db") : undefined;
126
+ try {
127
+ if (isCanonical)
128
+ assertNoPendingMigrationOperation();
129
+ const existed = fs.existsSync(resolvedPath);
130
+ if (existed) {
131
+ const preflight = openDatabase(resolvedPath, { readonly: true });
132
+ try {
133
+ preflight.exec("PRAGMA busy_timeout = 30000");
134
+ if (isCanonical)
135
+ assertCurrentMigrationLedger(preflight, STATE_MIGRATIONS);
136
+ else
137
+ assertMigrationLedger(preflight, STATE_MIGRATIONS);
138
+ }
139
+ finally {
140
+ preflight.close();
141
+ }
142
+ }
143
+ const db = openManagedDatabase({
144
+ path: resolvedPath,
145
+ init: (db) => runMigrations(db, { applyPending: !(isCanonical && existed) }),
146
+ });
147
+ if (!releaseActivity)
148
+ return db;
149
+ let closed = false;
150
+ return {
151
+ prepare: db.prepare.bind(db),
152
+ exec: db.exec.bind(db),
153
+ run: db.run.bind(db),
154
+ transaction: db.transaction.bind(db),
155
+ get inTransaction() {
156
+ return db.inTransaction;
157
+ },
158
+ close() {
159
+ if (closed)
160
+ return;
161
+ closed = true;
162
+ try {
163
+ db.close();
164
+ }
165
+ finally {
166
+ releaseActivity();
167
+ }
168
+ },
169
+ };
170
+ }
171
+ catch (error) {
172
+ releaseActivity?.();
173
+ throw error;
174
+ }
100
175
  }
101
176
  /**
102
177
  * Run `fn` against state.db, owning the handle unless one is borrowed. The loan
@@ -109,19 +184,32 @@ export function withStateDb(fn, opts) {
109
184
  return withManagedDb(() => openStateDatabase(opts?.path), fn, opts);
110
185
  }
111
186
  /**
112
- * Async sibling of {@link withStateDb} — for `fn`s that hold the handle across
113
- * an `await` (the sync version would close it too early). Same borrow/own +
114
- * optional `path` override semantics.
187
+ * Fire-and-forget telemetry write to state.db (Chunk-8 WI-8.3: usage_events'
188
+ * durable home). Skips entirely when state.db does not exist yet (never
189
+ * fabricates an un-migrated DB); otherwise opens the migrated DB and lowers
190
+ * `busy_timeout` to a short window so a contended state.db (e.g. a reindex
191
+ * finalize holding the write lock while relinking usage_events) never stalls a
192
+ * hot path — mirrors `withIndexDb`'s `TELEMETRY_BUSY_TIMEOUT_MS`. WAL mode lets
193
+ * the read-only migration-preflight run concurrently with a writer, so the open
194
+ * itself does not block. Callers wrap this in their own try/catch.
115
195
  */
116
- export function withStateDbAsync(fn, opts) {
117
- return withManagedDbAsync(() => openStateDatabase(opts?.path), fn, opts);
196
+ export function withStateDbTelemetry(fn, busyTimeoutMs = 250) {
197
+ if (!fs.existsSync(getStateDbPath()))
198
+ return;
199
+ const db = openStateDatabase();
200
+ try {
201
+ db.exec(`PRAGMA busy_timeout = ${Math.max(0, Math.floor(busyTimeoutMs))}`);
202
+ fn(db);
203
+ }
204
+ finally {
205
+ db.close();
206
+ }
118
207
  }
119
208
  // ── Migration engine ─────────────────────────────────────────────────────────
120
209
  //
121
210
  // The MIGRATIONS registry + runMigrations live in ./state/migrations (the single
122
211
  // append-only ordered source of truth). Imported for internal use by
123
212
  // openStateDatabase.
124
- import { runMigrations } from "./state/migrations.js";
125
213
  // ── BEGIN IMMEDIATE transaction helper ───────────────────────────────────────
126
214
  /**
127
215
  * Run `fn` inside a `BEGIN IMMEDIATE` transaction.
@@ -15,7 +15,7 @@
15
15
  *
16
16
  * Layering: this file lives in `core/` — NOT `llm/` — because the agent path
17
17
  * must be able to reach it and `agent/ ⇏ llm/` is an enforced invariant
18
- * (`tests/architecture/agent-no-llm-sdk-guard.test.ts`). The transport is
18
+ * (`tests/integration/architecture/agent-no-llm-sdk-guard.test.ts`). The transport is
19
19
  * always injected; this module never performs IO of its own.
20
20
  *
21
21
  * Retry semantics: only parse/validation misses are retried (with corrective