akm-cli 0.9.16 → 0.9.17-alpha.10

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 (403) hide show
  1. package/CHANGELOG.md +2101 -0
  2. package/STABILITY.md +11 -10
  3. package/dist/akm +124 -193
  4. package/dist/akm-migrate +38 -19
  5. package/dist/assets/hints/cli-hints-full.md +6 -7
  6. package/dist/assets/improve-strategies/catchup.json +0 -3
  7. package/dist/assets/improve-strategies/consolidate.json +0 -1
  8. package/dist/assets/improve-strategies/default.json +1 -2
  9. package/dist/assets/improve-strategies/proactive-maintenance.json +1 -2
  10. package/dist/assets/improve-strategies/quick.json +1 -2
  11. package/dist/assets/improve-strategies/reflect-distill.json +1 -2
  12. package/dist/assets/improve-strategies/thorough.json +0 -3
  13. package/dist/assets/prompts/consolidate-pair.md +20 -0
  14. package/dist/assets/prompts/consolidate-system.md +4 -11
  15. package/dist/assets/prompts/retrieval-relevance-judge.md +6 -0
  16. package/dist/assets/stash-skeleton/facts/conventions/backlinks.md +20 -20
  17. package/dist/assets/stash-skeleton/facts/conventions/domains.md +2 -2
  18. package/dist/assets/templates/html/health.html +3 -5
  19. package/dist/cli/retired-commands.js +1 -1
  20. package/dist/cli/shared.js +6 -2
  21. package/dist/cli/unknown-flags.js +24 -1
  22. package/dist/cli.js +68 -10
  23. package/dist/commands/agent/agent-dispatch.js +1 -1
  24. package/dist/commands/command/command-execution.js +24 -62
  25. package/dist/commands/feedback-cli.js +0 -1
  26. package/dist/commands/health/accept-rate.js +6 -0
  27. package/dist/commands/health/archive-usage.js +92 -0
  28. package/dist/commands/health/checks.js +83 -74
  29. package/dist/commands/health/config-skew.js +38 -0
  30. package/dist/commands/health/data-dir-usage.js +25 -13
  31. package/dist/commands/health/egress.js +54 -0
  32. package/dist/commands/health/html-report.js +1 -42
  33. package/dist/commands/health/improve-metrics.js +136 -591
  34. package/dist/commands/health/md-report.js +1 -6
  35. package/dist/commands/health/plugin-staleness.js +53 -3
  36. package/dist/commands/health/renderers.js +12 -4
  37. package/dist/commands/health/report-view-model.js +14 -120
  38. package/dist/commands/health/types-improve.js +4 -19
  39. package/dist/commands/health/windows.js +64 -74
  40. package/dist/commands/health.js +145 -143
  41. package/dist/commands/improve/consolidate/chunking.js +26 -117
  42. package/dist/commands/improve/consolidate/continuity-check.js +137 -0
  43. package/dist/commands/improve/consolidate/pair-pass.js +791 -0
  44. package/dist/commands/improve/consolidate/sanitize.js +54 -149
  45. package/dist/commands/improve/consolidate.js +589 -1127
  46. package/dist/commands/improve/content-hash.js +16 -24
  47. package/dist/commands/improve/distill/content-repair.js +18 -100
  48. package/dist/commands/improve/distill-guards.js +20 -81
  49. package/dist/commands/improve/distill-promotion-policy.js +23 -243
  50. package/dist/commands/improve/distill.js +608 -1041
  51. package/dist/commands/improve/eligibility.js +126 -390
  52. package/dist/commands/improve/execution.js +8 -10
  53. package/dist/commands/improve/extract-prompt.js +1 -2
  54. package/dist/commands/improve/extract.js +487 -1046
  55. package/dist/commands/improve/feedback-valence.js +0 -25
  56. package/dist/commands/improve/improve-cli.js +75 -169
  57. package/dist/commands/improve/improve-result-file.js +10 -66
  58. package/dist/commands/improve/improve-strategies.js +52 -4
  59. package/dist/commands/improve/improve-usage-report.js +18 -64
  60. package/dist/commands/improve/improve.js +480 -1074
  61. package/dist/commands/improve/ledger.js +119 -0
  62. package/dist/commands/improve/locks.js +2 -8
  63. package/dist/commands/improve/loop-stages.js +415 -1073
  64. package/dist/commands/improve/memory/derived-ref.js +12 -77
  65. package/dist/commands/improve/memory/memory-belief.js +16 -118
  66. package/dist/commands/improve/memory/memory-improve.js +266 -14
  67. package/dist/commands/improve/outcome-loop.js +28 -156
  68. package/dist/commands/improve/planner.js +5 -15
  69. package/dist/commands/improve/preparation.js +779 -2319
  70. package/dist/commands/improve/proactive-maintenance.js +34 -101
  71. package/dist/commands/improve/reflect-noise.js +104 -280
  72. package/dist/commands/improve/reflect.js +642 -1353
  73. package/dist/commands/improve/retrieval-gate.js +127 -0
  74. package/dist/commands/improve/retrieval-scope.js +92 -0
  75. package/dist/commands/improve/salience.js +41 -240
  76. package/dist/commands/improve/session-asset.js +19 -100
  77. package/dist/commands/improve/stage.js +322 -0
  78. package/dist/commands/lint/base-linter.js +37 -15
  79. package/dist/commands/proposal/drain.js +261 -578
  80. package/dist/commands/proposal/proposal-cli.js +19 -20
  81. package/dist/commands/proposal/proposal-types.js +31 -24
  82. package/dist/commands/proposal/proposal.js +38 -8
  83. package/dist/commands/proposal/propose.js +134 -160
  84. package/dist/commands/proposal/repository.js +1097 -1394
  85. package/dist/commands/proposal/validators/proposal-quality-validators.js +71 -174
  86. package/dist/commands/proposal/validators/proposal-validators.js +1 -1
  87. package/dist/commands/proposal/validators/proposals.js +22 -89
  88. package/dist/commands/read/curate.js +105 -462
  89. package/dist/commands/read/knowledge.js +3 -2
  90. package/dist/commands/read/search-cli.js +16 -33
  91. package/dist/commands/read/search.js +17 -23
  92. package/dist/commands/read/show.js +57 -108
  93. package/dist/commands/sources/bundle-cli.js +25 -2
  94. package/dist/commands/sources/bundle-config-ops.js +4 -0
  95. package/dist/commands/sources/dangerous-env-audit.js +1 -2
  96. package/dist/commands/sources/info.js +127 -29
  97. package/dist/commands/sources/installed-stashes.js +197 -746
  98. package/dist/commands/sources/schema-repair.js +98 -129
  99. package/dist/commands/sources/source-add.js +62 -12
  100. package/dist/commands/sources/source-manage.js +9 -2
  101. package/dist/commands/sources/stash-cli.js +24 -4
  102. package/dist/commands/tasks/explain.js +10 -13
  103. package/dist/commands/tasks/tasks-cli.js +12 -13
  104. package/dist/commands/tasks/tasks.js +350 -936
  105. package/dist/commands/tasks/validate.js +26 -24
  106. package/dist/commands/workflow/plan.js +22 -29
  107. package/dist/commands/workflow-cli.js +4 -4
  108. package/dist/core/adapter/adapters/akm-adapter.js +2 -1
  109. package/dist/core/adapter/adapters/akm-lint.js +2 -3
  110. package/dist/core/adapter/adapters/akm-metadata.js +42 -12
  111. package/dist/core/adapter/adapters/akm-task-adapter.js +29 -8
  112. package/dist/core/adapter/adapters/akm-workflow-adapter.js +1 -1
  113. package/dist/core/adapter/execution-source.js +17 -29
  114. package/dist/core/asset/asset-placement.js +4 -13
  115. package/dist/core/asset/frontmatter.js +106 -1
  116. package/dist/core/asset/resolve-ref.js +1 -1
  117. package/dist/core/bundle-id.js +42 -5
  118. package/dist/core/bundle-rename.js +285 -0
  119. package/dist/core/config/config-io.js +1 -2
  120. package/dist/core/config/config-schema.js +9 -34
  121. package/dist/core/config/config-walker.js +1 -1
  122. package/dist/core/config/config.js +184 -111
  123. package/dist/core/config/engine-semantics.js +0 -2
  124. package/dist/core/config/legacy-source-shape-shim.js +38 -9
  125. package/dist/core/config/schema/embedding.js +20 -5
  126. package/dist/core/config/schema/engines.js +5 -0
  127. package/dist/core/config/schema/execution.js +1 -1
  128. package/dist/core/config/schema/experimental.js +1 -1
  129. package/dist/core/config/schema/improve-processes.js +54 -125
  130. package/dist/core/config/schema/improve.js +4 -42
  131. package/dist/core/config/schema/index-config.js +9 -48
  132. package/dist/core/config/schema/scheduler.js +12 -12
  133. package/dist/core/config/schema/search.js +6 -22
  134. package/dist/core/env-secret-ref.js +0 -1
  135. package/dist/core/errors.js +8 -9
  136. package/dist/core/file-change.js +13 -5
  137. package/dist/core/file-lock.js +76 -173
  138. package/dist/core/improve-result.js +35 -7
  139. package/dist/core/improve-types.js +0 -1
  140. package/dist/core/logs-db.js +2 -2
  141. package/dist/core/loopback.js +7 -12
  142. package/dist/core/non-task-input.js +20 -0
  143. package/dist/core/parse.js +13 -16
  144. package/dist/core/paths.js +0 -24
  145. package/dist/core/redaction.js +109 -2
  146. package/dist/core/run-lock.js +2 -5
  147. package/dist/core/spawn-env.js +1 -1
  148. package/dist/core/state/migrations.js +123 -61
  149. package/dist/core/state-db-scope.js +2 -4
  150. package/dist/core/state-db.js +126 -692
  151. package/dist/core/time.js +0 -20
  152. package/dist/core/type-presentation.js +1 -9
  153. package/dist/core/write-source.js +294 -1005
  154. package/dist/execution/input-contract.js +1 -1
  155. package/dist/execution/resolved-request.js +135 -689
  156. package/dist/execution/source.js +63 -257
  157. package/dist/execution/target-ref.js +1 -1
  158. package/dist/indexer/bundle-identity-guard.js +2 -2
  159. package/dist/indexer/db/llm-cache.js +2 -2
  160. package/dist/indexer/ensure-index.js +77 -73
  161. package/dist/indexer/index-rebuild-lock.js +3 -11
  162. package/dist/indexer/index-writer-lock.js +8 -17
  163. package/dist/indexer/index-written-assets.js +141 -154
  164. package/dist/indexer/indexer.js +400 -1124
  165. package/dist/indexer/links/declared-links.js +90 -0
  166. package/dist/indexer/materialize-embeddings.js +60 -397
  167. package/dist/indexer/passes/memory-inference.js +96 -90
  168. package/dist/indexer/passes/metadata.js +132 -219
  169. package/dist/indexer/read-preflight.js +0 -7
  170. package/dist/indexer/scan/doc-to-entry.js +2 -3
  171. package/dist/indexer/scan/drain-dir.js +1 -1
  172. package/dist/indexer/search/db-search.js +190 -590
  173. package/dist/indexer/search/fts-query.js +30 -41
  174. package/dist/indexer/search/ranking.js +28 -154
  175. package/dist/indexer/search/search-attribution.js +12 -32
  176. package/dist/indexer/search/search-fields.js +11 -15
  177. package/dist/indexer/search/search-hit-enrichers.js +54 -85
  178. package/dist/indexer/search/search-source.js +1 -4
  179. package/dist/indexer/usage/usage-events.js +36 -7
  180. package/dist/indexer/walk/walker.js +3 -4
  181. package/dist/integrations/agent/engine-fallback.js +23 -40
  182. package/dist/integrations/agent/engine-resolution.js +93 -183
  183. package/dist/integrations/agent/execution.js +507 -0
  184. package/dist/integrations/agent/model-map.js +28 -156
  185. package/dist/integrations/agent/request-lowering.js +66 -141
  186. package/dist/integrations/agent/runner-dispatch.js +143 -321
  187. package/dist/integrations/agent/runner.js +54 -14
  188. package/dist/integrations/lockfile.js +53 -101
  189. package/dist/llm/client.js +18 -6
  190. package/dist/llm/embedders/deterministic.js +2 -3
  191. package/dist/llm/embedders/profile.js +71 -0
  192. package/dist/llm/embedders/remote.js +11 -17
  193. package/dist/llm/feature-gate.js +0 -8
  194. package/dist/llm/index-passes.js +3 -5
  195. package/dist/llm/memory-infer.js +1 -2
  196. package/dist/llm/structured-call.js +5 -24
  197. package/dist/output/generic-render.js +23 -11
  198. package/dist/output/html-render.js +13 -10
  199. package/dist/output/render-registry.js +3 -32
  200. package/dist/output/shapes/helpers.js +25 -38
  201. package/dist/output/shapes/passthrough.js +1 -9
  202. package/dist/{indexer/graph/graph-types.js → output/text/bundle-rename.js} +4 -1
  203. package/dist/output/text/command-format.js +69 -31
  204. package/dist/output/text/helpers.js +1 -1
  205. package/dist/output/text/migrate.js +5 -14
  206. package/dist/output/text/proposal-format.js +48 -3
  207. package/dist/output/text/show-format.js +13 -17
  208. package/dist/output/text/workflow-format.js +0 -32
  209. package/dist/output/text.js +2 -0
  210. package/dist/registry/factory.js +4 -19
  211. package/dist/registry/network.js +66 -220
  212. package/dist/registry/providers/index.js +0 -2
  213. package/dist/registry/providers/skills-sh.js +3 -14
  214. package/dist/registry/providers/static-index.js +24 -26
  215. package/dist/registry/resolve.js +55 -131
  216. package/dist/scripts/akm-migrate-node.js +42948 -92369
  217. package/dist/scripts/akm-migrate.js +42935 -92354
  218. package/dist/setup/registry-stash-loader.js +4 -13
  219. package/dist/setup/semantic-assets.js +3 -44
  220. package/dist/setup/setup.js +1 -1
  221. package/dist/setup/steps/connection.js +5 -6
  222. package/dist/setup/steps/platforms.js +2 -2
  223. package/dist/setup/steps/tasks.js +25 -15
  224. package/dist/sources/provider-factory.js +17 -18
  225. package/dist/sources/providers/filesystem.js +2 -3
  226. package/dist/sources/providers/git-install.js +7 -1
  227. package/dist/sources/providers/git-provider.js +0 -3
  228. package/dist/sources/providers/git-stash.js +83 -21
  229. package/dist/sources/providers/npm.js +2 -4
  230. package/dist/sources/providers/provider-utils.js +5 -10
  231. package/dist/sources/providers/website.js +0 -2
  232. package/dist/sources/snapshot-fetchers/website-ingest.js +1 -1
  233. package/dist/sources/website-url.js +2 -2
  234. package/dist/storage/database.js +9 -35
  235. package/dist/storage/repositories/improve-ledger-repository.js +209 -0
  236. package/dist/storage/repositories/index-connection.js +39 -72
  237. package/dist/storage/repositories/index-entries-repository.js +131 -129
  238. package/dist/storage/repositories/index-entry-mapper.js +1 -2
  239. package/dist/storage/repositories/index-entry-schema.js +101 -268
  240. package/dist/storage/repositories/index-fts-repository.js +86 -256
  241. package/dist/storage/repositories/index-links-repository.js +143 -0
  242. package/dist/storage/repositories/index-llm-cache-repository.js +7 -9
  243. package/dist/storage/repositories/index-meta-repository.js +6 -4
  244. package/dist/storage/repositories/index-schema.js +257 -325
  245. package/dist/storage/repositories/index-utility-repository.js +8 -29
  246. package/dist/storage/repositories/index-vec-repository.js +133 -414
  247. package/dist/storage/repositories/outcome-repository.js +2 -1
  248. package/dist/storage/repositories/proposals-repository.js +104 -1
  249. package/dist/storage/repositories/registry-index-cache-repository.js +100 -0
  250. package/dist/storage/repositories/salience-repository.js +1 -19
  251. package/dist/storage/repositories/task-history-repository.js +26 -4
  252. package/dist/storage/repositories/workflow-runs-repository.js +53 -244
  253. package/dist/storage/sqlite-migrations.js +136 -0
  254. package/dist/storage/sqlite-pragmas.js +11 -9
  255. package/dist/storage/sqlite-transaction.js +170 -0
  256. package/dist/storage/state-db-integrity.js +130 -0
  257. package/dist/tasks/activation-config.js +134 -62
  258. package/dist/tasks/backends/cron.js +191 -302
  259. package/dist/tasks/backends/exec-utils.js +2 -5
  260. package/dist/tasks/backends/launchd.js +141 -748
  261. package/dist/tasks/backends/schtasks.js +119 -623
  262. package/dist/tasks/prepare/prepare-support.js +5 -15
  263. package/dist/tasks/prepare/prepare.js +0 -2
  264. package/dist/tasks/resolve-akm-bin.js +20 -79
  265. package/dist/tasks/run/attempt-lifecycle.js +0 -1
  266. package/dist/tasks/run/load-task.js +1 -1
  267. package/dist/tasks/scheduler-binding.js +20 -238
  268. package/dist/tasks/scheduler-invocation.js +136 -244
  269. package/dist/tasks/scheduler-lock.js +53 -0
  270. package/dist/tasks/scheduler-sync.js +368 -679
  271. package/dist/tasks/source/parse-task-source.js +55 -9
  272. package/dist/tasks/source/task-source-v3-frozen.js +3 -4
  273. package/dist/tasks/source/task-to-v4.js +464 -88
  274. package/dist/workflows/authoring/authoring.js +3 -12
  275. package/dist/workflows/compile.js +211 -0
  276. package/dist/workflows/concurrency-policy.js +13 -74
  277. package/dist/workflows/exec/child-invocation.js +3 -17
  278. package/dist/workflows/exec/child-workflow.js +32 -141
  279. package/dist/workflows/exec/dispatch-redaction.js +13 -53
  280. package/dist/workflows/exec/environment.js +98 -0
  281. package/dist/workflows/exec/exec-unit.js +33 -140
  282. package/dist/workflows/exec/frozen-judge.js +7 -59
  283. package/dist/workflows/exec/native-executor.js +82 -341
  284. package/dist/workflows/exec/param-secrets.js +29 -47
  285. package/dist/workflows/exec/run-workflow.js +154 -387
  286. package/dist/workflows/exec/scheduler.js +9 -36
  287. package/dist/workflows/exec/step-work.js +127 -430
  288. package/dist/workflows/exec/unit-dispatch.js +11 -63
  289. package/dist/workflows/exec/unit-writer.js +8 -52
  290. package/dist/workflows/exec/worktree.js +39 -273
  291. package/dist/workflows/freeze/child-output-references.js +4 -15
  292. package/dist/workflows/freeze/environment.js +99 -92
  293. package/dist/workflows/freeze/freeze.js +172 -0
  294. package/dist/workflows/freeze/step-values.js +19 -21
  295. package/dist/workflows/freeze/targets/child-workflow.js +23 -92
  296. package/dist/workflows/freeze/targets/command.js +10 -33
  297. package/dist/workflows/freeze/targets/script.js +5 -12
  298. package/dist/workflows/freeze/targets/shell.js +3 -6
  299. package/dist/workflows/freeze/targets/task.js +25 -80
  300. package/dist/workflows/freeze/task-bindings.js +20 -67
  301. package/dist/workflows/{source-ir/github-yaml.js → github-yaml.js} +88 -206
  302. package/dist/workflows/ir/params.js +6 -51
  303. package/dist/workflows/ir/plan-hash.js +2 -34
  304. package/dist/workflows/parser.js +140 -43
  305. package/dist/{commands/improve/consolidate/types.js → workflows/plan.js} +2 -1
  306. package/dist/workflows/renderer.js +36 -69
  307. package/dist/workflows/resource-limits.js +12 -120
  308. package/dist/workflows/runtime/agent-identity.js +8 -40
  309. package/dist/workflows/runtime/run-outputs.js +3 -6
  310. package/dist/workflows/runtime/run-plan.js +316 -0
  311. package/dist/workflows/runtime/runs.js +48 -200
  312. package/dist/workflows/runtime/workflow-asset-loader.js +24 -57
  313. package/dist/workflows/{source-ir/semantics.js → source-semantics.js} +16 -20
  314. package/dist/workflows/validate-summary.js +2 -7
  315. package/docs/integration/bundling-akm.md +49 -42
  316. package/docs/migration/README.md +1 -0
  317. package/docs/migration/release-notes/0.9.17.md +43 -0
  318. package/docs/migration/v0.9.1-to-v0.9.2.md +23 -7
  319. package/docs/reference/cli.md +232 -135
  320. package/docs/reference/configuration.md +71 -57
  321. package/docs/reference/data-and-telemetry.md +20 -21
  322. package/docs/reference/tasks.md +105 -39
  323. package/docs/reference/workflow-schema.md +14 -18
  324. package/docs/reference/workflows.md +6 -9
  325. package/package.json +1 -1
  326. package/schemas/akm-config.json +115 -738
  327. package/schemas/akm-workflow.json +1 -0
  328. package/dist/assets/improve-strategies/graph-refresh.json +0 -15
  329. package/dist/assets/prompts/contradiction-judge.md +0 -33
  330. package/dist/assets/prompts/graph-extract-system.md +0 -1
  331. package/dist/assets/prompts/graph-extract-user-prompt.md +0 -35
  332. package/dist/assets/prompts/metadata-enhance-system.md +0 -1
  333. package/dist/assets/tasks/improve/akm-graph-refresh-weekly.yml +0 -4
  334. package/dist/commands/health/advisories.js +0 -150
  335. package/dist/commands/health/metrics.js +0 -329
  336. package/dist/commands/health/surfaces.js +0 -102
  337. package/dist/commands/improve/anti-collapse.js +0 -83
  338. package/dist/commands/improve/collapse-detector.js +0 -432
  339. package/dist/commands/improve/consolidate/eligibility.js +0 -48
  340. package/dist/commands/improve/consolidate/merge.js +0 -149
  341. package/dist/commands/improve/distill/promote-memory.js +0 -291
  342. package/dist/commands/improve/distill/quality-gate.js +0 -337
  343. package/dist/commands/improve/eval-cases.js +0 -52
  344. package/dist/commands/improve/memory/memory-contradiction-detect.js +0 -291
  345. package/dist/commands/improve/proposal-envelope.js +0 -31
  346. package/dist/commands/improve/run-context.js +0 -123
  347. package/dist/commands/improve/shared.js +0 -31
  348. package/dist/commands/improve/source-identity.js +0 -28
  349. package/dist/commands/improve/triage.js +0 -96
  350. package/dist/commands/proposal/drain-policies.js +0 -151
  351. package/dist/commands/sources/update-transaction.js +0 -220
  352. package/dist/core/action-contributors.js +0 -28
  353. package/dist/core/config/config-version-shim.js +0 -101
  354. package/dist/core/fs-txn.js +0 -405
  355. package/dist/core/lexical-score.js +0 -25
  356. package/dist/core/maintenance-barrier.js +0 -167
  357. package/dist/execution/executable-identity.js +0 -105
  358. package/dist/execution/guarded-source.js +0 -427
  359. package/dist/indexer/db/graph-db.js +0 -444
  360. package/dist/indexer/graph/graph-boost.js +0 -427
  361. package/dist/indexer/graph/graph-dedup.js +0 -95
  362. package/dist/indexer/graph/graph-extraction.js +0 -1108
  363. package/dist/indexer/search/name-match.js +0 -35
  364. package/dist/indexer/search/ranking-contributors.js +0 -515
  365. package/dist/indexer/search/ranking-types.js +0 -4
  366. package/dist/indexer/walk/project-context.js +0 -192
  367. package/dist/integrations/agent/execution-cascade.js +0 -566
  368. package/dist/integrations/agent/execution-definitions.js +0 -202
  369. package/dist/integrations/agent/execution-lowering.js +0 -841
  370. package/dist/integrations/agent/execution-preparation.js +0 -98
  371. package/dist/integrations/agent/inline-execution.js +0 -74
  372. package/dist/llm/graph-extract.js +0 -728
  373. package/dist/llm/metadata-enhance.js +0 -96
  374. package/dist/registry/create-provider-registry.js +0 -29
  375. package/dist/registry/pinned-request-helper.js +0 -247
  376. package/dist/registry/pinned-transport.js +0 -717
  377. package/dist/sources/providers/index.js +0 -14
  378. package/dist/storage/engines/sqlite-migrations.js +0 -271
  379. package/dist/storage/repositories/canaries-repository.js +0 -107
  380. package/dist/storage/repositories/embedding-salvage-repository.js +0 -184
  381. package/dist/storage/repositories/registry-cache.js +0 -113
  382. package/dist/tasks/scheduler-sync-preview.js +0 -52
  383. package/dist/tasks/source/task-to-v3.js +0 -507
  384. package/dist/workflows/freeze/resolve-steps.js +0 -86
  385. package/dist/workflows/freeze/source-freeze.js +0 -64
  386. package/dist/workflows/ir/compile.js +0 -321
  387. package/dist/workflows/ir/environment-v4.js +0 -330
  388. package/dist/workflows/ir/freeze-v4.js +0 -153
  389. package/dist/workflows/ir/schema-v4.js +0 -745
  390. package/dist/workflows/ir/schema.js +0 -354
  391. package/dist/workflows/program/schema.js +0 -77
  392. package/dist/workflows/runtime/checkin.js +0 -57
  393. package/dist/workflows/runtime/plan-classifier.js +0 -196
  394. package/dist/workflows/runtime/unit-checkin.js +0 -45
  395. package/dist/workflows/runtime/unit-phases.js +0 -20
  396. package/dist/workflows/schema.js +0 -4
  397. package/dist/workflows/source-ir/compile.js +0 -200
  398. package/dist/workflows/source-ir/program.js +0 -50
  399. package/dist/workflows/source-ir/result.js +0 -26
  400. package/dist/workflows/source-ir/schema.js +0 -786
  401. package/dist/workflows/source-ir/triggers.js +0 -79
  402. package/dist/workflows/source-ir/uses.js +0 -40
  403. package/dist/workflows/validator.js +0 -60
