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
@@ -5,15 +5,16 @@ import fs from "node:fs";
5
5
  import os from "node:os";
6
6
  import path from "node:path";
7
7
  import { isDeepStrictEqual } from "node:util";
8
- import { isBundleSlug } from "../asset/asset-ref.js";
9
- import { isRecord } from "../common.js";
8
+ import { isBundleSlug, parseBundleRef } from "../asset/asset-ref.js";
9
+ import { deriveBundleId } from "../bundle-id.js";
10
+ import { isRecord, resolveStashDir } from "../common.js";
10
11
  import { ConfigError } from "../errors.js";
11
12
  import { liftLegacyEngineExtraParams } from "../extra-params.js";
12
13
  import { formatRegistryLabel, hasRegistryUrlCredentials } from "../registry-url.js";
13
14
  import { acquireConfigLock, backupExistingConfig, parseConfigText, readConfigText, withConfigLock, writeConfigAtomic, } from "./config-io.js";
14
- import { AkmConfigSchema, CURRENT_CONFIG_VERSION, listTopLevelConfigKeys } from "./config-schema.js";
15
- import { bundleComponentConfig, bundleContentRoot, bundleContentRoots, bundlesToSourceEntries } from "./config-sources.js";
16
- import { upgradeConfigVersion } from "./config-version-shim.js";
15
+ import { AkmConfigSchema, CURRENT_CONFIG_VERSION } from "./config-schema.js";
16
+ import { bundleComponentConfig, bundleContentRoot, bundleContentRoots, bundleSourceId, bundlesToSourceEntries, filesystemBundleSourceId, isBundleEnabled, } from "./config-sources.js";
17
+ import { resolveSchemaAt } from "./config-walker.js";
17
18
  import { deepMergeConfig, isPlainObject } from "./deep-merge.js";
18
19
  import { migrateLegacySourceShape } from "./legacy-source-shape-shim.js";
19
20
  import { isApiKeyReference, SECRET_STORE_REFERENCE_PATTERN } from "./schema/primitives.js";
@@ -26,36 +27,6 @@ export { VALID_HARNESS_IDS } from "./config-types.js";
26
27
  // Canonical taxonomy lives in the schema/validator layer; re-exported here so
27
28
  // existing `../core/config/config` import sites keep working.
28
29
  export { FEEDBACK_FAILURE_MODES } from "./config-schema.js";
29
- /**
30
- * Default value for {@link IndexPassConfig.graphExtractionBatchSize}. Chosen
31
- * empirically: 4 amortises the per-call HTTP overhead 4× while keeping the
32
- * combined prompt size well under common 8K/16K context windows (each body is
33
- * sliced to ~500 chars in the graph-extract prompt builder).
34
- */
35
- export const DEFAULT_GRAPH_EXTRACTION_BATCH_SIZE = 4;
36
- /**
37
- * Approximate character budget per asset body inside a batched
38
- * graph-extraction prompt — used by {@link resolveBatchSize} to derive a
39
- * context-window ceiling when `llm.contextLength` is configured. This accounts
40
- * for the actual `MAX_BODY_CHARS` (500) in graph-extract.ts plus the system
41
- * prompt, user prompt wrapper, and expected JSON response overhead.
42
- */
43
- const GRAPH_EXTRACTION_CHARS_PER_BODY = 1500;
44
- /**
45
- * Clamp a configured batch size against the model's known context window.
46
- *
47
- * `configured` defaults to {@link DEFAULT_GRAPH_EXTRACTION_BATCH_SIZE} when
48
- * `undefined`. When `contextLength` is provided, the result is the smaller of
49
- * `configured` and `floor(contextLength / GRAPH_EXTRACTION_CHARS_PER_BODY)`,
50
- * with a floor of 1 so the batched path always processes at least one body.
51
- */
52
- export function resolveBatchSize(configured, contextLength) {
53
- const base = configured && configured > 0 ? configured : DEFAULT_GRAPH_EXTRACTION_BATCH_SIZE;
54
- if (!contextLength || contextLength <= 0)
55
- return base;
56
- const ceiling = Math.max(1, Math.floor(contextLength / GRAPH_EXTRACTION_CHARS_PER_BODY));
57
- return Math.max(1, Math.min(base, ceiling));
58
- }
59
30
  // ── Defaults ────────────────────────────────────────────────────────────────
