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

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (381) hide show
  1. package/CHANGELOG.md +715 -0
  2. package/README.md +12 -4
  3. package/dist/akm +38 -0
  4. package/dist/akm-migrate-storage +38 -0
  5. package/dist/assets/help/help-improve.md +9 -6
  6. package/dist/assets/hints/cli-hints-full.md +6 -5
  7. package/dist/assets/profiles/default.json +9 -4
  8. package/dist/assets/profiles/frequent.json +1 -1
  9. package/dist/assets/profiles/memory-focus.json +1 -1
  10. package/dist/assets/profiles/proactive-maintenance.json +25 -0
  11. package/dist/assets/profiles/quick.json +1 -1
  12. package/dist/assets/profiles/recombine-only.json +21 -0
  13. package/dist/assets/profiles/reflect-distill.json +30 -0
  14. package/dist/assets/profiles/synthesize.json +15 -0
  15. package/dist/assets/profiles/thorough.json +1 -1
  16. package/dist/assets/prompts/consolidate-system.md +23 -0
  17. package/dist/assets/prompts/contradiction-judge.md +33 -0
  18. package/dist/assets/prompts/distill-knowledge-system.md +22 -0
  19. package/dist/assets/prompts/distill-lesson-system.md +36 -0
  20. package/dist/assets/prompts/extract-session.md +11 -3
  21. package/dist/assets/prompts/graph-extract-system.md +1 -0
  22. package/dist/assets/prompts/graph-extract-user-prompt.md +1 -1
  23. package/dist/assets/prompts/memory-infer-system.md +1 -0
  24. package/dist/assets/prompts/memory-infer-user.md +5 -0
  25. package/dist/assets/prompts/metadata-enhance-system.md +1 -0
  26. package/dist/assets/prompts/procedural-system.md +44 -0
  27. package/dist/assets/prompts/recombine-system.md +40 -0
  28. package/dist/assets/prompts/staleness-detect-system.md +6 -0
  29. package/dist/assets/prompts/validate-summary-judge.md +1 -0
  30. package/dist/assets/prompts/workflow-unit-preamble.md +26 -0
  31. package/dist/assets/stash-skeleton/facts/conventions/assets/agent.md +38 -0
  32. package/dist/assets/stash-skeleton/facts/conventions/assets/command.md +38 -0
  33. package/dist/assets/stash-skeleton/facts/conventions/assets/fact.md +39 -0
  34. package/dist/assets/stash-skeleton/facts/conventions/assets/knowledge.md +40 -0
  35. package/dist/assets/stash-skeleton/facts/conventions/assets/lesson.md +43 -0
  36. package/dist/assets/stash-skeleton/facts/conventions/assets/memory.md +38 -0
  37. package/dist/assets/stash-skeleton/facts/conventions/assets/script.md +43 -0
  38. package/dist/assets/stash-skeleton/facts/conventions/assets/skill.md +40 -0
  39. package/dist/assets/stash-skeleton/facts/conventions/assets/workflow.md +43 -0
  40. package/dist/assets/templates/html/health.html +281 -111
  41. package/dist/assets/wiki/ingest-workflow-template.md +45 -16
  42. package/dist/assets/wiki/schema-template.md +4 -4
  43. package/dist/cli/clack.js +56 -0
  44. package/dist/cli/config-migrate.js +7 -1
  45. package/dist/cli/confirm.js +1 -1
  46. package/dist/cli/parse-args.js +46 -1
  47. package/dist/cli/shared.js +28 -0
  48. package/dist/cli.js +25 -21
  49. package/dist/commands/agent/agent-dispatch.js +3 -2
  50. package/dist/commands/agent/agent-support.js +0 -7
  51. package/dist/commands/agent/contribute-cli.js +26 -7
  52. package/dist/commands/config-cli.js +26 -13
  53. package/dist/commands/env/child-env.js +47 -0
  54. package/dist/commands/env/env-binding.js +95 -0
  55. package/dist/commands/env/env-cli.js +228 -292
  56. package/dist/commands/env/env.js +14 -67
  57. package/dist/commands/env/secret-cli.js +140 -138
  58. package/dist/commands/feedback-cli.js +156 -155
  59. package/dist/commands/graph/graph-cli.js +5 -13
  60. package/dist/commands/graph/graph.js +3 -3
  61. package/dist/commands/health/advisories.js +151 -0
  62. package/dist/commands/health/checks.js +103 -16
  63. package/dist/commands/health/html-report.js +447 -81
  64. package/dist/commands/health/improve-metrics.js +771 -0
  65. package/dist/commands/health/llm-usage.js +65 -0
  66. package/dist/commands/health/md-report.js +103 -0
  67. package/dist/commands/health/metrics.js +278 -0
  68. package/dist/commands/health/stash-exposure.js +46 -0
  69. package/dist/commands/health/surfaces.js +216 -0
  70. package/dist/commands/health/task-runs.js +135 -0
  71. package/dist/commands/health/types.js +26 -0
  72. package/dist/commands/health/windows.js +195 -0
  73. package/dist/commands/health.js +91 -1091
  74. package/dist/commands/improve/anti-collapse.js +170 -0
  75. package/dist/commands/improve/calibration.js +161 -0
  76. package/dist/commands/improve/collapse-detector.js +421 -0
  77. package/dist/commands/improve/consolidate/chunking.js +141 -0
  78. package/dist/commands/improve/consolidate/eligibility.js +64 -0
  79. package/dist/commands/improve/consolidate/merge.js +145 -0
  80. package/dist/commands/improve/consolidate/sanitize.js +231 -0
  81. package/dist/commands/{lint.js → improve/consolidate/types.js} +1 -1
  82. package/dist/commands/improve/consolidate.js +1295 -1277
  83. package/dist/commands/improve/dedup.js +482 -0
  84. package/dist/commands/improve/distill/content-repair.js +202 -0
  85. package/dist/commands/improve/distill/promote-memory.js +229 -0
  86. package/dist/commands/improve/distill/quality-gate.js +236 -0
  87. package/dist/commands/improve/distill-guards.js +127 -0
  88. package/dist/commands/improve/distill-promotion-policy.js +826 -167
  89. package/dist/commands/improve/distill.js +228 -605
  90. package/dist/commands/improve/eligibility.js +434 -0
  91. package/dist/commands/improve/encoding-salience.js +205 -0
  92. package/dist/commands/improve/extract-cli.js +179 -59
  93. package/dist/commands/improve/extract-prompt.js +54 -3
  94. package/dist/commands/improve/extract-watch.js +140 -0
  95. package/dist/commands/improve/extract.js +409 -43
  96. package/dist/commands/improve/feedback-valence.js +54 -0
  97. package/dist/commands/improve/hot-probation.js +45 -0
  98. package/dist/commands/improve/improve-auto-accept.js +157 -10
  99. package/dist/commands/improve/improve-cli.js +115 -73
  100. package/dist/commands/improve/improve-profiles.js +28 -8
  101. package/dist/commands/improve/improve-result-file.js +15 -25
  102. package/dist/commands/improve/improve-session.js +58 -0
  103. package/dist/commands/improve/improve.js +485 -2764
  104. package/dist/commands/improve/locks.js +154 -0
  105. package/dist/commands/improve/loop-stages.js +1100 -0
  106. package/dist/commands/improve/memory/memory-belief.js +14 -15
  107. package/dist/commands/improve/memory/memory-contradiction-detect.js +83 -60
  108. package/dist/commands/improve/memory/memory-improve.js +27 -27
  109. package/dist/commands/improve/outcome-loop.js +270 -0
  110. package/dist/commands/improve/preparation.js +2002 -0
  111. package/dist/commands/improve/proactive-maintenance.js +37 -35
  112. package/dist/commands/improve/procedural.js +398 -0
  113. package/dist/commands/improve/recombine.js +818 -0
  114. package/dist/commands/improve/reflect-noise.js +0 -0
  115. package/dist/commands/improve/reflect.js +206 -45
  116. package/dist/commands/improve/salience.js +455 -0
  117. package/dist/commands/improve/schema-similarity-gate.js +168 -0
  118. package/dist/commands/improve/shared.js +51 -0
  119. package/dist/commands/improve/triage.js +93 -0
  120. package/dist/commands/lint/agent-linter.js +19 -24
  121. package/dist/commands/lint/base-linter.js +173 -60
  122. package/dist/commands/lint/command-linter.js +19 -24
  123. package/dist/commands/lint/env-key-rules.js +38 -1
  124. package/dist/commands/lint/fact-linter.js +39 -0
  125. package/dist/commands/lint/index.js +31 -13
  126. package/dist/commands/lint/memory-linter.js +1 -1
  127. package/dist/commands/lint/registry.js +7 -2
  128. package/dist/commands/lint/task-linter.js +3 -3
  129. package/dist/commands/lint/workflow-linter.js +26 -1
  130. package/dist/commands/observability-cli.js +4 -4
  131. package/dist/commands/proposal/drain-policies.js +13 -4
  132. package/dist/commands/proposal/drain.js +45 -51
  133. package/dist/commands/proposal/legacy-import.js +115 -0
  134. package/dist/commands/proposal/proposal-cli.js +24 -34
  135. package/dist/commands/proposal/proposal.js +2 -1
  136. package/dist/commands/proposal/propose.js +8 -3
  137. package/dist/commands/proposal/repository.js +829 -0
  138. package/dist/commands/proposal/validators/proposal-quality-validators.js +9 -8
  139. package/dist/commands/proposal/validators/proposals.js +93 -895
  140. package/dist/commands/read/curate.js +410 -111
  141. package/dist/commands/read/knowledge.js +10 -3
  142. package/dist/commands/read/remember-cli.js +133 -138
  143. package/dist/commands/read/search-cli.js +15 -8
  144. package/dist/commands/read/search.js +22 -11
  145. package/dist/commands/read/show.js +106 -14
  146. package/dist/commands/registry-cli.js +76 -87
  147. package/dist/commands/remember.js +11 -12
  148. package/dist/commands/sources/add-cli.js +91 -95
  149. package/dist/commands/sources/history.js +1 -1
  150. package/dist/commands/sources/init.js +66 -18
  151. package/dist/commands/sources/installed-stashes.js +11 -3
  152. package/dist/commands/sources/migration-help.js +7 -4
  153. package/dist/commands/sources/schema-repair.js +44 -46
  154. package/dist/commands/sources/self-update.js +2 -2
  155. package/dist/commands/sources/source-add.js +7 -3
  156. package/dist/commands/sources/sources-cli.js +3 -3
  157. package/dist/commands/sources/stash-cli.js +19 -39
  158. package/dist/commands/sources/stash-skeleton.js +57 -8
  159. package/dist/commands/tasks/default-tasks.js +15 -2
  160. package/dist/commands/tasks/tasks-cli.js +20 -29
  161. package/dist/commands/tasks/tasks.js +39 -11
  162. package/dist/commands/wiki-cli.js +23 -38
  163. package/dist/commands/workflow-cli.js +291 -13
  164. package/dist/core/asset/asset-registry.js +3 -1
  165. package/dist/core/asset/asset-spec.js +79 -5
  166. package/dist/core/asset/frontmatter.js +188 -167
  167. package/dist/core/asset/markdown.js +8 -0
  168. package/dist/core/authoring-rules.js +92 -0
  169. package/dist/core/common.js +4 -23
  170. package/dist/core/concurrent.js +10 -1
  171. package/dist/core/config/config-io.js +10 -1
  172. package/dist/core/config/config-migration.js +18 -40
  173. package/dist/core/config/config-schema.js +403 -62
  174. package/dist/core/config/config-types.js +3 -3
  175. package/dist/core/config/config.js +67 -22
  176. package/dist/core/deep-merge.js +38 -0
  177. package/dist/core/errors.js +1 -0
  178. package/dist/core/eval/rank-metrics.js +113 -0
  179. package/dist/core/events.js +4 -7
  180. package/dist/core/improve-types.js +47 -8
  181. package/dist/core/json-schema.js +142 -0
  182. package/dist/core/logs-db.js +14 -75
  183. package/dist/core/parse.js +36 -16
  184. package/dist/core/paths.js +18 -18
  185. package/dist/core/standards/resolve-standards-context.js +87 -0
  186. package/dist/core/standards/resolve-stash-standards.js +99 -0
  187. package/dist/core/standards/resolve-type-conventions.js +66 -0
  188. package/dist/core/state/migrations.js +770 -0
  189. package/dist/core/state-db.js +132 -1126
  190. package/dist/core/structured.js +69 -0
  191. package/dist/core/time.js +53 -0
  192. package/dist/core/warn.js +21 -0
  193. package/dist/core/write-source.js +37 -0
  194. package/dist/indexer/db/db.js +261 -770
  195. package/dist/indexer/db/entry-mapper.js +41 -0
  196. package/dist/indexer/db/graph-db.js +129 -86
  197. package/dist/indexer/db/llm-cache.js +2 -2
  198. package/dist/indexer/db/schema.js +516 -0
  199. package/dist/indexer/ensure-index.js +36 -92
  200. package/dist/indexer/feedback/utility-policy.js +75 -0
  201. package/dist/indexer/graph/graph-boost.js +51 -41
  202. package/dist/indexer/graph/graph-extraction.js +207 -4
  203. package/dist/indexer/index-writer-lock.js +18 -11
  204. package/dist/indexer/index-written-assets.js +105 -0
  205. package/dist/indexer/indexer.js +182 -204
  206. package/dist/indexer/passes/dir-staleness.js +114 -0
  207. package/dist/indexer/passes/memory-inference.js +13 -5
  208. package/dist/indexer/passes/metadata.js +20 -0
  209. package/dist/indexer/read-preflight.js +23 -0
  210. package/dist/indexer/search/db-search.js +89 -13
  211. package/dist/indexer/search/fts-query.js +51 -0
  212. package/dist/indexer/search/ranking-contributors.js +95 -9
  213. package/dist/indexer/search/ranking.js +79 -3
  214. package/dist/indexer/search/search-fields.js +6 -0
  215. package/dist/indexer/search/search-source.js +32 -21
  216. package/dist/indexer/search/semantic-status.js +4 -0
  217. package/dist/indexer/walk/matchers.js +48 -0
  218. package/dist/indexer/walk/walker.js +21 -13
  219. package/dist/integrations/agent/builders.js +41 -13
  220. package/dist/integrations/agent/config.js +20 -59
  221. package/dist/integrations/agent/detect.js +9 -0
  222. package/dist/integrations/agent/index.js +3 -19
  223. package/dist/integrations/agent/model-aliases.js +16 -2
  224. package/dist/integrations/agent/profiles.js +79 -6
  225. package/dist/integrations/agent/prompts.js +75 -9
  226. package/dist/integrations/agent/runner-dispatch.js +83 -0
  227. package/dist/integrations/agent/runner.js +13 -9
  228. package/dist/integrations/agent/spawn.js +206 -81
  229. package/dist/integrations/harnesses/aider/agent-builder.js +113 -0
  230. package/dist/integrations/harnesses/aider/index.js +58 -0
  231. package/dist/integrations/harnesses/aider/result-extractor.js +53 -0
  232. package/dist/integrations/harnesses/amazonq/agent-builder.js +153 -0
  233. package/dist/integrations/harnesses/amazonq/index.js +59 -0
  234. package/dist/integrations/harnesses/amazonq/result-extractor.js +48 -0
  235. package/dist/integrations/harnesses/claude/agent-builder.js +46 -7
  236. package/dist/integrations/harnesses/claude/index.js +27 -23
  237. package/dist/integrations/harnesses/claude/result-extractor.js +52 -0
  238. package/dist/integrations/harnesses/claude/session-log.js +10 -0
  239. package/dist/integrations/harnesses/codex/agent-builder.js +137 -0
  240. package/dist/integrations/harnesses/codex/index.js +63 -0
  241. package/dist/integrations/harnesses/codex/result-extractor.js +73 -0
  242. package/dist/integrations/harnesses/copilot/agent-builder.js +122 -0
  243. package/dist/integrations/harnesses/copilot/index.js +60 -0
  244. package/dist/integrations/harnesses/copilot/result-extractor.js +151 -0
  245. package/dist/integrations/harnesses/gemini/agent-builder.js +121 -0
  246. package/dist/integrations/harnesses/gemini/index.js +60 -0
  247. package/dist/integrations/harnesses/gemini/result-extractor.js +121 -0
  248. package/dist/integrations/harnesses/index.js +28 -7
  249. package/dist/integrations/harnesses/opencode/agent-builder.js +1 -1
  250. package/dist/integrations/harnesses/opencode/index.js +17 -16
  251. package/dist/integrations/harnesses/opencode/session-log.js +173 -3
  252. package/dist/integrations/harnesses/opencode-sdk/harness.js +65 -0
  253. package/dist/integrations/harnesses/opencode-sdk/index.js +10 -34
  254. package/dist/integrations/harnesses/opencode-sdk/sdk-runner.js +642 -71
  255. package/dist/integrations/harnesses/openhands/agent-builder.js +126 -0
  256. package/dist/integrations/harnesses/openhands/index.js +58 -0
  257. package/dist/integrations/harnesses/openhands/result-extractor.js +103 -0
  258. package/dist/integrations/harnesses/pi/agent-builder.js +104 -0
  259. package/dist/integrations/harnesses/pi/index.js +58 -0
  260. package/dist/integrations/harnesses/pi/result-extractor.js +135 -0
  261. package/dist/integrations/harnesses/types.js +8 -0
  262. package/dist/integrations/session-logs/index.js +40 -11
  263. package/dist/llm/call-ai.js +2 -2
  264. package/dist/llm/client.js +34 -11
  265. package/dist/llm/embedder.js +67 -4
  266. package/dist/llm/embedders/cache.js +3 -1
  267. package/dist/llm/embedders/deterministic.js +66 -0
  268. package/dist/llm/embedders/local.js +73 -3
  269. package/dist/llm/feature-gate.js +16 -15
  270. package/dist/llm/graph-extract.js +67 -44
  271. package/dist/llm/memory-infer-impl.js +138 -0
  272. package/dist/llm/memory-infer.js +1 -127
  273. package/dist/llm/metadata-enhance.js +44 -31
  274. package/dist/llm/structured-call.js +49 -0
  275. package/dist/migrate-storage-node.mjs +8 -0
  276. package/dist/output/context.js +5 -5
  277. package/dist/output/renderers.js +87 -15
  278. package/dist/output/shapes/curate.js +14 -2
  279. package/dist/output/shapes/helpers.js +0 -3
  280. package/dist/output/shapes/passthrough.js +6 -1
  281. package/dist/output/text/helpers.js +241 -2
  282. package/dist/output/text/workflow.js +4 -1
  283. package/dist/registry/providers/skills-sh.js +21 -147
  284. package/dist/registry/providers/static-index.js +15 -157
  285. package/dist/registry/resolve.js +27 -9
  286. package/dist/runtime.js +25 -1
  287. package/dist/schemas/akm-config.json +14225 -0
  288. package/dist/schemas/akm-workflow.json +328 -0
  289. package/dist/scripts/migrate-storage.js +2743 -8390
  290. package/dist/scripts/migrations/import-fs-improve-runs-to-db.js +1652 -607
  291. package/dist/setup/detect.js +9 -0
  292. package/dist/setup/legacy-config.js +106 -0
  293. package/dist/setup/prompt.js +57 -0
  294. package/dist/setup/providers.js +14 -0
  295. package/dist/setup/registry-stash-loader.js +12 -0
  296. package/dist/setup/semantic-assets.js +124 -0
  297. package/dist/setup/setup.js +52 -1614
  298. package/dist/setup/steps/connection.js +734 -0
  299. package/dist/setup/steps/output.js +31 -0
  300. package/dist/setup/steps/platforms.js +124 -0
  301. package/dist/setup/steps/semantic.js +27 -0
  302. package/dist/setup/steps/sources.js +222 -0
  303. package/dist/setup/steps/stashdir.js +42 -0
  304. package/dist/setup/steps/tasks.js +152 -0
  305. package/dist/sources/include.js +6 -2
  306. package/dist/sources/providers/filesystem.js +0 -1
  307. package/dist/sources/providers/git-install.js +210 -0
  308. package/dist/sources/providers/git-provider.js +234 -0
  309. package/dist/sources/providers/git-stash.js +248 -0
  310. package/dist/sources/providers/git.js +10 -661
  311. package/dist/sources/providers/npm.js +2 -6
  312. package/dist/sources/providers/provider-utils.js +13 -7
  313. package/dist/sources/providers/sync-from-ref.js +9 -1
  314. package/dist/sources/providers/website.js +9 -5
  315. package/dist/sources/website-ingest.js +187 -29
  316. package/dist/sources/wiki-fetchers/registry.js +53 -0
  317. package/dist/sources/wiki-fetchers/youtube.js +239 -0
  318. package/dist/storage/database.js +45 -10
  319. package/dist/storage/managed-db.js +82 -0
  320. package/dist/storage/repositories/canaries-repository.js +107 -0
  321. package/dist/storage/repositories/consolidation-repository.js +38 -0
  322. package/dist/storage/repositories/embeddings-repository.js +72 -0
  323. package/dist/storage/repositories/events-repository.js +187 -0
  324. package/dist/storage/repositories/extract-sessions-repository.js +96 -0
  325. package/dist/storage/repositories/improve-runs-repository.js +146 -0
  326. package/dist/storage/repositories/index-db.js +14 -8
  327. package/dist/storage/repositories/proposals-repository.js +220 -0
  328. package/dist/storage/repositories/recombine-repository.js +213 -0
  329. package/dist/storage/repositories/registry-cache.js +93 -0
  330. package/dist/storage/repositories/registry-index-cache-repository.js +46 -0
  331. package/dist/storage/repositories/task-history-repository.js +93 -0
  332. package/dist/storage/repositories/workflow-runs-repository.js +189 -1
  333. package/dist/storage/sqlite-pragmas.js +146 -0
  334. package/dist/tasks/backends/cron.js +1 -1
  335. package/dist/tasks/backends/index.js +9 -0
  336. package/dist/tasks/backends/launchd.js +1 -1
  337. package/dist/tasks/backends/schtasks.js +1 -1
  338. package/dist/tasks/{resolveAkmBin.js → resolve-akm-bin.js} +2 -2
  339. package/dist/tasks/runner.js +15 -13
  340. package/dist/text-import-hook.mjs +1 -1
  341. package/dist/wiki/wiki.js +52 -11
  342. package/dist/workflows/authoring/authoring.js +123 -10
  343. package/dist/workflows/authoring/workflow-program-template.yaml +31 -0
  344. package/dist/workflows/cli.js +5 -0
  345. package/dist/workflows/db.js +138 -4
  346. package/dist/workflows/exec/brief.js +484 -0
  347. package/dist/workflows/exec/native-executor.js +975 -0
  348. package/dist/workflows/exec/param-secrets.js +115 -0
  349. package/dist/workflows/exec/report.js +1295 -0
  350. package/dist/workflows/exec/run-workflow.js +596 -0
  351. package/dist/workflows/exec/scheduler.js +100 -0
  352. package/dist/workflows/exec/step-work.js +1156 -0
  353. package/dist/workflows/exec/unit-writer.js +23 -0
  354. package/dist/workflows/exec/watch.js +116 -0
  355. package/dist/workflows/exec/worktree.js +171 -0
  356. package/dist/workflows/ir/compile.js +388 -0
  357. package/dist/workflows/ir/params.js +54 -0
  358. package/dist/workflows/ir/plan-hash.js +33 -0
  359. package/dist/workflows/ir/schema.js +4 -0
  360. package/dist/workflows/parser.js +3 -1
  361. package/dist/workflows/program/expressions.js +369 -0
  362. package/dist/workflows/program/parser.js +760 -0
  363. package/dist/workflows/program/project.js +105 -0
  364. package/dist/workflows/program/schema.js +54 -0
  365. package/dist/workflows/renderer.js +82 -5
  366. package/dist/workflows/runtime/agent-identity.js +59 -14
  367. package/dist/workflows/runtime/runs.js +248 -153
  368. package/dist/workflows/runtime/unit-checkin.js +45 -0
  369. package/dist/workflows/runtime/workflow-asset-loader.js +188 -0
  370. package/dist/workflows/validate-summary.js +26 -10
  371. package/dist/workflows/validator.js +1 -1
  372. package/docs/README.md +69 -18
  373. package/docs/data-and-telemetry.md +7 -5
  374. package/docs/migration/release-notes/0.7.0.md +1 -1
  375. package/docs/migration/release-notes/0.9.0-beta.60.md +19 -0
  376. package/docs/migration/release-notes/0.9.0.md +39 -0
  377. package/package.json +10 -10
  378. package/dist/assets/tasks/core/update-stashes.yml +0 -4
  379. package/dist/commands/db-cli.js +0 -23
  380. package/dist/indexer/db/db-backup.js +0 -376
  381. package/dist/indexer/passes/staleness-detect.js +0 -488