@@ -1,31 +1,6 @@
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
- /**
5
- * Symmetric valence weighting for the improve eligibility sort (#614).
6
- *
7
- * BACKGROUND. The improve attention/eligibility ranking historically combined
8
- * utility with a NEGATIVE-ONLY feedback term: `negative / (positive + negative)`.
9
- * Under that formula a strong-positive asset contributes a feedback ratio of
10
- * `0` — i.e. positive feedback never drives attention. Only complaints could
11
- * lift an asset up the ranking, so a heavily-praised, heavily-used asset that
12
- * deserves REINFORCEMENT (distill / promote the win) is treated identically to
13
- * a never-rated one.
14
- *
15
- * FIX (gated, default-off). When symmetric valence is enabled we replace the
16
- * negative-only ratio with a |valence| MAGNITUDE term so that BOTH strong
17
- * positive and strong negative feedback drive attention. Utility remains the
18
- * dominant ordering factor — valence is a secondary attention nudge with a
19
- * small fixed weight, never a utility override.
20
- *
21
- * This module is intentionally pure and storage-free: it takes pre-aggregated
22
- * positive/negative counts plus a utility lookup and returns a deterministic
23
- * score and lane. All DB access stays in the caller.
24
- */
25
- /** Weight on utility in the combined eligibility score. Utility is dominant. */
26
- export const UTILITY_WEIGHT = 0.7;
27
- /** Weight on the feedback attention term in the combined eligibility score. */
28
- export const FEEDBACK_WEIGHT = 0.3;
29
4
  /**
30
5
  * Compute the symmetric-valence attention score for one asset's feedback.
31
6
  *
@@ -14,6 +14,7 @@ import { getCacheDir } from "../../core/paths.js";
14
14
  import { redactSensitiveText } from "../../core/redaction.js";
15
15
  import { clearLogFile, setLogFile, warn } from "../../core/warn.js";
16
16
  import { resolveWriteTarget } from "../../core/write-source.js";
17
+ import { DEFAULT_LLM_TIMEOUT_MS } from "../../integrations/agent/config.js";
17
18
  import { collectEngineCredentialValues } from "../../integrations/agent/engine-resolution.js";
18
19
  import { probeLlmReachable } from "../../llm/client.js";
19
20
  import { getOutputMode } from "../../output/context.js";
@@ -31,15 +32,9 @@ export function _setAkmImproveForTests(fake) {
31
32
  akmImproveForRun = fake ?? akmImprove;
32
33
  }
33
34
  /**
34
- * Handle the `--auto-accept` flag retired in 0.9.0, returning the scope the run
35
- * should actually use.
36
- *
37
- * citty is non-strict, so the removed flag is silently absorbed rather than
38
- * rejected — which is the dangerous case. The SPACE-separated spelling
39
- * (`--auto-accept 90`) leaves `90` sitting in the positional slot, where it is
40
- * read as the asset-type scope: the run then matches nothing and exits 0, so a
41
- * 0.8-era crontab goes dark with no error at all. Warn about the flag, and drop
42
- * the poisoned positional so the run behaves as an unscoped improve instead.
35
+ * `--auto-accept` (removed in 0.9): citty absorbs it silently, and
36
+ * `--auto-accept 90` would leave `90` as the scope — a 0.8-era crontab would
37
+ * match nothing and exit 0. Warn, and drop that positional.
43
38
  */