60
31
  export const DEFAULT_CONFIG = {
61
32
  configVersion: "0.9.0",
@@ -124,39 +95,39 @@ export function loadUserConfig() {
124
95
  };
125
96
  return finalConfig;
126
97
  }
127
- /**
128
- * Acquire the existing config-write sentinel and read a fresh validated
129
- * generation while keeping the sentinel held. Source update uses this to
130
- * fence an audited bundle descriptor through publication: a cooperating
131
- * config writer can commit either before this snapshot or after the update,
132
- * never between the final generation check and index commit.
133
- */
134
- export function acquireConfigReadFence() {
135
- const release = acquireConfigLock();
136
- try {
137
- cachedConfig = undefined;
138
- return { config: loadUserConfig(), release };
139
- }
140
- catch (error) {
141
- release();
142
- throw error;
143
- }
144
- }
145
98
  /**
146
99
  * Run the per-file config pipeline every raw config object goes through
147
100
  * before it is either validated (the local/top-level file) or merged in as
148
- * an `extends` base: JSONC parse already done by the caller, then version
149
- * shim, then legacy `stashDir`/`sources[]`/`installed[]` shim, then the
150
- * legacy `extraParams` lift (#852). Shared by {@link parseAndValidateConfigText}
151
- * (the local file) and {@link resolveExtendsChain} (each base in the chain) so
152
- * a fleet-shared base config can carry its own old `configVersion` / legacy
153
- * shape independently of the file that extends it.
101
+ * an `extends` base: JSONC parse already done by the caller, then the
102
+ * `configVersion` read ({@link readConfigVersion}), then the legacy
103
+ * `stashDir`/`sources[]`/`installed[]` shim, then the legacy `extraParams`
104
+ * lift (#852). Unknown keys are not an error: the schema drops them in
105
+ * memory. Shared by {@link parseAndValidateConfigText} (the local file) and
106
+ * {@link resolveExtendsChain} (each base in the chain) so a fleet-shared base
107
+ * config can carry its own `configVersion` / legacy shape independently of
108
+ * the file that extends it.
154
109
  */
155
110
  function runConfigFilePipeline(text, sourcePath) {
156
- const versioned = upgradeConfigVersion(parseConfigText(text, sourcePath), sourcePath);
111
+ const versioned = readConfigVersion(parseConfigText(text, sourcePath), sourcePath);
157
112
  const parsedRaw = migrateLegacySourceShape(versioned, sourcePath);
158
113
  return liftExtraParamsOrThrow(parsedRaw, sourcePath);
159
114
  }
115
+ /**
116
+ * `configVersion` is read, never gated on. `"0.9.0"` is the only value akm
117
+ * has ever shipped, and a document without the field is that same document.
118
+ * Any other value is named once and the file is read as the current shape
119
+ * anyway; every ordinary config write and `akm migrate apply`'s `configFile`
120
+ * step then persist `"0.9.0"`.
121
+ */
122
+ function readConfigVersion(raw, sourcePath) {
123
+ const version = raw.configVersion;
124
+ if (version === CURRENT_CONFIG_VERSION)
125
+ return raw;
126
+ if (version !== undefined) {
127
+ warnOnce(`config:config-version${sourcePath ? `:${sourcePath}` : ""}`, `${sourcePath ?? "config.json"} declares configVersion ${JSON.stringify(version)}; this release reads it as ${CURRENT_CONFIG_VERSION}.`);
128
+ }
129
+ return { ...raw, configVersion: CURRENT_CONFIG_VERSION };
130
+ }
160
131
  /**
161
132
  * #852 (following #815): a config still using legacy `extraParams` keys —
162
133
  * e.g. `reasoning_effort`, a documented 0.9.1 workaround — needs to be
@@ -192,49 +163,74 @@ function liftExtraParamsOrThrow(parsedRaw, sourcePath) {
192
163
  * keeps around, instead of only getting the final merged `AkmConfig` back.
193
164
  */