@@ -1,8 +1,68 @@
1
1
  // This Source Code Form is subject to the terms of the Mozilla Public
2
2
  // License, v. 2.0. If a copy of the MPL was not distributed with this
3
3
  // file, You can obtain one at https://mozilla.org/MPL/2.0/.
4
+ import fs from "node:fs";
5
+ import { makeAssetRef } from "../../core/asset/asset-ref.js";
6
+ import { getStateDbPath } from "../../core/state-db.js";
7
+ import { openDatabase } from "../../storage/database.js";
4
8
  import { getUtilityScoresByIds } from "../db/db.js";
5
- import { applyScoreContributors, applyUtilityContributors } from "./ranking-contributors.js";
9
+ import { applyContributorAblation, applyScoreContributors, applyUtilityContributors, defaultRankingContributors, defaultUtilityRankingContributors, } from "./ranking-contributors.js";
10
+ /**
11
+ * R2 — best-effort load of `asset_salience.rank_score` from state.db for the
12
+ * ranked items. Fail-open: any error (state.db locked by a concurrent improve
13
+ * run, missing table, unreadable path) returns an empty map, which makes the
14
+ * salience contributor a no-op — byte-identical to pre-R2 ranking.
15
+ *
16
+ * Deliberately NOT `openStateDatabase()`: that helper runs migrations and sets
17
+ * a 30 s busy timeout — too heavy for a search hot path. This opens read-only,
18
+ * never creates or migrates state.db (missing file / missing table = empty
19
+ * map), and caps lock waits at 250 ms so a concurrent improve run can only
20
+ * ever cost the search a quarter second, not a stall.
21
+ */
22
+ export function loadSalienceRankScores(items) {
23
+ const result = new Map();
24
+ if (items.length === 0)
25
+ return result;
26
+ try {
27
+ const dbPath = getStateDbPath();
28
+ if (!fs.existsSync(dbPath))
29
+ return result; // improve loop has never run here
30
+ const idByRef = new Map();
31
+ for (const item of items) {
32
+ idByRef.set(makeAssetRef(item.entry.type, item.entry.name), item.id);
33
+ }
34
+ const stateDb = openDatabase(dbPath, { readonly: true });
35
+ try {
36
+ try {
37
+ stateDb.exec("PRAGMA busy_timeout = 250");
38
+ }
39
+ catch {
40
+ // pragma failure on a readonly handle is fine — default timeout applies
41
+ }
42
+ const refs = [...idByRef.keys()];
43
+ const CHUNK = 500;
44
+ for (let i = 0; i < refs.length; i += CHUNK) {
45
+ const chunk = refs.slice(i, i + CHUNK);
46
+ const placeholders = chunk.map(() => "?").join(",");
47
+ const rows = stateDb
48
+ .prepare(`SELECT asset_ref, rank_score FROM asset_salience WHERE asset_ref IN (${placeholders})`)
49
+ .all(...chunk);
50
+ for (const row of rows) {
51
+ const id = idByRef.get(row.asset_ref);
52
+ if (id !== undefined)
53
+ result.set(id, row.rank_score);
54
+ }
55
+ }
56
+ }
57
+ finally {
58
+ stateDb.close();
59
+ }
60
+ }
61
+ catch {
62
+ // Fail open — search must never break because state.db is unavailable.
63
+ }
64
+ return result;
65
+ }
6
66
  export function normalizeFtsScores(results) {
7
67
  const ftsScoreMap = new Map();
8
68
  if (results.length === 0)
@@ -20,6 +80,7 @@ export function normalizeFtsScores(results) {
20
80
  export function combineSearchScores(options) {
21
81
  const FTS_WEIGHT = 0.7;
22
82
  const VEC_WEIGHT = 0.3;
83
+ const excludeTypeSet = options.excludeTypes && options.excludeTypes.length > 0 ? new Set(options.excludeTypes) : null;
23
84
  const scored = [];
24
85
  const seenIds = new Set();
25
86
  for (const [id, { score: ftsScore, result }] of options.ftsScoreMap) {
@@ -42,6 +103,9 @@ export function combineSearchScores(options) {
42
103
  continue;
43
104
  if (options.typeFilter && found.entry.type !== options.typeFilter)
44
105
  continue;
106
+ // #627 — drop vector-only neighbors whose type is excluded on the default path.
107
+ if (excludeTypeSet?.has(found.entry.type))
108
+ continue;
45
109
  scored.push({
46
110
  id,
47
111
  entry: found.entry,
@@ -63,19 +127,31 @@ export function applyRankingRules(options) {
63
127
  graphContext: options.graphContext,
64
128
  projectContext: options.projectContext,
65
129
  };
130
+ // Eval/debug only: AKM_ABLATE_CONTRIBUTORS lets the ablation harness drop
131
+ // named contributors to measure their effect. Resolved once per query;
132
+ // a no-op (full lists) when the env var is unset — see applyContributorAblation.
133
+ const ablateEnv = process.env.AKM_ABLATE_CONTRIBUTORS;
134
+ const activeScoreContributors = applyContributorAblation(defaultRankingContributors, ablateEnv);
135
+ const activeUtilityContributors = applyContributorAblation(defaultUtilityRankingContributors, ablateEnv);
66
136
  for (const item of options.items) {
67
- applyScoreContributors(item, rankingContext);
137
+ applyScoreContributors(item, rankingContext, activeScoreContributors);
68
138
  }
69
139
  const { global: utilScoresMap, scoped: scopedUtilScoresMap } = getUtilityScoresByIds(options.db, options.items.map((item) => item.id), options.scopeKey);
140
+ // R2 — compose the improve loop's salience into user-facing ranking.
141
+ // undefined = load from state.db (default); null = explicitly disabled.
142
+ const salienceRankScores = options.salienceRankScores === null
143
+ ? new Map()
144
+ : (options.salienceRankScores ?? loadSalienceRankScores(options.items));
70
145
  const utilityContext = {
71
146
  ...rankingContext,
72
147
  utilityScores: utilScoresMap,
73
148
  scopedUtilityScores: scopedUtilScoresMap,
74
149
  utilityDecayConfig: options.utilityDecayConfig,
75
150
  positiveFeedbackCounts: options.positiveFeedbackCounts,
151
+ salienceRankScores,
76
152
  };
77
153
  for (const item of options.items) {
78
- applyUtilityContributors(item, utilityContext);
154
+ applyUtilityContributors(item, utilityContext, activeUtilityContributors);
79
155
  }
80
156
  return options.items;
81
157
  }
@@ -11,6 +11,12 @@
11
11
  * - hints: searchHints + examples + usage + intent fields
12
12
  * - content: TOC headings (lowest-weight catch-all)
13
13
  */
14
+ // NOTE (R5): the collapse detector's frozen canary queries are built from the
15
+ // same surface this function indexes (name tokens / tags / description) and
16
+ // scored via FTS against it. Changing what buildSearchFields includes shifts
17
+ // the detector's recall baseline for ALL existing canary sets — coordinate
18
+ // with src/commands/improve/collapse-detector.ts (buildCanaryQuery) and expect
19
+ // operators to re-mint via `akm improve canary --refresh` after such a change.
14
20
  export function buildSearchFields(entry) {
15
21
  const name = entry.name.replace(/[-_]/g, " ").toLowerCase();
16
22
  const description = (entry.description ?? "").toLowerCase();
@@ -10,8 +10,6 @@ import { resolveSourceProviderFactory } from "../../sources/provider-factory.js"
10
10
  // before resolveEntryContentDir() runs.
11
11
  import "../../sources/providers/index.js";
12
12
  import { warn } from "../../core/warn.js";
13
- import { ensureGitMirror, getCachePaths, parseGitRepoUrl } from "../../sources/providers/git.js";
14
- import { ensureWebsiteMirror } from "../../sources/website-ingest.js";
15
13
  // Legacy "context-hub" / "github" type aliases are normalized to "git" at
16
14
  // config-load time (see src/config.ts), so this set only contains the canonical
17
15
  // type.
@@ -169,14 +167,26 @@ export function getWritableStashDirs(overrideStashDir, existingConfig) {
169
167
  }
170
168
  /**
171
169
  * Find which source a file path belongs to.
170
+ *
171
+ * Longest-matching-prefix wins: a source nested inside another (e.g. `akm add
172
+ * ./sub` where `./sub` lives under the primary stash — which is always
173
+ * `sources[0]`) is the more specific owner and must win over the enclosing
174
+ * source regardless of array order. A first-match-in-order scan would
175
+ * misattribute every asset under the nested source to the primary stash,
176
+ * corrupting origin / editability / provenance decisions for the affected files.
172
177
  */
173
178
  export function findSourceForPath(filePath, sources) {
174
179
  const resolved = path.resolve(filePath);
180
+ let best;
181
+ let bestLen = -1;
175
182
  for (const source of sources) {
176
- if (resolved.startsWith(path.resolve(source.path) + path.sep))
177
- return source;
183
+ const base = path.resolve(source.path);
184
+ if (resolved.startsWith(base + path.sep) && base.length > bestLen) {
185
+ best = source;
186
+ bestLen = base.length;
187
+ }
178
188
  }
179
- return undefined;
189
+ return best;
180
190
  }
181
191
  /**
182
192
  * Return the primary stash source (first entry in the list).
@@ -261,31 +271,32 @@ function isValidDirectory(dir) {
261
271
  export async function ensureSourceCaches(config, options) {
262
272
  const cfg = config ?? loadConfig();
263
273
  const force = options?.force === true;
264
- const entries = getSources(cfg);
265
- for (const entry of entries) {
266
- if (!GIT_STASH_TYPES.has(entry.type) || !entry.url || entry.enabled === false)
274
+ // Polymorphic refresh: walk every enabled source through its registered
275
+ // provider and call `sync()`. Every cache-backed kind (git, website, npm)
276
+ // refreshes the same way a bad source warns and is skipped without
277
+ // aborting the others. The git content/-subdir layout convention stays in
278
+ // resolveEntryContentDir.
279
+ for (const entry of getSources(cfg)) {
280
+ if (entry.enabled === false)
281
+ continue;
282
+ const factory = resolveSourceProviderFactory(entry.type);
283
+ if (!factory)
267
284
  continue;
285
+ let provider;
268
286
  try {
269
- const repo = parseGitRepoUrl(entry.url);
270
- const cachePaths = getCachePaths(repo.canonicalUrl);
271
- await ensureGitMirror(repo, cachePaths, {
272
- requireRepoDir: true,
273
- writable: entry.writable === true,
274
- force,
275
- });
287
+ provider = factory(entry);
276
288
  }
277
289
  catch (err) {
278
- warn(`Warning: failed to refresh git mirror for "${entry.url}": ${err instanceof Error ? err.message : String(err)}`);
290
+ warn(`Warning: failed to construct ${entry.type} source provider for "${entry.name ?? entry.url ?? entry.path}": ${err instanceof Error ? err.message : String(err)}`);
291
+ continue;
279
292
  }
280
- }
281
- for (const entry of entries) {
282
- if (entry.type !== "website" || !entry.url || entry.enabled === false)
293
+ if (!provider.sync)
283
294
  continue;
284
295
  try {
285
- await ensureWebsiteMirror(entry, { requireStashDir: true, force });
296
+ await provider.sync({ force });
286
297
  }
287
298
  catch (err) {
288
- warn(`Warning: failed to refresh website stash for "${entry.url}": ${err instanceof Error ? err.message : String(err)}`);
299
+ warn(`Warning: failed to refresh ${provider.kind} source "${provider.name}": ${err instanceof Error ? err.message : String(err)}`);
289
300
  }
290
301
  }
291
302
  }
@@ -4,8 +4,12 @@
4
4
  import fs from "node:fs";
5
5
  import { writeFileAtomic } from "../../core/common.js";
6
6
  import { getCacheDir, getSemanticStatusPath } from "../../core/paths.js";
7
+ import { DETERMINISTIC_EMBED_MODEL_ID, isDeterministicEmbedEnabled } from "../../llm/embedders/deterministic.js";
7
8
  import { DEFAULT_LOCAL_MODEL } from "../../llm/embedders/local.js";
8
9
  export function deriveSemanticProviderFingerprint(embedding) {
10
+ if (isDeterministicEmbedEnabled()) {
11
+ return `deterministic:${DETERMINISTIC_EMBED_MODEL_ID}`;
12
+ }
9
13
  if (embedding?.endpoint) {
10
14
  return `remote:${embedding.endpoint}|${embedding.model}|${embedding.dimension ?? "default"}`;
11
15
  }
@@ -11,6 +11,8 @@
11
11
  import { defaultRendererRegistry } from "../../core/asset/asset-registry.js";
12
12
  import { SCRIPT_EXTENSIONS } from "../../core/asset/asset-spec.js";
13
13
  import { looksLikeWorkflow } from "../../workflows/parser.js";
14
+ import { looksLikeWorkflowProgram } from "../../workflows/program/parser.js";
15
+ import { WORKFLOW_PROGRAM_RENDERER_NAME } from "../../workflows/program/project.js";
14
16
  import { registerMatcher } from "./file-context.js";
15
17
  // ---------------------------------------------------------------------------
16
18
  // Private data
@@ -78,6 +80,15 @@ const DIR_TYPE_MAP = [
78
80
  type: "session",
79
81
  test: (ext) => ext === ".md",
80
82
  },
83
+ {
84
+ // Durable stash-level facts live under `facts/<category>/<name>.md`.
85
+ // classifyByDirectory walks every ancestor dir, so nested category
86
+ // subdirs still match. Without this entry a fact file would fall through
87
+ // to classifyBySmartMd and be mistyped as `knowledge`.
88
+ dir: "facts",
89
+ type: "fact",
90
+ test: (ext) => ext === ".md",
91
+ },
81
92
  ];
82
93
  const COMMAND_PLACEHOLDER_RE = /\$ARGUMENTS|\$[123]\b/;
83
94
  // Files that should never be treated as the typed asset for the surrounding
@@ -169,6 +180,35 @@ function classifyBySmartMd(ctx) {
169
180
  }
170
181
  return { type: "knowledge", specificity: 5 };
171
182
  }
183
+ /** YAML workflow *programs* (redesign addendum, R1): `.yaml`/`.yml` files. */
184
+ const WORKFLOW_PROGRAM_EXTENSIONS = new Set([".yaml", ".yml"]);
185
+ /**
186
+ * Classify YAML workflow programs. Two claims, mirroring the markdown rules:
187
+ *
188
+ * - any `.yaml`/`.yml` under a `workflows/` dir (the directory rule —
189
+ * specificity 15 when `workflows` is the immediate parent, 10 for a
190
+ * deeper ancestor, same ladder as `matchDirectoryHint`);
191
+ * - anywhere else, a content probe via `looksLikeWorkflowProgram`
192
+ * (`version: 1` + `steps:` at column 0) at specificity 19, the same
193
+ * level as `classifyBySmartMd`'s `looksLikeWorkflow` claim.
194
+ *
195
+ * The fact does NOT go through `toMatchResult` — the workflow TYPE maps to
196
+ * the markdown renderer by default, so this classifier names the
197
+ * `workflow-program-yaml` renderer on its result directly.
198
+ */
199
+ function classifyByWorkflowProgram(ctx) {
200
+ if (!WORKFLOW_PROGRAM_EXTENSIONS.has(ctx.ext))
201
+ return null;
202
+ if (isTypedDirDocFile(ctx.fileName))
203
+ return null;
204
+ if (ctx.parentDir === "workflows")
205
+ return { type: "workflow", specificity: 15 };
206
+ if (ctx.ancestorDirs.includes("workflows"))
207
+ return { type: "workflow", specificity: 10 };
208
+ if (looksLikeWorkflowProgram(ctx.content()))
209
+ return { type: "workflow", specificity: 19 };
210
+ return null;
211
+ }
172
212
  function classifyByWiki(ctx) {
173
213
  if (ctx.ext !== ".md")
174
214
  return null;
@@ -214,12 +254,20 @@ export function smartMdMatcher(ctx) {
214
254
  export function wikiMatcher(ctx) {
215
255
  return toMatchResult(ctx, classifyByWiki);
216
256
  }
257
+ export function workflowProgramMatcher(ctx) {
258
+ const fact = classifyByWorkflowProgram(ctx);
259
+ if (!fact)
260
+ return null;
261
+ // Named directly (not via rendererNameFor) — see classifyByWorkflowProgram.
262
+ return { type: fact.type, specificity: fact.specificity, renderer: WORKFLOW_PROGRAM_RENDERER_NAME };
263
+ }
217
264
  const builtinMatchers = [
218
265
  extensionMatcher,
219
266
  directoryMatcher,
220
267
  parentDirHintMatcher,
221
268
  smartMdMatcher,
222
269
  wikiMatcher,
270
+ workflowProgramMatcher,
223
271
  ];
224
272
  export function registerBuiltinMatchers() {
225
273
  for (const matcher of builtinMatchers) {
@@ -148,20 +148,28 @@ function isInsideGitRepo(dir) {
148
148
  * read (e.g. permission errors).
149
149
  */
150
150
  export function* walkMarkdownFiles(root) {
151
- let entries;
152
- try {
153
- entries = fs.readdirSync(root, { withFileTypes: true });
154
- }
155
- catch {
156
- return;
157
- }
158
- for (const entry of entries) {
159
- const full = path.join(root, entry.name);
160
- if (entry.isDirectory()) {
161
- yield* walkMarkdownFiles(full);
151
+ const stack = [root];
152
+ while (stack.length > 0) {
153
+ const current = stack.pop();
154
+ if (!current)
155
+ continue;
156
+ let entries;
157
+ try {
158
+ entries = fs.readdirSync(current, { withFileTypes: true });
162
159
  }
163
- else if (entry.isFile() && entry.name.toLowerCase().endsWith(".md")) {
164
- yield full;
160
+ catch {
161
+ continue;
162
+ }
163
+ for (const entry of entries) {
164
+ const full = path.join(current, entry.name);
165
+ if (entry.isSymbolicLink())
166
+ continue;
167
+ if (entry.isDirectory()) {
168
+ stack.push(full);
169
+ }
170
+ else if (entry.isFile() && entry.name.toLowerCase().endsWith(".md")) {
171
+ yield full;
172
+ }
165
173
  }
166
174
  }
167
175
  }
@@ -12,8 +12,8 @@
12
12
  * Adding a new platform: implement `AgentCommandBuilder`, add to
13
13
  * `BUILTIN_BUILDERS`. Nothing else changes.
14
14
  */
15
- import { claudeBuilder } from "../harnesses/claude/agent-builder.js";
16
- import { opencodeBuilder } from "../harnesses/opencode/agent-builder.js";
15
+ import { ConfigError } from "../../core/errors.js";
16
+ import { HARNESS_REGISTRY } from "../harnesses/index.js";
17
17
  // Types + shared validation helpers live in the leaf module `builder-shared.ts`
18
18
  // so per-harness builders (harnesses/claude/agent-builder.ts) can depend on them
19
19
  // without importing this file back — avoiding an init-order cycle through
@@ -21,6 +21,7 @@ import { opencodeBuilder } from "../harnesses/opencode/agent-builder.js";
21
21
  // sites keep working.
22
22
  import { assertNotFlag } from "./builder-shared.js";
23
23
  import { resolveModel } from "./model-aliases.js";
24
+ import { getBuiltinAgentProfile } from "./profiles.js";
24
25
  export { assertNotFlag, normalizeTools } from "./builder-shared.js";
25
26
  // ── Platform builders ─────────────────────────────────────────────────────────
26
27
  // The OpenCode builder was migrated to its harness directory in #564
@@ -43,7 +44,7 @@ const defaultBuilder = {
43
44
  args.push("--system-prompt", req.systemPrompt);
44
45
  }
45
46
  if (req.model) {
46
- const resolved = resolveModel(req.model, profile.name, profile.modelAliases);
47
+ const resolved = resolveModel(req.model, profile.name, profile.modelAliases, profile.globalModelAliases);
47
48
  args.push("--model", resolved);
48
49
  }
49
50
  args.push("--");
@@ -52,17 +53,44 @@ const defaultBuilder = {
52
53
  },
53
54
  };
54
55
  // ── Registry ──────────────────────────────────────────────────────────────────
55
- const BUILTIN_BUILDERS = {
56
- opencode: opencodeBuilder,
57
- "opencode-headless": opencodeBuilder,
58
- claude: claudeBuilder,
59
- "claude-headless": claudeBuilder,
60
- };
61
56
  /**
62
- * Return the builder for the given platform name, falling back to the default
63
- * builder for unknown platforms. Custom builders injected via tests can be
64
- * passed as `registry`.
57
+ * DERIVED from `HARNESS_REGISTRY` (P0.5 registry-drift fix): each harness that
58
+ * owns an `agentBuilder` is registered under its canonical id, its
59
+ * `<id>-headless` profile variant, and every alias. Previously this was a
60
+ * hand-maintained map that could (and did) drift from the harness registry.
61
+ */
62
+ const BUILTIN_BUILDERS = (() => {
63
+ const registry = {};
64
+ for (const harness of HARNESS_REGISTRY) {
65
+ if (!harness.agentBuilder)
66
+ continue;
67
+ registry[harness.id] = harness.agentBuilder;
68
+ registry[`${harness.id}-headless`] = harness.agentBuilder;
69
+ for (const alias of harness.aliases)
70
+ registry[alias] = harness.agentBuilder;
71
+ }
72
+ return Object.freeze(registry);
73
+ })();
74
+ /**
75
+ * Return the builder for the given platform name.
76
+ *
77
+ * A *custom* profile (unknown platform) falls back to the default builder —
78
+ * that generic `--system-prompt`/`--model`/`--` shape is the documented
79
+ * contract for user-defined wrappers. A *known built-in agent CLI* with no
80
+ * dedicated builder is a loud `ConfigError` instead: the default flag shape
81
+ * is wrong for those CLIs (aider, for one, treats positionals as file names),
82
+ * so the old silent fallback produced a broken command that "ran" and failed
83
+ * downstream. As of the P2 harness-adapter integration every built-in profile
84
+ * has a registry-derived builder, so this branch only fires if a future
85
+ * builtin profile ships without one. Custom builders injected via tests can
86
+ * be passed as `registry`.
65
87
  */
66
88
  export function getCommandBuilder(platform, registry = BUILTIN_BUILDERS) {
67
- return registry[platform] ?? defaultBuilder;
89
+ const found = registry[platform];
90
+ if (found)
91
+ return found;
92
+ if (getBuiltinAgentProfile(platform)) {
93
+ throw new ConfigError(`agent dispatch for "${platform}" is not supported yet: no command builder exists for this CLI, and the generic flag shape would produce a broken command.`, "INVALID_CONFIG_FILE", 'Use an "opencode" or "claude" profile, or — if your CLI is flag-compatible with one of those — set `profiles.agent.<name>.commandBuilder` to "opencode" or "claude".');
94
+ }
95
+ return defaultBuilder;
68
96
  }
@@ -1,9 +1,7 @@
1
1
  // This Source Code Form is subject to the terms of the Mozilla Public
2
2
  // License, v. 2.0. If a copy of the MPL was not distributed with this
3
3
  // file, You can obtain one at https://mozilla.org/MPL/2.0/.
4
- import { VALID_HARNESS_IDS } from "../../core/config/config.js";
5
4
  import { ConfigError } from "../../core/errors.js";
6
- import { warn } from "../../core/warn.js";
7
5
  import { BUILTIN_AGENT_PROFILE_NAMES, getBuiltinAgentProfile, listBuiltinAgentProfiles, } from "./profiles.js";
8
6
  /**
9
7
  * Default hard timeout for an agent CLI (60s — matches the value used in
@@ -15,7 +13,7 @@ export const DEFAULT_AGENT_TIMEOUT_MS = 60_000;
15
13
  * user override (`profiles.agent[name]`) on top of the built-in profile (if
16
14
  * any). Returns `undefined` when neither yields a usable profile.
17
15
  */
18
- export function resolveAgentProfile(name, overrides) {
16
+ export function resolveAgentProfile(name, overrides, globalModelAliases) {
19
17
  const builtin = getBuiltinAgentProfile(name);
20
18
  const platform = overrides?.platform;
21
19
  // For opencode-sdk profiles, allow synthesizing without a built-in.
@@ -32,8 +30,14 @@ export function resolveAgentProfile(name, overrides) {
32
30
  parseOutput: "text",
33
31
  ...(sdkMode ? { sdkMode: true } : {}),
34
32
  };
35
- if (!overrides)
36
- return base;
33
+ if (!overrides) {
34
+ return globalModelAliases ? { ...base, globalModelAliases } : base;
35
+ }
36
+ // Per-profile aliases from config extend (and shadow) the built-in
37
+ // profile's own entries. (Previously always used base.modelAliases, so the
38
+ // documented `profiles.agent.<name>.modelAliases` config was silently
39
+ // dropped — same bug class as the timeoutMs override below.)
40
+ const modelAliases = overrides.modelAliases || base.modelAliases ? { ...base.modelAliases, ...overrides.modelAliases } : undefined;
37
41
  return {
38
42
  name,
39
43
  bin: overrides.bin ?? base.bin,
@@ -41,22 +45,29 @@ export function resolveAgentProfile(name, overrides) {
41
45
  stdio: base.stdio,
42
46
  env: base.env,
43
47
  envPassthrough: base.envPassthrough,
44
- timeoutMs: base.timeoutMs,
48
+ // Honor a user-configured `profiles.agent.<name>.timeoutMs` override; fall
49
+ // back to the built-in profile's value. (Previously always used base, so
50
+ // the documented config override was silently ignored — callers had to pass
51
+ // a CLI flag like `--timeout-ms`.) runAgent (spawn.ts) reads profile.timeoutMs
52
+ // when no per-call timeout is supplied, so this makes the config knob work.
53
+ timeoutMs: overrides.timeoutMs ?? base.timeoutMs,
45
54
  parseOutput: base.parseOutput,
46
55
  ...(sdkMode ? { sdkMode: true } : {}),
47
56
  model: overrides.model ?? base.model,
48
57
  endpoint: base.endpoint,
49
58
  apiKey: base.apiKey,
50
59
  commandBuilder: base.commandBuilder,
51
- modelAliases: base.modelAliases,
60
+ modelAliases,
61
+ ...(globalModelAliases ? { globalModelAliases } : {}),
52
62
  };
53
63
  }
54
64
  /**
55
65
  * Resolve the runnable profile for `name`, or `undefined` if none is
56
- * available (no built-in and no user override).
66
+ * available (no built-in and no user override). Threads the config-root
67
+ * `modelAliases` tier table onto the resolved profile.
57
68
  */
58
69
  export function resolveProfileFromConfig(name, config) {
59
- return resolveAgentProfile(name, config?.profiles?.agent?.[name]);
70
+ return resolveAgentProfile(name, config?.profiles?.agent?.[name], config?.modelAliases);
60
71
  }
61
72
  /**
62
73
  * Return the names of every agent profile available in `config` — built-ins
@@ -134,53 +145,3 @@ export function listResolvedAgentProfiles(config) {
134
145
  }
135
146
  return resolved;
136
147
  }
137
- /**
138
- * Parse the v2 `profiles.agent` map (AgentProfileConfigV2 shape with required
139
- * `platform` field). Returns a map of profile name → AgentProfileConfigV2.
140
- */
141
- export function parseAgentProfilesMapV2(value) {
142
- if (typeof value !== "object" || value === null || Array.isArray(value))
143
- return undefined;
144
- const out = {};
145
- // Derives from the canonical harness-id source of truth (#565).
146
- const VALID_PLATFORMS = VALID_HARNESS_IDS;
147
- for (const [name, raw] of Object.entries(value)) {
148
- if (typeof raw !== "object" || raw === null || Array.isArray(raw)) {
149
- warn(`[akm] Ignoring profiles.agent["${name}"]: expected an object.`);
150
- continue;
151
- }
152
- const obj = raw;
153
- if (!VALID_PLATFORMS.includes(obj.platform)) {
154
- warn(`[akm] Ignoring profiles.agent["${name}"]: missing or invalid "platform" (must be one of: ${VALID_PLATFORMS.join(", ")}).`);
155
- continue;
156
- }
157
- const profile = {
158
- platform: obj.platform,
159
- };
160
- if (typeof obj.bin === "string" && obj.bin.trim())
161
- profile.bin = obj.bin.trim();
162
- if (Array.isArray(obj.args) && obj.args.every((a) => typeof a === "string")) {
163
- profile.args = obj.args;
164
- }
165
- if (typeof obj.workspace === "string" && obj.workspace.trim())
166
- profile.workspace = obj.workspace.trim();
167
- if (typeof obj.model === "string" && obj.model.trim())
168
- profile.model = obj.model.trim();
169
- out[name] = profile;
170
- }
171
- return Object.keys(out).length > 0 ? out : undefined;
172
- }
173
- /**
174
- * Stub kept for source-compat with callers that previously used the v1 agent
175
- * config parser. After 0.8.0 there is no separate `agent` block to parse — the
176
- * loaded `AkmConfig` already carries the agent data on `profiles.agent` and
177
- * `defaults.agent`. This function is a no-op alias for those callers.
178
- *
179
- * @deprecated v0.8.0 — the unified `AkmConfig` IS the agent config. Use the
180
- * profile/defaults accessors above instead.
181
- */
182
- export function parseAgentConfig(_value) {
183
- // No-op: there is no separate agent block in 0.8.0. Callers should pass
184
- // their loaded `AkmConfig` directly to `requireAgentProfile` etc.
185
- return undefined;
186
- }
@@ -55,6 +55,11 @@ export function defaultWhich(bin, envSource = process.env) {
55
55
  }
56
56
  return undefined;
57
57
  }
58
+ let detectOverrides;
59
+ /** TEST-ONLY. Swap the detection implementations; pass undefined to restore. */
60
+ export function _setAgentDetectForTests(fakes) {
61
+ detectOverrides = fakes;
62
+ }
58
63
  /**
59
64
  * Probe every resolvable agent profile (built-ins plus user overrides)
60
65
  * for an installed CLI.
@@ -64,6 +69,8 @@ export function defaultWhich(bin, envSource = process.env) {
64
69
  * @param whichFn Binary lookup. Tests should inject a stub.
65
70
  */
66
71
  export function detectAgentCliProfiles(agent, whichFn = defaultWhich) {
72
+ if (detectOverrides?.detectAgentCliProfiles)
73
+ return detectOverrides.detectAgentCliProfiles(agent, whichFn);
67
74
  const profiles = listResolvedAgentProfiles(agent);
68
75
  return profiles.map((profile) => probeProfile(profile, whichFn));
69
76
  }
@@ -87,6 +94,8 @@ function probeProfile(profile, whichFn) {
87
94
  * writing `agent.default`.
88
95
  */
89
96
  export function pickDefaultAgentProfile(results, existingDefault) {
97
+ if (detectOverrides?.pickDefaultAgentProfile)
98
+ return detectOverrides.pickDefaultAgentProfile(results, existingDefault);
90
99
  if (existingDefault) {
91
100
  const match = results.find((r) => r.name === existingDefault && r.available);
92
101
  if (match)
@@ -1,26 +1,10 @@
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
- * Internal entry point for the `agent` integration. CLI-only project — no
6
- * public exports map. Other akm modules import from this barrel for the
7
- * sake of grouping imports.
8
- *
9
- * Surface:
10
- * • Types: AgentProfile, AgentConfig, AgentRunResult, AgentFailureReason.
11
- * • Profiles: getBuiltinAgentProfile, listBuiltinAgentProfiles, BUILTIN_AGENT_PROFILE_NAMES.
12
- * • Config: parseAgentConfig, resolveProfileFromConfig, requireAgentProfile, listResolvedAgentProfiles, listAgentProfileNames.
13
- * • Spawn: runAgent. Builders: getCommandBuilder, AgentCommandBuilder, AgentDispatchRequest — platform-specific argv construction.
14
- * • Detection: detectAgentCliProfiles, pickDefaultAgentProfile, defaultWhich.
15
- */
16
- // The OpenCode SDK runner moved to its harness directory in #564
17
- // (`harnesses/opencode-sdk/`). Re-exported here so existing `agent/index`
18
- // import sites keep working.
19
- export { runAgentSdk } from "../harnesses/opencode-sdk/index.js";
20
4
  export { getCommandBuilder } from "./builders.js";
21
- export { DEFAULT_AGENT_TIMEOUT_MS, listAgentProfileNames, listResolvedAgentProfiles, parseAgentConfig, requireAgentProfile, resolveAgentProfile, resolveDefaultProfileName, resolveProfileFromConfig, } from "./config.js";
22
- export { defaultWhich, detectAgentCliProfiles, pickDefaultAgentProfile } from "./detect.js";
5
+ export { DEFAULT_AGENT_TIMEOUT_MS, listAgentProfileNames, listResolvedAgentProfiles, requireAgentProfile, resolveAgentProfile, resolveDefaultProfileName, resolveProfileFromConfig, } from "./config.js";
6
+ export { _setAgentDetectForTests, defaultWhich, detectAgentCliProfiles, pickDefaultAgentProfile } from "./detect.js";
23
7
  export { listBuiltinModelAliases, resolveModel } from "./model-aliases.js";
24
8
  export { BUILTIN_AGENT_PROFILE_NAMES, getBuiltinAgentProfile, listBuiltinAgentProfiles, } from "./profiles.js";
25
- export { buildProposePrompt, buildReflectPrompt, buildSchemaRepairPrompt, extractDraftConfidence, parseAgentProposalPayload, stripJsonFences, } from "./prompts.js";
9
+ export { buildProposePrompt, buildReflectPrompt, buildSchemaRepairPrompt, extractDraftConfidence, parseAgentProposalPayload, } from "./prompts.js";
26
10
  export { runAgent } from "./spawn.js";