44
39
  function resolveScopeAfterRetiredAutoAccept(scopeArg) {
45
40
  const invocation = getParsedInvocation();
@@ -55,41 +50,22 @@ function resolveScopeAfterRetiredAutoAccept(scopeArg) {
55
50
  }
56
51
  return scopeArg;
57
52
  }
58
- /**
59
- * `akm improve canary` was removed in 0.9 (moved to
60
- * `scripts/refresh-canary-set.ts`). Without this check "canary" falls through
61
- * to the generic scope positional, where resolveImproveScope treats any bare
62
- * word as a type filter that matches zero entries — so an unmigrated caller
63
- * silently acquires the improve lock and exits 0 having done nothing, instead
64
- * of getting an error.
65
- */
53
+ /** `akm improve canary` (removed in 0.9) would otherwise be a type scope matching nothing, exiting 0. */
66
54
  function rejectRetiredCanaryScope(scopeArg) {
67
55
  if (scopeArg !== "canary")
68
56
  return;
69
- throw new UsageError('"akm improve canary" was removed in 0.9. Use `bun scripts/refresh-canary-set.ts [--refresh]` instead.', "INVALID_FLAG_VALUE");
57
+ throw new UsageError('"akm improve canary" was removed in 0.9; the collapse-detector canary set it managed no longer exists.', "INVALID_FLAG_VALUE");
70
58
  }