194
165
  function buildEffectiveConfig(liftedLocalRaw, sourcePath) {
195
- warnUnknownTopLevelConfigKeys(liftedLocalRaw, sourcePath);
196
166
  const withExtends = resolveExtendsChain(liftedLocalRaw, sourcePath);
197
167
  const where = sourcePath ? ` at ${sourcePath}` : "";
168
+ warnUnknownConfigKeys(liftedLocalRaw, sourcePath);
198
169
  const parsed = AkmConfigSchema.safeParse(withExtends);
199
170
  if (!parsed.success) {
200
171
  const lines = parsed.error.issues.map((i) => ` - ${i.path.join(".") || "(root)"}: ${i.message}`).join("\n");
201
- const needsSchedulerMigration = parsed.error.issues.some((issue) => issue.path[0] === "scheduler" && issue.path.at(-1) === "sourceId");
202
- throw new ConfigError(`Invalid config${where}:\n${lines}`, "INVALID_CONFIG_FILE", needsSchedulerMigration
203
- ? "Run `akm migrate apply` to bind existing scheduler grants to their source."
204
- : undefined);
172
+ throw new ConfigError(`Invalid config${where}:\n${lines}`, "INVALID_CONFIG_FILE");
205
173
  }
206
174
  const merged = deepMergeConfig(DEFAULT_CONFIG, parsed.data);
207
175
  const finalResult = AkmConfigSchema.safeParse(merged);
208
176
  if (!finalResult.success) {
209
177
  const lines = finalResult.error.issues.map((i) => ` - ${i.path.join(".") || "(root)"}: ${i.message}`).join("\n");
210
- const needsSchedulerMigration = finalResult.error.issues.some((issue) => issue.path[0] === "scheduler" && issue.path.at(-1) === "sourceId");
211
- throw new ConfigError(`Invalid merged config${sourcePath ? ` at ${sourcePath}` : ""}:\n${lines}`, "INVALID_CONFIG_FILE", needsSchedulerMigration
212
- ? "Run `akm migrate apply` to bind existing scheduler grants to their source."
213
- : undefined);
178
+ throw new ConfigError(`Invalid merged config${sourcePath ? ` at ${sourcePath}` : ""}:\n${lines}`, "INVALID_CONFIG_FILE");
214
179
  }
215
180
  assertUniquePhysicalBundleRoots(finalResult.data, sourcePath);
216
181
  return finalResult.data;
217
182
  }