71
- /**
72
- * `--target` was renamed to `--bundle` on `improve` in 0.9 (S8). citty is
73
- * non-strict, so the retired spelling is silently absorbed rather than
74
- * rejected — accepted proposals then write into the default bundle instead
75
- * of the one the caller named, with exit 0 and no error. Reject it
76
- * explicitly instead.
77
- */
59
+ /** `--target` (renamed `--bundle` in 0.9) would otherwise be absorbed and write to the default bundle. */
78
60
  function rejectRetiredImproveTargetFlag() {
79
61
  if (!getParsedInvocation().hasFlag("--target"))
80
62
  return;
81
63
  throw new UsageError("`akm improve --target` was renamed to `--bundle` in 0.9. Use `--bundle <name>` instead.", "INVALID_FLAG_VALUE");
82
64
  }
83
65
  /**
84
- * `--require-engines` (#957): abort before any lock, log, or index side
85
- * effect when the resolved plan already knows a process the active strategy
86
- * would enable cannot run. Without this flag improve degrades gracefully —
87
- * it skips the affected processes and reports them in `skippedProcesses` —
88
- * which is right for an interactive run but wrong for a scheduled one that
89
- * would rather fail loudly than burn its budget re-indexing and then skip
90
- * everything. Names the unresolved credential reference per process (not
91
- * just the process name) so an operator whose own shell passes config
92
- * validation can see exactly what the scheduler's environment is missing.
66
+ * `--require-engines` (#957): fail before any side effect when an enabled
67
+ * process cannot run, naming what each is missing — a scheduled run would
68
+ * rather fail loudly than index and then skip everything.
93
69
  */
94
70
  function assertRequiredEnginesAvailable(plan) {
95
71
  if (plan.engineUnavailable.length === 0)
@@ -97,66 +73,81 @@ function assertRequiredEnginesAvailable(plan) {
97
73
  const lines = plan.engineUnavailable.map((item) => ` - ${item.process} (${item.configKey}): ${item.reason}`);
98
74
  throw new ConfigError(`--require-engines: ${plan.engineUnavailable.length} improve process${plan.engineUnavailable.length === 1 ? "" : "es"} cannot run because ${plan.engineUnavailable.length === 1 ? "its" : "their"} engine is unavailable:\n${lines.join("\n")}`, "LLM_NOT_CONFIGURED");
99
75
  }
100
- /**
101
- * Every distinct `kind: "llm"` connection the active strategy's plan would
102
- * actually dispatch against — the main per-process runners plus triage's own
103
- * judgment engine, which is resolved separately (#957).
104
- */
76
+ /** Every LLM connection the plan would dispatch to, triage's judgment engine included. */
105
77
  function collectRequiredEngineTargets(plan) {
106
78
  const targets = [];
107
79
  for (const [processName, process] of Object.entries(plan.processes)) {
108
80
  if (process.runner) {
109
- targets.push({ process: processName, engine: process.runner.engine, connection: process.runner.connection });
81
+ targets.push({
82
+ process: processName,
83
+ engine: process.runner.engine,
84
+ connection: probeConnection(process.runner),
85
+ });
110
86
  }
111
87
  }
112
88
  if (plan.triageJudgment?.kind === "llm") {
113
89
  targets.push({
114
90
  process: "triage.judgment",
115
91
  engine: plan.triageJudgment.engine,
116
- connection: plan.triageJudgment.connection,
92
+ connection: probeConnection(plan.triageJudgment),
117
93
  });
118
94
  }
119
95
  return targets;
120
96
  }
97
+ /** The resolved engine keeps its request timeout beside the connection (the runtime merges it in); the probe needs it on the connection. */
98
+ function probeConnection(runner) {
99
+ return runner.timeoutMs !== undefined ? { ...runner.connection, timeoutMs: runner.timeoutMs } : runner.connection;
100
+ }
101
+ /**
102
+ * The bound on `--require-engines`' probe: the connection's own request
103
+ * timeout, at most two minutes. A local server busy with another job queues
104
+ * the probe behind that job, and a fixed 3s bound failed every scheduled
105
+ * improve run on 2026-09-27 against a reachable endpoint; the cap still ends a
106
+ * hung endpoint (#957) long before a run's own multi-minute calls would.
107
+ */
108
+ export function requiredEngineProbeTimeoutMs(connection) {
109
+ return Math.min(connection.timeoutMs ?? DEFAULT_LLM_TIMEOUT_MS, REQUIRED_ENGINE_PROBE_MAX_MS);
110
+ }
111
+ const REQUIRED_ENGINE_PROBE_MAX_MS = 120_000;
121
112
  /**
122
- * `--require-engines` field re-test (#957): the static check above only
123
- * proves an engine is configured and credentialed — it cannot see a dead
124
- * endpoint. A field run against an unreachable engine sat silent for
125
- * minutes instead of hitting the documented exit-78 path. Exercise the real
126
- * model completion path with a tiny response and a three-second bound. The
127
- * `/models` endpoint used by the lightweight health check is deliberately
128
- * insufficient here: a gateway can list a model while its upstream completion
129
- * route is dead (#980). Deduplicate by endpoint + model, not endpoint alone,
130
- * because model backends behind one gateway can fail independently.
113
+ * `--require-engines`, live: probe each connection's real completion path
114
+ * (a gateway can list a model whose completion route is dead, #980), once per
115
+ * endpoint + model, within {@link requiredEngineProbeTimeoutMs}. Returns each
116
+ * target's latency for the run result (R17); an unreachable one fails the run.
131
117
  */
132
- async function assertRequiredEnginesReachable(plan, probeReachable = (connection) => probeLlmReachable(connection, 3_000)) {
118
+ export async function assertRequiredEnginesReachable(plan, probeReachable = (connection) => probeLlmReachable(connection, requiredEngineProbeTimeoutMs(connection))) {
133
119
  const targets = collectRequiredEngineTargets(plan);
134
120
  if (targets.length === 0)
135
- return;
121
+ return [];
136
122
  const probesByConnection = new Map();
137
123
  const probed = await Promise.all(targets.map(async (target) => {
138
124
  const key = `${target.connection.endpoint.replace(/\/+$/, "")}|${target.connection.model}`;
139
125
  let pending = probesByConnection.get(key);
140
126
  if (!pending) {
141
- pending = probeReachable(target.connection);
127
+ const probeStartedAt = Date.now();
128
+ pending = probeReachable(target.connection).then((reach) => ({
129
+ reach,
130
+ latencyMs: Date.now() - probeStartedAt,
131
+ }));
142
132
  probesByConnection.set(key, pending);
143
133
  }
144
- return { ...target, reach: await pending };
134
+ const { reach, latencyMs } = await pending;
135
+ return { ...target, reach, latencyMs };
145
136
  }));
146
137
  const unreachable = probed.filter((item) => !item.reach.reachable);
147
- if (unreachable.length === 0)
148
- return;
149
- const lines = unreachable.map((item) => ` - ${item.process} (engine "${item.engine}", ${item.connection.endpoint}): ${item.reach.error ?? "did not respond"}`);
150
- throw new ConfigError(`--require-engines: ${unreachable.length} improve process${unreachable.length === 1 ? "" : "es"} cannot run because ${unreachable.length === 1 ? "its" : "their"} engine completion path is not reachable:\n${lines.join("\n")}`, "LLM_NOT_CONFIGURED");
138
+ if (unreachable.length > 0) {
139
+ const lines = unreachable.map((item) => ` - ${item.process} (engine "${item.engine}", ${item.connection.endpoint}): ${item.reach.error ?? "did not respond"}`);
140
+ throw new ConfigError(`--require-engines: ${unreachable.length} improve process${unreachable.length === 1 ? "" : "es"} cannot run because ${unreachable.length === 1 ? "its" : "their"} engine completion path is not reachable:\n${lines.join("\n")}`, "LLM_NOT_CONFIGURED", "Check that each listed endpoint is up and serves its model. The probe is one short completion, bounded by the engine's timeoutMs (at most two minutes).");
141
+ }
142
+ return probed.map((item) => ({
143
+ process: item.process,
144
+ engine: item.engine,
145
+ endpoint: item.connection.endpoint,
146
+ reachable: item.reach.reachable,
147
+ latencyMs: item.latencyMs,
148
+ }));
151
149
  }
152
- /**
153
- * `--show-prompt` (#952): render the composed reflect prompt for one asset ref
154
- * and exit, before any lock, log, index write, or engine dispatch — the field
155
- * had no cheap way to confirm the #952 prompt fix (unverified-feedback framing,
156
- * no-truncation-marker instruction) without running a full improve cycle.
157
- * Reuses `renderReflectPromptPreview` (reflect.ts), which stops before the
158
- * dispatch lease reflect would otherwise acquire, so this never calls an engine.
159
- */
150
+ /** `--show-prompt` (#952): print reflect's composed prompt for one ref — no lock, write or dispatch. */
160
151
  async function runShowPromptCli(refArg, parsedRef, taskArg, targetArg, resolvedPlan) {
161
152
  const readSource = resolveImproveReadSource(resolvedPlan.config, parsedRef, targetArg);
162
153
  const preview = await renderReflectPromptPreview({
@@ -180,30 +171,14 @@ async function runShowPromptCli(refArg, parsedRef, taskArg, targetArg, resolvedP
180
171
  prompt: preview.prompt,
181
172
  });
182
173
  }
183
- /**
184
- * `akm improve report` (#944): a scope value that dispatches to the per-run
185
- * LLM usage/routing report instead of a real improve run — "report" is not,
186
- * and will never be, a real asset type (`DEFAULT_ALLOWED_TYPES` in
187
- * improve-strategies.ts), so this already matched zero assets before this
188
- * flag existed, matching the precedent `rejectRetiredCanaryScope` set for
189
- * intercepting a special scope word ahead of any lock/log/index side effect.
190
- */
174
+ /** `akm improve report` (#944): the per-run LLM usage/routing report ("report" is no asset type). */
191
175
  function runImproveReportCli(args) {
192
176
  const runIdArg = getStringArg(args, "run");
193
177
  const sinceArg = getStringArg(args, "since");
194
178
  const result = runImproveReportQuery({ runId: runIdArg, since: sinceArg });
195
179
  output("improve-report", { ok: true, ...result });
196
180
  }
197
- /**
198
- * `--run`/`--since` only mean anything with the "report" scope, which
199
- * intercepts before this point in the `run` handler below. citty is
200
- * non-strict, so passing either with a real scope (or no scope at all) used
201
- * to be silently ignored — the flag's value was read nowhere else, and the
202
- * run proceeded as an ordinary improve run with no error, discarding the
203
- * operator's intent. Reject explicitly instead, matching the precedent
204
- * `rejectRetiredCanaryScope`/`rejectRetiredImproveTargetFlag` set for other
205
- * flag misuse on this command.
206
- */
181
+ /** `--run`/`--since` belong to `improve report`; elsewhere citty would silently ignore them. */
207
182
  function rejectReportOnlyFlags(args) {
208
183
  const flag = getStringArg(args, "run") !== undefined
209
184
  ? "--run"
@@ -219,9 +194,7 @@ export const improveCommand = defineCommand({
219
194
  name: "improve",
220
195
  description: "Analyze existing AKM assets and generate improvement proposals; also consolidates memories when the selected strategy enables consolidate.",
221
196
  },
222
- // Raw defineCommand, so the global output flags are declared here explicitly.
223
- // Without them citty treats `--format` as a boolean and its space-separated
224
- // value falls through to the `scope` positional.
197
+ // Declared explicitly: otherwise citty takes `--format`'s value as the scope.
225
198
  args: {
226
199
  ...GLOBAL_OUTPUT_ARGS,
227
200
  scope: {
@@ -277,7 +250,7 @@ export const improveCommand = defineCommand({
277
250
  },
278
251
  strategy: {
279
252
  type: "string",
280
- description: "Named improve strategy from improve.strategies or built-in strategies (catchup, consolidate, default, graph-refresh, proactive-maintenance, quick, reflect-distill, thorough). Controls which sub-processes run and which asset types are processed.",
253
+ description: "Named improve strategy from improve.strategies or built-in strategies (catchup, consolidate, default, proactive-maintenance, quick, reflect-distill, thorough). Controls which sub-processes run and which asset types are processed.",
281
254
  },
282
255
  sync: {
283
256
  type: "boolean",
@@ -290,27 +263,16 @@ export const improveCommand = defineCommand({
290
263
  },
291
264
  async run({ args }) {
292
265
  await runWithJsonErrors(async () => {
293
- // #944 — dispatch before any lock/log/index side effect, same
294
- // interception point as rejectRetiredCanaryScope below.
295
266
  if (getStringArg(args, "scope") === "report") {
296
267
  runImproveReportCli(args);
297
268
  return;
298
269
  }
299
270
  rejectReportOnlyFlags(args);
300
271
  rejectRetiredImproveTargetFlag();
301
- // D7 — `--format` used to be rejected here outright. It is a global flag on
302
- // a command that does emit an envelope through `output()` (always on
303
- // `--dry-run`, otherwise with `--json-to-stdout`), so rejecting it made
304
- // improve a fourth inconsistent format behaviour rather than a documented
305
- // exemption. It now applies to that envelope; progress output stays on
306
- // stderr regardless.
307
272
  const jsonToStdout = args["json-to-stdout"];
308
273
  const targetArg = getStringArg(args, "bundle");
309
274
  const taskArg = getStringArg(args, "task");
310
- // #947 — `--plan` is a zero-logic discoverability alias for `--dry-run`;
311
- // it must never fork the computation, only set the same flag. #952 —
312
- // `--show-prompt` implies the same read-only posture (it never reaches
313
- // akmImprove at all, but keeps writeTarget/resolvedPlan unset the same way).
275
+ // `--plan` is an alias for `--dry-run`; `--show-prompt` is read-only too.
314
276
  const dryRun = args["dry-run"] || args.plan || args["show-prompt"];
315
277
  const limitRaw = parsePositiveIntFlag(args.limit ?? undefined);
316
278
  const timeoutMs = parsePositiveIntFlag(args["timeout-ms"], "--timeout-ms");
@@ -326,16 +288,9 @@ export const improveCommand = defineCommand({
326
288
  : scopeRef
327
289
  ? resolveMutationTarget(effectiveConfig, scopeRef, targetArg).target
328
290
  : resolveWriteTarget(effectiveConfig, targetArg);
329
- // Resolve every enabled model-backed process before logging, signal
330
- // lifecycle setup, or any filesystem/database side effect.
331
- // #800/#957 round 3 — `--dry-run`/`--plan` never dispatches, so the
332
- // "no improve process can run" guard must not throw when every process
333
- // is disabled purely by an unreachable credential; a live run keeps
334
- // throwing (allowAllDisabled unset).
291
+ // Every model-backed process resolves before any side effect; a dry run
292
+ // never dispatches, so it tolerates every process being disabled.
335
293
  const resolvedPlan = resolveImprovePlan(strategyArg, effectiveConfig, { allowAllDisabled: Boolean(dryRun) });
336
- // #952 — same interception point as the `report` scope above: before any
337
- // lock, log, or index side effect. Requires a single fully-qualified
338
- // asset ref (not a type or whole-bundle scope).
339
294
  if (args["show-prompt"]) {
340
295
  if (!scopeArg || !scopeRef) {
341
296
  throw new UsageError("`--show-prompt` requires a fully-qualified asset ref as the scope (e.g. `akm improve lessons/my-lesson --show-prompt`).", "INVALID_FLAG_VALUE");
@@ -343,15 +298,14 @@ export const improveCommand = defineCommand({
343
298
  await runShowPromptCli(scopeArg, scopeRef, taskArg, targetArg, resolvedPlan);
344
299
  return;
345
300
  }
301
+ let engineProbe;
346
302
  if (args["require-engines"]) {
347
303
  assertRequiredEnginesAvailable(resolvedPlan);
348
- await assertRequiredEnginesReachable(resolvedPlan);
304
+ engineProbe = await assertRequiredEnginesReachable(resolvedPlan);
349
305
  }
350
306
  const selectedStrategyName = resolvedPlan.strategy.name;
351
307
  const sensitiveValues = collectEngineCredentialValues(effectiveConfig);
352
- // Only set the keys the user actually passed (citty leaves the flag
353
- // undefined unless `--sync`/`--no-sync` / `--push`/`--no-push` appears),
354
- // so the resolved profile `sync` block wins by default.
308
+ // Only flags actually passed override the strategy's `sync` block.
355
309
  const syncFlag = args.sync;
356
310
  const pushFlag = args.push;
357
311
  const syncOverride = {};
@@ -365,16 +319,10 @@ export const improveCommand = defineCommand({
365
319
  }
366
320
  const startedAtMs = Date.now();
367
321
  const startedAtIso = new Date(startedAtMs).toISOString();
368
- // Mint the run-id up front so signal handlers can persist a partial
369
- // record if the process is killed mid-run. Pre-2026-05-26 the runId
370
- // was minted at end-of-run, so SIGTERM'd runs (cron timeout) left no
371
- // row in improve_runs and effectively disappeared from `akm health`.
322
+ // The run id is minted up front so a killed run still leaves an improve_runs row.
372
323
  const runId = buildImproveRunId();
373
324
  const primaryStashDir = writeTarget?.source.path;
374
325
  const inferredScopeMode = scopeRef ? "ref" : scopeArg ? "type" : "all";
375
- // Signal handler + exception path both flow through this helper so
376
- // every abnormal termination produces a row with ok:false and a
377
- // reason in metadata.terminated.
378
326
  let runRecorded = false;
379
327
  const persistTerminated = (reason, errorMessage) => {
380
328
  if (dryRun)
@@ -398,14 +346,7 @@ export const improveCommand = defineCommand({
398
346
  process.stderr.write(`warning: failed to persist terminated improve run ${runId}: ${err instanceof Error ? err.message : String(err)}\n`);
399
347
  }
400
348
  };
401
- // R8: the signal table / handlers / watchdog / persist-before-exit
402
- // choreography lives in `runImproveSession`. It registers the
403
- // SIGTERM/SIGINT/SIGHUP handlers (each persists the terminated-run row
404
- // BEFORE process.exit so a SIGTERM'd run — e.g. cron timeout — always
405
- // leaves a row in improve_runs), awaits the work, then removes the
406
- // handlers on the way out. `onTerminate` persists synchronously
407
- // (recordTerminatedImproveRun -> bun:sqlite writes are sync), and the
408
- // 2000ms watchdog inside the session force-exits if that ever hangs.
349
+ // The session persists the terminated-run row before exiting on a signal.
409
350
  let improveResult;
410
351
  try {
411
352
  improveResult = await runImproveSession({
@@ -422,12 +363,8 @@ export const improveCommand = defineCommand({
422
363
  ...(requireFeedbackSignal ? { requireFeedbackSignal } : {}),
423
364
  ...(skipIfLocked ? { skipIfLocked } : {}),
424
365
  ...(strategyArg !== undefined ? { strategy: strategyArg } : {}),
366
+ ...(engineProbe !== undefined ? { engineProbe } : {}),
425
367
  ...(Object.keys(syncOverride).length > 0 ? { sync: syncOverride } : {}),
426
- consolidateOptions: {
427
- target: targetArg,
428
- dryRun,
429
- task: taskArg,
430
- },
431
368
  }),
432
369
  }, {
433
370
  signalSource: process,
@@ -439,10 +376,6 @@ export const improveCommand = defineCommand({
439
376
  });
440
377
  }
441
378
  catch (err) {
442
- // akmImprove threw — record the failure before letting runWithJsonErrors
443
- // emit the standard JSON error envelope. Without this, exceptions in
444
- // the main loop (LLM provider crash, OOM, etc.) leave no improve_runs
445
- // row, matching the SIGTERM gap.
446
379
  persistTerminated("exception", err instanceof Error ? err.message : String(err));
447
380
  throw err;
448
381
  }
@@ -450,57 +383,30 @@ export const improveCommand = defineCommand({
450
383
  clearLogFile();
451
384
  }
452
385
  if (dryRun) {
453
- // A dry-run never persists its result, so stdout is its only result
454
- // channel. F4: was `process.exit(0)`, which terminates synchronously
455
- // and skips pending cleanup (e.g. the `finally { clearLogFile(); }`
456
- // above already ran, but any citty/runWithJsonErrors-level cleanup
457
- // on the way out would not). Exit code is 0 either way — `return`
458
- // alone is sufficient since success is the default `process.exitCode`.
386
+ // A dry run persists nothing: stdout is its only result channel.
459
387
  output("improve", improveResult);
460
388
  return;
461
389
  }
462
- // Default mode (0.8.0+): persist the full result as a row in the
463
- // `improve_runs` table of state.db (migration 003) and emit NOTHING
464
- // on stdout. The verbose JSON would otherwise scroll earlier progress
465
- // logs out of the terminal buffer. The existing `[improve] ...`
466
- // progress log lines on stderr remain the canonical console UX — the
467
- // usage-report table below (#944) follows that same convention
468
- // (stderr, `[improve]`-prefixed), it is not new stdout noise.
469
- //
470
- // Pre-0.8.0 wrote `<stash>/.akm/runs/<run-id>/improve-result.json`;
471
- // those files are no longer authored. Query recent runs with:
472
- // sqlite3 "$AKM_DATA_DIR/state.db" \
473
- // "SELECT id, started_at, ok, dry_run FROM improve_runs \
474
- // ORDER BY started_at DESC LIMIT 10"
475
- // runId + primaryStashDir minted up-top so signal handlers can record
476
- // partial runs; reuse them here for the success path.
477
- runRecorded = true; // Suppress any late signal-handler write — the success path owns the row now.
390
+ // A live run's result goes to state.db's improve_runs, not stdout
391
+ // (progress stays on stderr). The success path owns the row now.
392
+ runRecorded = true;
478
393
  if (primaryStashDir) {
479
394
  try {
480
395
  recordImproveRunResult(primaryStashDir, runId, improveResult, startedAtIso, sensitiveValues);
481
396
  }
482
397
  catch (err) {
483
- // Stderr warning on the failure path is preferable to crashing
484
- // the run after all the work has completed.
485
398
  process.stderr.write(`warning: failed to record improve run ${runId}: ${err instanceof Error ? err.message : String(err)}\n`);
486
399
  }
487
400
  }
488
401
  else {
489
402
  process.stderr.write(`warning: no writable bundle directory resolved; improve result not persisted to state.db (use --json-to-stdout to capture)\n`);
490
403
  }
491
- // #944 — same table `akm improve report` renders, appended to every
492
- // real (non-dry-run) run so an operator sees the routing/cost split
493
- // without a separate command. Omitted when the run made no LLM calls
494
- // and skipped no enabled process (nothing to report).
404
+ // The `akm improve report` table, on stderr, when there is anything to report (#944).
495
405
  if (improveResult.usageReport) {
496
406
  process.stderr.write(`${formatUsageReportTable(improveResult.usageReport)}\n`);
497
407
  }
498
408
  if (jsonToStdout)
499
409
  output("improve", improveResult);
500
- // F4: was `process.exit(0)` — the run has already been fully recorded
501
- // above (recordImproveRunResult / the warning path), so nothing here
502
- // depends on an immediate synchronous exit. This is the last statement
503
- // in the handler, so a plain fall-through is equivalent.
504
410
  });
505
411
  },
506
412
  });
@@ -2,72 +2,31 @@
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
- * Helpers for persisting the `akm improve` result envelope.
6
- *
7
- * v0.8.0 behavioural default change:
8
- * - Default: the full result is recorded as a single row in the
9
- * `improve_runs` table of `state.db` (migration 003). Stdout is empty.
10
- * The existing `[improve] ...` progress log lines on stderr remain the
11
- * canonical console UX.
12
- * - `--json-to-stdout` additionally emits the persisted result as JSON.
13
- *
14
- * v0.8.0 storage change (this module): the previous on-disk artifact at
15
- * `<stash>/.akm/runs/<runId>/improve-result.json` is no longer written. The
16
- * canonical record now lives in `improve_runs` (see
17
- * `src/core/state-db.ts`). Pre-existing files from older runs are not
18
- * deleted by this change — they become historical artifacts. Zero current
19
- * code paths read them, so no consumers needed to update.
20
- *
21
- * Run-id format: ISO-8601 timestamp (colons/dots replaced by `-`) plus an
22
- * 8-char hex random suffix. There is no existing canonical run-id helper for
23
- * persistent per-command artefacts on disk — the `workflow_runs` table uses
24
- * `randomUUID()` but is database-scoped, and `consolidate-journal.json` is a
25
- * single-slot artefact. We mint a fresh timestamped id for each improve run.
5
+ * Persist an `akm improve` result as one `improve_runs` row in state.db (since
6
+ * 0.8.0 stdout stays empty unless `--json-to-stdout`). A run that did not
7
+ * complete still gets a row.
26
8
  */
27
9
  import crypto from "node:crypto";
28
10
  import { decodeImproveResult } from "../../core/improve-result.js";
29
11
  import { redactSensitiveValue } from "../../core/redaction.js";
30
12
  import { withImmediateTransaction, withStateDb } from "../../core/state-db.js";
31
13
  import { recordImproveRun } from "../../storage/repositories/improve-runs-repository.js";
32
- /**
33
- * Build a stable run-id for a single improve invocation.
34
- *
35
- * Shape: `<iso-8601-utc-with-dashes>-<8 hex chars>`, e.g.
36
- * `2026-05-19T17-30-22-123Z-a1b2c3d4`.
37
- *
38
- * The hex suffix protects against same-millisecond collisions when multiple
39
- * runs happen back-to-back in tests or scripts.
40
- */
14
+ /** `<iso-8601 with dashes>-<8 hex>`, e.g. `2026-05-19T17-30-22-123Z-a1b2c3d4` (the suffix breaks same-ms ties). */
41
15
  export function buildImproveRunId(now = new Date()) {
42
16
  const iso = now.toISOString().replace(/[:.]/g, "-");
43
17
  const rand = crypto.randomBytes(4).toString("hex");
44
18
  return `${iso}-${rand}`;
45
19
  }
46
- /**
47
- * Persist the full improve result into the `improve_runs` table of state.db.
48
- *
49
- * The state.db row carries the scope and dry-run flag from `result.scope`
50
- * and `result.dryRun`, plus the full result JSON for full fidelity. The
51
- * dry-run column is indexed so productivity audits can filter cleanly
52
- * (closes the dry-run/real-run artifact-trap recorded in MEMORY.md
53
- * `feedback_akm_dryrun_artifact_trap`).
54
- *
55
- */
20
+ /** Record a finished run (the full result, redacted; dry runs stay filterable). */
56
21
  export function recordImproveRunResult(stashDir, runId, result, startedAt, sensitiveValues = []) {
57
22
  const decoded = decodeImproveResult(result);
58
23
  const persistedResult = redactSensitiveValue(result, sensitiveValues);
59
24
  withStateDb((db) => {
60
25
  const completedAt = new Date().toISOString();
61
- // startedAt is the ISO timestamp captured at process launch (passed from the
62
- // CLI entry point). If omitted, fall back to the run-id's embedded timestamp
63
- // so started_at != completed_at even on older call sites.
26
+ // Without a launch timestamp, the one embedded in the run id.
64
27
  const resolvedStartedAt = startedAt ??
65
28
  runId.slice(0, 24).replace(/^(\d{4}-\d{2}-\d{2}T)(\d{2})-(\d{2})-(\d{2})-(\d{3})Z$/, "$1$2:$3:$4.$5Z");
66
- // #948: route through the shared BEGIN IMMEDIATE retry/reclassify helper
67
- // instead of a bare write — this INSERT used to rely solely on the
68
- // connection's 30s busy_timeout, with no retry and no friendly
69
- // reclassification on exhaustion, so a raw "database is locked" from
70
- // improve's own ledger write could reach the CLI as exit 70.
29
+ // BEGIN IMMEDIATE with retry: a bare write surfaced "database is locked" (#948).
71
30
  withImmediateTransaction(db, () => {
72
31
  recordImproveRun(db, {
73
32
  id: runId,
@@ -86,21 +45,9 @@ export function recordImproveRunResult(stashDir, runId, result, startedAt, sensi
86
45
  });
87
46
  }
88
47
  /**
89
- * Persist an improve_runs row for a run that did NOT complete normally.
90
- * 2026-05-26 incident: the cron's `timeout_ms: 1800000` SIGTERM'd an
91
- * akm-improve invocation at 30:00 with 54 actionable refs in-flight. No
92
- * `improve_runs` row was written because the writer only fired at successful
93
- * end-of-run, so the run vanished from `akm health --detail per-run` even
94
- * though it had consumed 30 min of LLM time and produced 29 ref-level
95
- * proposals. This helper closes that gap: signal handlers and the CLI
96
- * try/catch wrapper call it on the abnormal-exit paths so the row exists
97
- * with `ok: false` and `metadata.terminated.reason` set.
98
- *
99
- * The persisted result envelope is minimal — we don't try to reconstruct
100
- * the in-flight `actions[]` because that state lives inside `akmImprove`
101
- * and is gone by the time the signal handler runs. The row captures
102
- * enough to know: a run started, was scoped to X, did NOT complete, and
103
- * why.
48
+ * Record a run that did not complete (a signal, e.g. a cron timeout, or an
49
+ * exception) so it does not vanish from `akm health`: `ok: false` with the
50
+ * reason. The in-flight actions are gone by then, so the envelope is minimal.
104
51
  */
105
52
  export function recordTerminatedImproveRun(stashDir, runId, startedAt, reason, ctx) {
106
53
  const completedAt = new Date().toISOString();
@@ -123,9 +70,6 @@ export function recordTerminatedImproveRun(stashDir, runId, startedAt, reason, c
123
70
  },
124
71
  }, ctx.sensitiveValues ?? []);
125
72
  withStateDb((db) => {
126
- // #948: same rationale as recordImproveRunResult above — this is the
127
- // signal-handler/terminated-run write path, which must not itself raise
128
- // a raw "database is locked" while trying to record why the run ended.
129
73
  withImmediateTransaction(db, () => {
130
74
  recordImproveRun(db, {
131
75
  id: runId,