218
- const RETIRED_TOP_LEVEL_CONFIG_KEYS = new Set([
219
- "agent",
220
- "bindings",
221
- "features",
222
- "installed",
223
- "llm",
224
- "modelAliases",
225
- "profiles",
226
- "sources",
227
- "stashDir",
228
- "stashes",
229
- "writable",
230
- ]);
231
- function warnUnknownTopLevelConfigKeys(raw, sourcePath) {
232
- const known = new Set(listTopLevelConfigKeys());
233
- for (const key of Object.keys(raw).sort()) {
234
- if (known.has(key) || RETIRED_TOP_LEVEL_CONFIG_KEYS.has(key))
183
+ /**
184
+ * Retired `index.<passName>` keys that still validate against the generic
185
+ * per-pass catchall schema (`IndexPassConfigSchema`), so `resolveSchemaAt`
186
+ * below never returns `undefined` for them and the walk would otherwise
187
+ * treat them as a live, ordinary pass. Named here so the same three
188
+ * guarantees apply as any other retired config key (AGENTS.md "Reading
189
+ * persisted data"): a config setting one keeps loading, is named once by
190
+ * the unknown-key warning, and is dropped only by `akm migrate apply`.
191
+ * Both were retired in 0.9.17-alpha.9: `index.graph` (the LLM entity-graph
192
+ * extraction pass) and `index.metadataEnhance` (LLM metadata enrichment).
193
+ */
194
+ const RETIRED_CATCHALL_KEY_PATHS = new Set(["index.graph", "index.metadataEnhance"]);
195
+ /**
196
+ * Every dotted key in `raw` the schema does not know, at any depth (arrays
197
+ * are not descended). Unknown keys are never an error: they are a typo, or a
198
+ * key another release used. Reads keep them (they round-trip through
199
+ * ordinary writes, so a newer release's settings survive a downgrade);
200
+ * `akm migrate apply` drops them.
201
+ */
202
+ export function unknownConfigKeyPaths(root, node = root, prefix = []) {
203
+ const found = [];
204
+ for (const key of Object.keys(node).sort()) {
205
+ const keyPath = [...prefix, key];
206
+ if (RETIRED_CATCHALL_KEY_PATHS.has(keyPath.join(".")) || resolveSchemaAt(keyPath, root) === undefined) {
207
+ found.push(keyPath);
235
208
  continue;
236
- warnOnce(`config:unknown-key:${sourcePath ?? "inline"}:${key}`, `Unknown config key ${JSON.stringify(key)}${sourcePath ? ` at ${sourcePath}` : ""} has no defined akm behavior. Check the spelling or remove it.`);
209
+ }
210
+ const value = node[key];
211
+ if (isPlainConfigObject(value))
212
+ found.push(...unknownConfigKeyPaths(root, value, keyPath));
213
+ }
214
+ return found;
215
+ }
216
+ function warnUnknownConfigKeys(raw, sourcePath) {
217
+ for (const keyPath of unknownConfigKeyPaths(raw)) {
218
+ const dotted = keyPath.join(".");
219
+ warnOnce(`config:unknown-key:${sourcePath ?? "inline"}:${dotted}`, `Unknown config key ${JSON.stringify(dotted)}${sourcePath ? ` at ${sourcePath}` : ""} has no defined akm behavior and is ignored. Check the spelling; a key retired by this release or added by a newer one is dropped by \`akm migrate apply\`.`);
220
+ }
221
+ }
222
+ function deleteConfigPath(node, keyPath) {
223
+ let cursor = node;
224
+ for (const segment of keyPath.slice(0, -1)) {
225
+ if (!isPlainConfigObject(cursor))
226
+ return;
227
+ cursor = cursor[segment];
237
228
  }
229
+ if (isPlainConfigObject(cursor))
230
+ delete cursor[keyPath[keyPath.length - 1]];
231
+ }
232
+ function isPlainConfigObject(value) {
233
+ return typeof value === "object" && value !== null && !Array.isArray(value);
238
234
  }
239
235
  function assertUniquePhysicalBundleRoots(config, sourcePath) {
240
236
  const owners = new Map();
@@ -250,11 +246,10 @@ function assertUniquePhysicalBundleRoots(config, sourcePath) {
250
246
  * Parse raw config text and validate via Zod.
251
247
  * ({@link AkmConfigSchema}). Returns the merged-with-defaults AkmConfig.
252
248
  *
253
- * The schema accepts only the current config version. A known older version
254
- * is auto-upgraded in memory first (see `./config-version-shim`); anything
255
- * else — including anything newer — is rejected before the canonical shape
256
- * is validated. When the config sets `extends` (#945), its resolved chain is
257
- * deep-merged underneath before validation — see {@link resolveExtendsChain}.
249
+ * `configVersion` is read as the current version whatever it says (see
250
+ * {@link readConfigVersion}). When the config sets `extends` (#945), its
251
+ * resolved chain is deep-merged underneath before validation — see
252
+ * {@link resolveExtendsChain}.
258
253
  */
259
254
  export function parseAndValidateConfigText(text, sourcePath) {
260
255
  const liftedConfig = runConfigFilePipeline(text, sourcePath);
@@ -287,7 +282,7 @@ function collectExtendsLayers(localRaw, configPath) {
287
282
  }
288
283
  visited.add(resolvedPath);
289
284
  const baseRaw = runConfigFilePipeline(text, resolvedPath);
290
- warnUnknownTopLevelConfigKeys(baseRaw, resolvedPath);
285
+ warnUnknownConfigKeys(baseRaw, resolvedPath);
291
286
  layers.push({ ref, raw: baseRaw });
292
287
  current = baseRaw;
293
288
  currentPath = resolvedPath;
@@ -663,6 +658,46 @@ function configWriteBody(localRaw, current, next, persistTopLevelKeys = []) {
663
658
  }
664
659
  return ordered;
665
660
  }
661
+ /**
662
+ * The migrator's one config step. The reader already tolerates every shape
663
+ * akm has written (`configVersion` read as current, legacy source layout,
664
+ * `extraParams` lift, unknown keys dropped); this writes that current shape back to
665
+ * `config.json` — the same body `mutateConfig` writes — so the tolerance
666
+ * becomes durable. Reports without writing unless `apply` is set.
667
+ */
668
+ export function normalizeConfigFile(configPath, options) {
669
+ return withConfigLock(() => {
670
+ const text = readConfigText(configPath);
671
+ if (text === undefined)
672
+ return { keys: [], changed: false, applied: false };
673
+ const raw = parseConfigText(text, configPath);
674
+ const localRaw = runConfigFilePipeline(text, configPath);
675
+ const current = buildEffectiveConfig(localRaw, configPath);
676
+ const next = validateCompleteConfig({ ...current, configVersion: CURRENT_CONFIG_VERSION });
677
+ const body = withSchedulerOnDisk(configWriteBody(localRaw, current, next), next);
678
+ for (const keyPath of unknownConfigKeyPaths(body))
679
+ deleteConfigPath(body, keyPath);
680
+ // `improve.strategies["graph-refresh"]` is schema-valid (any name is a
681
+ // legal custom-strategy key), so it never reaches the unknown-key sweep
682
+ // above. It can only be a leftover override of the deleted graph-refresh
683
+ // built-in (0.9.17-alpha.9) — resolveImproveStrategy now refuses that
684
+ // name unconditionally, so the override can never apply again. Drop it
685
+ // the same way any other retired key is dropped: only by `akm migrate
686
+ // apply`, never by an ordinary write.
687
+ const strategies = body.improve?.strategies;
688
+ if (strategies && Object.hasOwn(strategies, "graph-refresh"))
689
+ delete strategies["graph-refresh"];
690
+ const keys = [...new Set([...Object.keys(raw), ...Object.keys(body)])]
691
+ .filter((key) => JSON.stringify(raw[key]) !== JSON.stringify(body[key]))
692
+ .sort();
693
+ if (keys.length === 0 || !options.apply)
694
+ return { keys, changed: keys.length > 0, applied: false };
695
+ const backup = backupExistingConfig(configPath);
696
+ writeConfigAtomic(configPath, body);
697
+ cachedConfig = undefined;
698
+ return { keys, changed: true, applied: true, ...(backup ? { backupPath: backup.timestamped } : {}) };
699
+ });
700
+ }
666
701
  /**
667
702
  * Mutate config under one fail-closed lock spanning read, merge, validation,
668
703
  * ordinary backup, and atomic write.
@@ -716,6 +751,61 @@ export async function mutateConfigWithPrecommit(mutate, precommit, options) {
716
751
  release();
717
752
  }
718
753
  }
754
+ const UNBOUND_SCHEDULER_SOURCE_ID = `sha256:${"0".repeat(64)}`;
755
+ /**
756
+ * The source identity 0.9.16 bound a scheduler grant to: the configured
757
+ * bundle's source id, or the implicit `AKM_BUNDLE_DIR` stash's. `undefined`
758
+ * when the bundle is not active on this host.
759
+ */
760
+ export function schedulerSourceIdFor(config, bundleId) {
761
+ if (isBundleEnabled(config, bundleId))
762
+ return bundleSourceId(config, bundleId);
763
+ if (config.bundles?.[bundleId] !== undefined || !process.env.AKM_BUNDLE_DIR?.trim())
764
+ return undefined;
765
+ try {
766
+ const root = resolveStashDir();
767
+ const implicitId = deriveBundleId(undefined, root, new Set(Object.keys(config.bundles ?? {})));
768
+ return implicitId === bundleId ? filesystemBundleSourceId(root) : undefined;
769
+ }
770
+ catch {
771
+ return undefined;
772
+ }
773
+ }
774
+ /**
775
+ * `scheduler.enabled` is a list of refs in memory but is written in the
776
+ * `{kind, ref, sourceId}` shape 0.9.16 reads, so that release still runs
777
+ * against a config this one wrote (the upgrade rehearsal's read-back). This
778
+ * release reads either shape; the object form can go once no supported
779
+ * release is strict about it.
780
+ */
781
+ function schedulerEnabledOnDisk(config) {
782
+ const enabled = config.scheduler?.enabled;
783
+ if (enabled === undefined)
784
+ return undefined;
785
+ return enabled.map((ref) => {
786
+ let bundle;
787
+ let conceptId = "";
788
+ try {
789
+ const parsed = parseBundleRef(ref);
790
+ bundle = parsed.bundle;
791
+ conceptId = parsed.conceptId;
792
+ }
793
+ catch {
794
+ return ref;
795
+ }
796
+ return {
797
+ kind: conceptId.startsWith("workflows/") ? "workflow" : "task",
798
+ ref,
799
+ sourceId: (bundle !== undefined ? schedulerSourceIdFor(config, bundle) : undefined) ?? UNBOUND_SCHEDULER_SOURCE_ID,
800
+ };
801
+ });
802
+ }
803
+ function withSchedulerOnDisk(body, config) {
804
+ const onDisk = schedulerEnabledOnDisk(config);
805
+ if (onDisk === undefined || !isPlainConfigObject(body.scheduler))
806
+ return body;
807
+ return { ...body, scheduler: { ...body.scheduler, enabled: onDisk } };
808
+ }
719
809
  /**
720
810
  * Strip literal apiKey fields before writing config to disk.
721
811
  * API keys are expected to come from environment variables
@@ -780,7 +870,7 @@ export function sanitizeConfigForWrite(config) {
780
870
  warn(`Config sanitizer dropped registry entr${droppedRegistries.length === 1 ? "y" : "ies"} with URL credentials before writing to disk:\n - ${droppedRegistries.join("\n - ")}\n\nRegistry URLs must be credential-free; configure a credential-free HTTPS endpoint.`);
781
871
  }
782
872
  }
783
- return sanitized;
873
+ return withSchedulerOnDisk(sanitized, config);
784
874
  }
785
875
  export function updateConfig(partial) {
786
876
  return mutateConfig((current) => deepMergeConfig(current, partial)).config;
@@ -830,23 +920,6 @@ export function resolveSecret(value, resolveFromStore) {
830
920
  return resolved ?? "";
831
921
  });
832
922
  }
833
- /**
834
- * Read a per-pass {@link IndexPassConfig} entry from {@link IndexConfig},
835
- * filtering out the reserved feature-section keys so callers don't mistake
836
- * `metadataEnhance` for a pass.
837
- */
838
- /** Reserved well-known keys on IndexConfig that are NOT per-pass entries. */
839
- const INDEX_RESERVED_KEYS = new Set(["metadataEnhance"]);
840
- export function getIndexPassConfig(config, passName) {
841
- if (!config)
842
- return undefined;
843
- if (INDEX_RESERVED_KEYS.has(passName))
844
- return undefined;
845
- const entry = config[passName];
846
- if (!entry || typeof entry !== "object")
847
- return undefined;
848
- return entry;
849
- }
850
923
  // Re-export source runtime helpers — implementation lives in config-sources.ts.
851
924
  export { bundleComponentConfig, bundleContentRoot, bundleContentRoots, bundleEntryToSourceEntry, bundleKeyForContentRoot, bundlePhysicalContentRoot, bundleSourceId, bundlesToSourceEntries, installedSourceDescriptor, isBundleEnabled, parseSourceSpec, primaryBundlePath, resolveActiveConfiguredSources, resolveConfiguredSources, } from "./config-sources.js";
852
925
  /**
@@ -6,7 +6,6 @@ export const BUILTIN_IMPROVE_STRATEGY_NAMES = [
6
6
  "default",
7
7
  "quick",
8
8
  "thorough",
9
- "graph-refresh",
10
9
  "consolidate",
11
10
  "catchup",
12
11
  "reflect-distill",
@@ -18,7 +17,6 @@ export const IMPROVE_PROCESS_ENGINE_CAPABILITIES = {
18
17
  distill: "llm",
19
18
  consolidate: "llm",
20
19
  memoryInference: "llm",
21
- graphExtraction: "llm",
22
20
  extract: "llm",
23
21
  validation: "llm",
24
22
  triage: "runner",
@@ -55,20 +55,29 @@ function filesystemLocator(bundle) {
55
55
  return undefined;
56
56
  return path.resolve(bundle.path);
57
57
  }
58
- export function migrateLegacySourceShape(raw, sourcePath) {
59
- const hasStashDir = typeof raw.stashDir === "string" && raw.stashDir.trim().length > 0;
60
- const hasSources = Array.isArray(raw.sources) && raw.sources.length > 0;
58
+ /**
59
+ * Pure legacy `stashDir`/`sources[]`/`installed` -> `bundles`/`defaultBundle`
60
+ * conversion. Triggers on key *presence* (not on the value being usable), so
61
+ * an unusable value — `stashDir: ""`, `sources: []` — is still removed along
62
+ * with the rest of the legacy shape; only a usable `stashDir` or `sources[]`
63
+ * entry is actually folded into `bundles`. Never warns — see
64
+ * {@link migrateLegacySourceShape} for the warn-once wrapper callers use.
65
+ */
66
+ export function convertLegacySourceShape(raw) {
67
+ const hasStashDir = "stashDir" in raw;
68
+ const hasSources = "sources" in raw;
61
69
  const hasInstalled = "installed" in raw && raw.installed !== undefined;
62
70
  if (!hasStashDir && !hasSources && !hasInstalled)
63
- return raw;
71
+ return { config: raw, converted: [] };
64
72
  const { stashDir: _stashDir, sources: _sources, installed: _installed, ...rest } = raw;
65
73
  const bundles = isPlainRecord(rest.bundles) ? { ...rest.bundles } : {};
66
74
  let defaultBundle = typeof rest.defaultBundle === "string" ? rest.defaultBundle : undefined;
67
- if (hasStashDir) {
75
+ const usableStashDir = typeof raw.stashDir === "string" && raw.stashDir.trim().length > 0;
76
+ if (usableStashDir) {
68
77
  bundles.stash = { path: raw.stashDir, writable: true };
69
78
  defaultBundle ??= "stash";
70
79
  }
71
- if (hasSources) {
80
+ if (Array.isArray(raw.sources)) {
72
81
  raw.sources.forEach((entry, index) => {
73
82
  const converted = bundleFromLegacySource(entry, index);
74
83
  if (!converted)
@@ -81,8 +90,28 @@ export function migrateLegacySourceShape(raw, sourcePath) {
81
90
  defaultBundle ??= key;
82
91
  });
83
92
  }
84
- const droppedKeys = [hasStashDir && "stashDir", hasSources && "sources", hasInstalled && "installed"].filter(Boolean);
93
+ const converted = [hasStashDir && "stashDir", hasSources && "sources", hasInstalled && "installed"].filter((key) => typeof key === "string");
94
+ // Only add a `bundles` key when there is something to say: either a
95
+ // legacy entry actually converted into one, or the config already had a
96
+ // `bundles` map (preserved as-is). An unusable `stashDir: ""` / `sources: []`
97
+ // with no pre-existing `bundles` should just disappear, not leave behind
98
+ // an empty `bundles: {}`.
99
+ const hasBundles = Object.keys(bundles).length > 0 || isPlainRecord(rest.bundles);
100
+ return {
101
+ config: { ...rest, ...(hasBundles ? { bundles } : {}), ...(defaultBundle !== undefined ? { defaultBundle } : {}) },
102
+ converted,
103
+ };
104
+ }
105
+ /**
106
+ * Warn-once wrapper around {@link convertLegacySourceShape} for the
107
+ * in-memory read path: converts the legacy shape and, when it removed
108
+ * anything, warns once that `akm migrate apply` will persist the rewrite.
109
+ */
110
+ export function migrateLegacySourceShape(raw, sourcePath) {
111
+ const { config, converted } = convertLegacySourceShape(raw);
112
+ if (converted.length === 0)
113
+ return config;
85
114
  const where = sourcePath ? ` at ${sourcePath}` : "";
86
- warnOnce(`legacy-source-shape${sourcePath ? `:${sourcePath}` : ""}`, `Config${where} uses the retired ${droppedKeys.join("/")} shape — auto-migrated in memory to \`bundles\`/\`defaultBundle\`. Run \`akm migrate apply\` to rewrite the config file and silence this warning.`);
87
- return { ...rest, bundles, ...(defaultBundle !== undefined ? { defaultBundle } : {}) };
115
+ warnOnce(`legacy-source-shape${sourcePath ? `:${sourcePath}` : ""}`, `Config${where} uses the retired ${converted.join("/")} shape — auto-migrated in memory to \`bundles\`/\`defaultBundle\`. Run \`akm migrate apply\` to rewrite the config file and silence this warning.`);
116
+ return config;
88
117
  }
@@ -27,11 +27,7 @@ export const EmbeddingConnectionConfigSchema = z
27
27
  endpoint: z.string().optional(),
28
28
  model: z.string().optional(),
29
29
  apiKey: symbolicOrWarnApiKey("embedding.apiKey").optional(),
30
- // Bounded to the index schema's own vec-table guard (1–4096,
31
- // storage/repositories/index-schema.ts) so an out-of-range dimension
32
- // fails at config validation with a clear message instead of crashing
33
- // `akm index` when ensureSchema rejects it (§24.2 "Semantic" gate).
34
- dimension: positiveInt.max(4096).optional(),
30
+ dimension: positiveInt.optional(),
35
31
  localModel: z.string().min(1).optional(),
36
32
  /**
37
33
  * Per-document token cap applied BEFORE batching (default 512,
@@ -68,6 +64,25 @@ export const EmbeddingConnectionConfigSchema = z
68
64
  * no retry — every batch that hit it was silently dropped (#954).
69
65
  */
70
66
  timeoutMs: positiveInt.optional(),
67
+ /**
68
+ * How long search waits for the query embedding (default 3000,
69
+ * `DEFAULT_QUERY_EMBED_TIMEOUT_MS` in `src/indexer/search/db-search.ts`).
70
+ * On expiry the search is served by keyword ranking alone, with a warning.
71
+ */
72
+ queryTimeoutMs: positiveInt.optional(),
73
+ /**
74
+ * Text sent to the model around a search query, `{text}` marking the
75
+ * query (a template without it is a prefix). Overrides the preset matched
76
+ * on the model name (`src/llm/embedders/profile.ts`); `""` sends the query
77
+ * as is.
78
+ */
79
+ queryTemplate: z.string().optional(),
80
+ /**
81
+ * Text sent to the model around each document at index time, as
82
+ * `queryTemplate`. Part of the embedding fingerprint: changing it
83
+ * re-embeds the index.
84
+ */
85
+ documentTemplate: z.string().optional(),
71
86
  /**
72
87
  * Overrides the fixed in-flight request window (#954, added after field
73
88
  * evidence from multi-slot local servers). Bounded 1-16. Unset keeps
@@ -77,6 +77,11 @@ const LlmEngineSchema = z
77
77
  maxTokens: positiveInt.optional(),
78
78
  timeoutMs: timeoutMsField,
79
79
  concurrency: positiveInt.optional(),
80
+ // Same user-settable override LlmConnectionConfigSchema declares above; a
81
+ // named `kind: "llm"` engine is validated by THIS object, so without the
82
+ // field here the unknown-key walk reported a live setting as unknown and
83
+ // `akm migrate apply` dropped it from config.json.
84
+ supportsJsonSchema: z.boolean().optional(),
80
85
  extraParams: ExtraParamsSchema.optional(),
81
86
  contextLength: positiveInt.optional(),
82
87
  enableThinking: z.boolean().optional(),
@@ -20,4 +20,4 @@ export const ExecutionPolicyConfigSchema = z
20
20
  }
21
21
  }),
22
22
  })
23
- .strict();
23
+ .passthrough();
@@ -27,4 +27,4 @@ export const ExperimentalConfigSchema = z
27
27
  */
28
28
  improveAutonomy: z.boolean().optional(),
29
29
  })
30
- .strict();
30
+ .passthrough();