akm-cli 0.7.0 → 0.7.2

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 (332) hide show
  1. package/CHANGELOG.md +8 -0
  2. package/dist/{src/cli.js → cli.js} +22 -8
  3. package/dist/{src/commands → commands}/installed-stashes.js +1 -1
  4. package/dist/{src/commands → commands}/source-add.js +1 -1
  5. package/dist/{src/core → core}/common.js +16 -1
  6. package/dist/{src/core → core}/config.js +5 -2
  7. package/dist/{src/indexer → indexer}/db-search.js +16 -1
  8. package/dist/{src/indexer → indexer}/graph-extraction.js +5 -3
  9. package/dist/{src/indexer → indexer}/indexer.js +27 -11
  10. package/dist/{src/indexer → indexer}/memory-inference.js +47 -58
  11. package/dist/{src/indexer → indexer}/search-source.js +1 -1
  12. package/dist/{src/llm → llm}/client.js +61 -1
  13. package/dist/{src/llm → llm}/embedder.js +8 -5
  14. package/dist/{src/llm → llm}/embedders/local.js +8 -2
  15. package/dist/{src/llm → llm}/embedders/remote.js +4 -2
  16. package/dist/{src/llm → llm}/graph-extract.js +4 -4
  17. package/dist/llm/memory-infer.js +114 -0
  18. package/dist/{src/llm → llm}/metadata-enhance.js +2 -2
  19. package/dist/{src/output → output}/cli-hints.js +2 -0
  20. package/dist/{src/setup → setup}/setup.js +30 -20
  21. package/dist/sources/providers/website.js +27 -0
  22. package/dist/{src/sources/providers/website.js → sources/website-ingest.js} +38 -51
  23. package/docs/README.md +7 -0
  24. package/docs/migration/release-notes/0.7.0.md +14 -0
  25. package/package.json +11 -8
  26. package/dist/src/llm/memory-infer.js +0 -86
  27. package/dist/tests/add-website-source.test.js +0 -119
  28. package/dist/tests/agent/agent-config-loader.test.js +0 -70
  29. package/dist/tests/agent/agent-config.test.js +0 -221
  30. package/dist/tests/agent/agent-detect.test.js +0 -100
  31. package/dist/tests/agent/agent-spawn.test.js +0 -234
  32. package/dist/tests/agent-output.test.js +0 -186
  33. package/dist/tests/architecture/agent-no-llm-sdk-guard.test.js +0 -103
  34. package/dist/tests/architecture/agent-spawn-seam.test.js +0 -193
  35. package/dist/tests/architecture/llm-stateless-seam.test.js +0 -112
  36. package/dist/tests/asset-ref.test.js +0 -192
  37. package/dist/tests/asset-registry.test.js +0 -103
  38. package/dist/tests/asset-spec.test.js +0 -241
  39. package/dist/tests/bench/attribution.test.js +0 -996
  40. package/dist/tests/bench/cleanup-sigint.test.js +0 -83
  41. package/dist/tests/bench/cleanup.js +0 -234
  42. package/dist/tests/bench/cleanup.test.js +0 -166
  43. package/dist/tests/bench/cli.js +0 -1018
  44. package/dist/tests/bench/cli.test.js +0 -445
  45. package/dist/tests/bench/compare.test.js +0 -556
  46. package/dist/tests/bench/corpus.js +0 -317
  47. package/dist/tests/bench/corpus.test.js +0 -258
  48. package/dist/tests/bench/doctor.js +0 -525
  49. package/dist/tests/bench/driver.js +0 -401
  50. package/dist/tests/bench/driver.test.js +0 -584
  51. package/dist/tests/bench/environment.js +0 -233
  52. package/dist/tests/bench/environment.test.js +0 -199
  53. package/dist/tests/bench/evolve-metrics.js +0 -179
  54. package/dist/tests/bench/evolve-metrics.test.js +0 -187
  55. package/dist/tests/bench/evolve.js +0 -647
  56. package/dist/tests/bench/evolve.test.js +0 -624
  57. package/dist/tests/bench/failure-modes.test.js +0 -349
  58. package/dist/tests/bench/feedback-integrity.test.js +0 -457
  59. package/dist/tests/bench/leakage.test.js +0 -228
  60. package/dist/tests/bench/learning-curve.test.js +0 -134
  61. package/dist/tests/bench/metrics.js +0 -2395
  62. package/dist/tests/bench/metrics.test.js +0 -1150
  63. package/dist/tests/bench/no-os-tmpdir-invariant.test.js +0 -43
  64. package/dist/tests/bench/opencode-config.js +0 -194
  65. package/dist/tests/bench/opencode-config.test.js +0 -370
  66. package/dist/tests/bench/report.js +0 -1885
  67. package/dist/tests/bench/report.test.js +0 -1038
  68. package/dist/tests/bench/run-config.js +0 -355
  69. package/dist/tests/bench/run-config.test.js +0 -298
  70. package/dist/tests/bench/run-curate-test.js +0 -32
  71. package/dist/tests/bench/run-failing-tasks.js +0 -56
  72. package/dist/tests/bench/run-full-bench.js +0 -51
  73. package/dist/tests/bench/run-items36-targeted.js +0 -69
  74. package/dist/tests/bench/run-nano-quick.js +0 -42
  75. package/dist/tests/bench/run-waveg-targeted.js +0 -62
  76. package/dist/tests/bench/runner.js +0 -699
  77. package/dist/tests/bench/runner.test.js +0 -958
  78. package/dist/tests/bench/search-bridge.test.js +0 -331
  79. package/dist/tests/bench/tmp.js +0 -131
  80. package/dist/tests/bench/trajectory.js +0 -116
  81. package/dist/tests/bench/trajectory.test.js +0 -127
  82. package/dist/tests/bench/verifier.js +0 -114
  83. package/dist/tests/bench/verifier.test.js +0 -118
  84. package/dist/tests/bench/workflow-evaluator.js +0 -557
  85. package/dist/tests/bench/workflow-evaluator.test.js +0 -421
  86. package/dist/tests/bench/workflow-spec.js +0 -345
  87. package/dist/tests/bench/workflow-spec.test.js +0 -363
  88. package/dist/tests/bench/workflow-trace.js +0 -472
  89. package/dist/tests/bench/workflow-trace.test.js +0 -254
  90. package/dist/tests/benchmark-search-quality.js +0 -536
  91. package/dist/tests/benchmark-suite.js +0 -1441
  92. package/dist/tests/capture-cli.test.js +0 -112
  93. package/dist/tests/cli-errors.test.js +0 -204
  94. package/dist/tests/commands/events.test.js +0 -370
  95. package/dist/tests/commands/history.test.js +0 -418
  96. package/dist/tests/commands/import.test.js +0 -103
  97. package/dist/tests/commands/proposal-cli.test.js +0 -209
  98. package/dist/tests/commands/reflect-propose-cli.test.js +0 -333
  99. package/dist/tests/commands/remember.test.js +0 -97
  100. package/dist/tests/commands/scope-flags.test.js +0 -300
  101. package/dist/tests/commands/search.test.js +0 -537
  102. package/dist/tests/commands/show-indexer-parity.test.js +0 -117
  103. package/dist/tests/commands/show.test.js +0 -294
  104. package/dist/tests/common.test.js +0 -266
  105. package/dist/tests/completions.test.js +0 -142
  106. package/dist/tests/config-cli.test.js +0 -193
  107. package/dist/tests/config-llm-features.test.js +0 -139
  108. package/dist/tests/config.test.js +0 -569
  109. package/dist/tests/contracts/migration-baseline.test.js +0 -43
  110. package/dist/tests/contracts/reflect-propose-envelope.test.js +0 -139
  111. package/dist/tests/contracts/spec-helpers.js +0 -46
  112. package/dist/tests/contracts/v1-spec-section-11-proposal-queue.test.js +0 -228
  113. package/dist/tests/contracts/v1-spec-section-12-agent-config.test.js +0 -56
  114. package/dist/tests/contracts/v1-spec-section-13-lesson-type.test.js +0 -34
  115. package/dist/tests/contracts/v1-spec-section-14-llm-features.test.js +0 -94
  116. package/dist/tests/contracts/v1-spec-section-4-1-asset-types.test.js +0 -39
  117. package/dist/tests/contracts/v1-spec-section-4-2-quality-rules.test.js +0 -44
  118. package/dist/tests/contracts/v1-spec-section-5-configuration.test.js +0 -47
  119. package/dist/tests/contracts/v1-spec-section-6-orchestration.test.js +0 -40
  120. package/dist/tests/contracts/v1-spec-section-7-module-layout.test.js +0 -58
  121. package/dist/tests/contracts/v1-spec-section-8-extension-points.test.js +0 -34
  122. package/dist/tests/contracts/v1-spec-section-9-4-cli-surface.test.js +0 -75
  123. package/dist/tests/contracts/v1-spec-section-9-7-llm-agent-boundary.test.js +0 -36
  124. package/dist/tests/core/write-source.test.js +0 -366
  125. package/dist/tests/curate-command.test.js +0 -87
  126. package/dist/tests/db-scoring.test.js +0 -201
  127. package/dist/tests/db.test.js +0 -654
  128. package/dist/tests/distill-cli-flag.test.js +0 -208
  129. package/dist/tests/distill.test.js +0 -515
  130. package/dist/tests/docker-install.test.js +0 -120
  131. package/dist/tests/e2e.test.js +0 -1419
  132. package/dist/tests/embedder.test.js +0 -340
  133. package/dist/tests/embedding-model-config.test.js +0 -379
  134. package/dist/tests/feedback-command.test.js +0 -172
  135. package/dist/tests/file-context.test.js +0 -552
  136. package/dist/tests/fixtures/scripts/git/summarize-diff.js +0 -9
  137. package/dist/tests/fixtures/scripts/lint/eslint-check.js +0 -7
  138. package/dist/tests/fixtures/stashes/load.js +0 -166
  139. package/dist/tests/fixtures/stashes/load.test.js +0 -97
  140. package/dist/tests/fixtures/stashes/ranking-baseline/scripts/mem0-search.js +0 -12
  141. package/dist/tests/frontmatter.test.js +0 -190
  142. package/dist/tests/fts-field-weighting.test.js +0 -254
  143. package/dist/tests/fuzzy-search.test.js +0 -230
  144. package/dist/tests/git-provider-clone.test.js +0 -45
  145. package/dist/tests/github.test.js +0 -161
  146. package/dist/tests/graph-boost-ranking.test.js +0 -305
  147. package/dist/tests/graph-extraction.test.js +0 -282
  148. package/dist/tests/helpers/usage-events.js +0 -8
  149. package/dist/tests/index-pass-llm.test.js +0 -161
  150. package/dist/tests/indexer.test.js +0 -570
  151. package/dist/tests/info-command.test.js +0 -166
  152. package/dist/tests/init.test.js +0 -69
  153. package/dist/tests/install-script.test.js +0 -246
  154. package/dist/tests/integration/agent-real-profile.test.js +0 -94
  155. package/dist/tests/issue-36-repro.test.js +0 -304
  156. package/dist/tests/issues-191-194.test.js +0 -160
  157. package/dist/tests/lesson-lint.test.js +0 -111
  158. package/dist/tests/llm-client.test.js +0 -115
  159. package/dist/tests/llm-feature-gate.test.js +0 -151
  160. package/dist/tests/llm.test.js +0 -139
  161. package/dist/tests/lockfile.test.js +0 -216
  162. package/dist/tests/manifest.test.js +0 -205
  163. package/dist/tests/markdown.test.js +0 -126
  164. package/dist/tests/matchers-unit.test.js +0 -189
  165. package/dist/tests/memory-inference.test.js +0 -299
  166. package/dist/tests/merge-scoring.test.js +0 -136
  167. package/dist/tests/metadata.test.js +0 -313
  168. package/dist/tests/migration-help.test.js +0 -89
  169. package/dist/tests/origin-resolve.test.js +0 -124
  170. package/dist/tests/output-baseline.test.js +0 -218
  171. package/dist/tests/output-shapes-unit.test.js +0 -478
  172. package/dist/tests/parallel-search.test.js +0 -272
  173. package/dist/tests/parameter-metadata.test.js +0 -365
  174. package/dist/tests/paths.test.js +0 -177
  175. package/dist/tests/progressive-disclosure.test.js +0 -280
  176. package/dist/tests/proposals.test.js +0 -279
  177. package/dist/tests/proposed-quality.test.js +0 -271
  178. package/dist/tests/provider-registry.test.js +0 -32
  179. package/dist/tests/ranking-regression.test.js +0 -548
  180. package/dist/tests/reflect-propose.test.js +0 -455
  181. package/dist/tests/registry-build-index.test.js +0 -394
  182. package/dist/tests/registry-cli.test.js +0 -290
  183. package/dist/tests/registry-index-v2.test.js +0 -430
  184. package/dist/tests/registry-install.test.js +0 -728
  185. package/dist/tests/registry-providers/parity.test.js +0 -189
  186. package/dist/tests/registry-providers/skills-sh.test.js +0 -309
  187. package/dist/tests/registry-providers/static-index.test.js +0 -238
  188. package/dist/tests/registry-resolve.test.js +0 -126
  189. package/dist/tests/registry-search.test.js +0 -923
  190. package/dist/tests/remember-frontmatter.test.js +0 -378
  191. package/dist/tests/remember-unit.test.js +0 -123
  192. package/dist/tests/ripgrep-install.test.js +0 -251
  193. package/dist/tests/ripgrep-resolve.test.js +0 -108
  194. package/dist/tests/ripgrep.test.js +0 -163
  195. package/dist/tests/save-command.test.js +0 -94
  196. package/dist/tests/save-trust-qa-fixes.test.js +0 -270
  197. package/dist/tests/scoring-pipeline.test.js +0 -648
  198. package/dist/tests/search-include-proposed-cli.test.js +0 -118
  199. package/dist/tests/self-update.test.js +0 -442
  200. package/dist/tests/semantic-search-e2e.test.js +0 -512
  201. package/dist/tests/semantic-status.test.js +0 -471
  202. package/dist/tests/setup-run.integration.js +0 -877
  203. package/dist/tests/setup-wizard.test.js +0 -198
  204. package/dist/tests/setup.test.js +0 -131
  205. package/dist/tests/source-add.test.js +0 -11
  206. package/dist/tests/source-clone.test.js +0 -254
  207. package/dist/tests/source-manage.test.js +0 -366
  208. package/dist/tests/source-providers/filesystem.test.js +0 -82
  209. package/dist/tests/source-providers/git.test.js +0 -252
  210. package/dist/tests/source-providers/website.test.js +0 -128
  211. package/dist/tests/source-qa-fixes.test.js +0 -286
  212. package/dist/tests/source-registry.test.js +0 -350
  213. package/dist/tests/source-resolve.test.js +0 -100
  214. package/dist/tests/source-source.test.js +0 -281
  215. package/dist/tests/source.test.js +0 -533
  216. package/dist/tests/tar-utils-scan.test.js +0 -73
  217. package/dist/tests/toggle-components.test.js +0 -73
  218. package/dist/tests/usage-telemetry.test.js +0 -265
  219. package/dist/tests/utility-scoring.test.js +0 -558
  220. package/dist/tests/vault-load-error.test.js +0 -78
  221. package/dist/tests/vault-qa-fixes.test.js +0 -194
  222. package/dist/tests/vault.test.js +0 -429
  223. package/dist/tests/vector-search.test.js +0 -608
  224. package/dist/tests/walker.test.js +0 -252
  225. package/dist/tests/wave2-cluster-bc.test.js +0 -228
  226. package/dist/tests/wave2-cluster-d.test.js +0 -180
  227. package/dist/tests/wave2-cluster-e.test.js +0 -179
  228. package/dist/tests/wiki-qa-fixes.test.js +0 -270
  229. package/dist/tests/wiki.test.js +0 -529
  230. package/dist/tests/workflow-cli.test.js +0 -271
  231. package/dist/tests/workflow-markdown.test.js +0 -171
  232. package/dist/tests/workflow-path-escape.test.js +0 -132
  233. package/dist/tests/workflow-qa-fixes.test.js +0 -395
  234. package/dist/tests/workflows/indexer-rejection.test.js +0 -213
  235. /package/dist/{src/commands → commands}/completions.js +0 -0
  236. /package/dist/{src/commands → commands}/config-cli.js +0 -0
  237. /package/dist/{src/commands → commands}/curate.js +0 -0
  238. /package/dist/{src/commands → commands}/distill.js +0 -0
  239. /package/dist/{src/commands → commands}/events.js +0 -0
  240. /package/dist/{src/commands → commands}/history.js +0 -0
  241. /package/dist/{src/commands → commands}/info.js +0 -0
  242. /package/dist/{src/commands → commands}/init.js +0 -0
  243. /package/dist/{src/commands → commands}/install-audit.js +0 -0
  244. /package/dist/{src/commands → commands}/migration-help.js +0 -0
  245. /package/dist/{src/commands → commands}/proposal.js +0 -0
  246. /package/dist/{src/commands → commands}/propose.js +0 -0
  247. /package/dist/{src/commands → commands}/reflect.js +0 -0
  248. /package/dist/{src/commands → commands}/registry-search.js +0 -0
  249. /package/dist/{src/commands → commands}/remember.js +0 -0
  250. /package/dist/{src/commands → commands}/search.js +0 -0
  251. /package/dist/{src/commands → commands}/self-update.js +0 -0
  252. /package/dist/{src/commands → commands}/show.js +0 -0
  253. /package/dist/{src/commands → commands}/source-clone.js +0 -0
  254. /package/dist/{src/commands → commands}/source-manage.js +0 -0
  255. /package/dist/{src/commands → commands}/vault.js +0 -0
  256. /package/dist/{src/core → core}/asset-ref.js +0 -0
  257. /package/dist/{src/core → core}/asset-registry.js +0 -0
  258. /package/dist/{src/core → core}/asset-spec.js +0 -0
  259. /package/dist/{src/core → core}/errors.js +0 -0
  260. /package/dist/{src/core → core}/events.js +0 -0
  261. /package/dist/{src/core → core}/frontmatter.js +0 -0
  262. /package/dist/{src/core → core}/lesson-lint.js +0 -0
  263. /package/dist/{src/core → core}/markdown.js +0 -0
  264. /package/dist/{src/core → core}/paths.js +0 -0
  265. /package/dist/{src/core → core}/proposals.js +0 -0
  266. /package/dist/{src/core → core}/warn.js +0 -0
  267. /package/dist/{src/core → core}/write-source.js +0 -0
  268. /package/dist/{src/indexer → indexer}/db.js +0 -0
  269. /package/dist/{src/indexer → indexer}/file-context.js +0 -0
  270. /package/dist/{src/indexer → indexer}/graph-boost.js +0 -0
  271. /package/dist/{src/indexer → indexer}/manifest.js +0 -0
  272. /package/dist/{src/indexer → indexer}/matchers.js +0 -0
  273. /package/dist/{src/indexer → indexer}/metadata.js +0 -0
  274. /package/dist/{src/indexer → indexer}/search-fields.js +0 -0
  275. /package/dist/{src/indexer → indexer}/semantic-status.js +0 -0
  276. /package/dist/{src/indexer → indexer}/usage-events.js +0 -0
  277. /package/dist/{src/indexer → indexer}/walker.js +0 -0
  278. /package/dist/{src/integrations → integrations}/agent/config.js +0 -0
  279. /package/dist/{src/integrations → integrations}/agent/detect.js +0 -0
  280. /package/dist/{src/integrations → integrations}/agent/index.js +0 -0
  281. /package/dist/{src/integrations → integrations}/agent/profiles.js +0 -0
  282. /package/dist/{src/integrations → integrations}/agent/prompts.js +0 -0
  283. /package/dist/{src/integrations → integrations}/agent/spawn.js +0 -0
  284. /package/dist/{src/integrations → integrations}/github.js +0 -0
  285. /package/dist/{src/integrations → integrations}/lockfile.js +0 -0
  286. /package/dist/{src/llm → llm}/embedders/cache.js +0 -0
  287. /package/dist/{src/llm → llm}/embedders/types.js +0 -0
  288. /package/dist/{src/llm → llm}/feature-gate.js +0 -0
  289. /package/dist/{src/llm → llm}/index-passes.js +0 -0
  290. /package/dist/{src/output → output}/context.js +0 -0
  291. /package/dist/{src/output → output}/renderers.js +0 -0
  292. /package/dist/{src/output → output}/shapes.js +0 -0
  293. /package/dist/{src/output → output}/text.js +0 -0
  294. /package/dist/{src/registry → registry}/build-index.js +0 -0
  295. /package/dist/{src/registry → registry}/create-provider-registry.js +0 -0
  296. /package/dist/{src/registry → registry}/factory.js +0 -0
  297. /package/dist/{src/registry → registry}/origin-resolve.js +0 -0
  298. /package/dist/{src/registry → registry}/providers/index.js +0 -0
  299. /package/dist/{src/registry → registry}/providers/skills-sh.js +0 -0
  300. /package/dist/{src/registry → registry}/providers/static-index.js +0 -0
  301. /package/dist/{src/registry → registry}/providers/types.js +0 -0
  302. /package/dist/{src/registry → registry}/resolve.js +0 -0
  303. /package/dist/{src/registry → registry}/types.js +0 -0
  304. /package/dist/{src/setup → setup}/detect.js +0 -0
  305. /package/dist/{src/setup → setup}/ripgrep-install.js +0 -0
  306. /package/dist/{src/setup → setup}/ripgrep-resolve.js +0 -0
  307. /package/dist/{src/setup → setup}/steps.js +0 -0
  308. /package/dist/{src/sources → sources}/include.js +0 -0
  309. /package/dist/{src/sources → sources}/provider-factory.js +0 -0
  310. /package/dist/{src/sources → sources}/provider.js +0 -0
  311. /package/dist/{src/sources → sources}/providers/filesystem.js +0 -0
  312. /package/dist/{src/sources → sources}/providers/git.js +0 -0
  313. /package/dist/{src/sources → sources}/providers/index.js +0 -0
  314. /package/dist/{src/sources → sources}/providers/install-types.js +0 -0
  315. /package/dist/{src/sources → sources}/providers/npm.js +0 -0
  316. /package/dist/{src/sources → sources}/providers/provider-utils.js +0 -0
  317. /package/dist/{src/sources → sources}/providers/sync-from-ref.js +0 -0
  318. /package/dist/{src/sources → sources}/providers/tar-utils.js +0 -0
  319. /package/dist/{src/sources → sources}/resolve.js +0 -0
  320. /package/dist/{src/sources → sources}/types.js +0 -0
  321. /package/dist/{src/templates → templates}/wiki-templates.js +0 -0
  322. /package/dist/{src/version.js → version.js} +0 -0
  323. /package/dist/{src/wiki → wiki}/wiki.js +0 -0
  324. /package/dist/{src/workflows → workflows}/authoring.js +0 -0
  325. /package/dist/{src/workflows → workflows}/cli.js +0 -0
  326. /package/dist/{src/workflows → workflows}/db.js +0 -0
  327. /package/dist/{src/workflows → workflows}/document-cache.js +0 -0
  328. /package/dist/{src/workflows → workflows}/parser.js +0 -0
  329. /package/dist/{src/workflows → workflows}/renderer.js +0 -0
  330. /package/dist/{src/workflows → workflows}/runs.js +0 -0
  331. /package/dist/{src/workflows → workflows}/schema.js +0 -0
  332. /package/dist/{src/workflows → workflows}/validator.js +0 -0
@@ -1,221 +0,0 @@
1
- /**
2
- * Tests for the `agent.*` config block parser and profile resolver.
3
- *
4
- * Acceptance coverage:
5
- * • Parser accepts the documented shape.
6
- * • Unknown keys are warn-and-ignored (no throw).
7
- * • Built-in profiles resolve for opencode, claude, codex, gemini, aider.
8
- * • Missing block surfaces a stable ConfigError via requireAgentProfile.
9
- */
10
- import { afterEach, beforeEach, describe, expect, mock, test } from "bun:test";
11
- const warnings = [];
12
- // NOTE: `mock.module` in Bun is process-global — once installed it persists
13
- // across test files run in the same `bun test` invocation. So this mock has
14
- // to remain a faithful drop-in for the real `src/core/warn` module:
15
- //
16
- // 1. Every export that the real module ships must be represented here,
17
- // otherwise tests in other files that import a missing export get
18
- // `undefined` and silently break (issue #273).
19
- // 2. `warn()` must also forward to `console.warn` so other test files that
20
- // capture stderr (e.g. the noise-gate tests in
21
- // tests/workflows/indexer-rejection.test.ts) continue to see the calls.
22
- // We push to the local `warnings[]` so this file's own assertions still
23
- // work, AND forward to `console.warn` so callers that intercept it
24
- // still observe what was emitted.
25
- let mockedQuiet = false;
26
- let mockedVerbose = false;
27
- mock.module("../../src/core/warn", () => ({
28
- warn: (...args) => {
29
- warnings.push(args.join(" "));
30
- if (!mockedQuiet)
31
- console.warn(...args);
32
- },
33
- warnVerbose: (...args) => {
34
- if (!mockedVerbose)
35
- return;
36
- warnings.push(args.join(" "));
37
- if (!mockedQuiet)
38
- console.warn(...args);
39
- },
40
- setQuiet: (value) => {
41
- mockedQuiet = value;
42
- },
43
- resetQuiet: () => {
44
- mockedQuiet = false;
45
- },
46
- isQuiet: () => mockedQuiet,
47
- setVerbose: (value) => {
48
- mockedVerbose = value;
49
- },
50
- resetVerbose: () => {
51
- mockedVerbose = false;
52
- },
53
- isVerbose: () => {
54
- const env = process.env.AKM_VERBOSE?.trim().toLowerCase();
55
- if (env === "1" || env === "true" || env === "yes" || env === "on")
56
- return true;
57
- if (env === "0" || env === "false" || env === "no" || env === "off")
58
- return false;
59
- return mockedVerbose;
60
- },
61
- }));
62
- beforeEach(() => {
63
- warnings.length = 0;
64
- });
65
- afterEach(() => {
66
- warnings.length = 0;
67
- });
68
- describe("parseAgentConfig", () => {
69
- test("returns undefined when block is absent", async () => {
70
- const { parseAgentConfig } = await import("../../src/integrations/agent/config");
71
- expect(parseAgentConfig(undefined)).toBeUndefined();
72
- expect(warnings).toHaveLength(0);
73
- });
74
- test("warns and returns undefined for non-object root", async () => {
75
- const { parseAgentConfig } = await import("../../src/integrations/agent/config");
76
- expect(parseAgentConfig("oops")).toBeUndefined();
77
- expect(warnings.some((w) => w.includes('"agent"'))).toBe(true);
78
- });
79
- test("accepts the documented shape", async () => {
80
- const { parseAgentConfig } = await import("../../src/integrations/agent/config");
81
- const parsed = parseAgentConfig({
82
- default: "opencode",
83
- timeoutMs: 30000,
84
- profiles: {
85
- opencode: { bin: "opencode", args: ["--non-interactive"], stdio: "captured" },
86
- },
87
- });
88
- expect(parsed?.default).toBe("opencode");
89
- expect(parsed?.timeoutMs).toBe(30000);
90
- expect(parsed?.profiles?.opencode).toEqual({
91
- bin: "opencode",
92
- args: ["--non-interactive"],
93
- stdio: "captured",
94
- });
95
- });
96
- test("warn-and-ignore unknown top-level keys (no throw)", async () => {
97
- const { parseAgentConfig } = await import("../../src/integrations/agent/config");
98
- const parsed = parseAgentConfig({
99
- default: "claude",
100
- moonRoutingTable: { foo: "bar" }, // unknown
101
- });
102
- expect(parsed?.default).toBe("claude");
103
- expect(warnings.some((w) => w.includes("moonRoutingTable"))).toBe(true);
104
- });
105
- test("warn-and-ignore unknown per-profile keys", async () => {
106
- const { parseAgentConfig } = await import("../../src/integrations/agent/config");
107
- const parsed = parseAgentConfig({
108
- profiles: {
109
- custom: { bin: "ok", quirks: "nope" },
110
- },
111
- });
112
- expect(parsed?.profiles?.custom?.bin).toBe("ok");
113
- expect(warnings.some((w) => w.includes("quirks"))).toBe(true);
114
- });
115
- test("warn-and-ignore malformed timeoutMs", async () => {
116
- const { parseAgentConfig } = await import("../../src/integrations/agent/config");
117
- const parsed = parseAgentConfig({ timeoutMs: "60s" });
118
- expect(parsed?.timeoutMs).toBeUndefined();
119
- expect(warnings.some((w) => w.includes("timeoutMs"))).toBe(true);
120
- });
121
- test("rejects non-string args entries", async () => {
122
- const { parseAgentConfig } = await import("../../src/integrations/agent/config");
123
- const parsed = parseAgentConfig({
124
- profiles: { opencode: { args: ["--ok", 5, "--also-ok"] } },
125
- });
126
- expect(parsed?.profiles?.opencode?.args).toEqual(["--ok", "--also-ok"]);
127
- expect(warnings.some((w) => w.includes("args"))).toBe(true);
128
- });
129
- test("rejects bad stdio mode", async () => {
130
- const { parseAgentConfig } = await import("../../src/integrations/agent/config");
131
- const parsed = parseAgentConfig({
132
- profiles: { opencode: { stdio: "weird" } },
133
- });
134
- expect(parsed?.profiles?.opencode?.stdio).toBeUndefined();
135
- expect(warnings.some((w) => w.includes("stdio"))).toBe(true);
136
- });
137
- });
138
- describe("built-in profile resolution", () => {
139
- test("resolves opencode, claude, codex, gemini, aider out of the box", async () => {
140
- const { BUILTIN_AGENT_PROFILE_NAMES, getBuiltinAgentProfile } = await import("../../src/integrations/agent/profiles");
141
- expect(BUILTIN_AGENT_PROFILE_NAMES).toEqual(["aider", "claude", "codex", "gemini", "opencode"]);
142
- for (const name of ["opencode", "claude", "codex", "gemini", "aider"]) {
143
- const profile = getBuiltinAgentProfile(name);
144
- expect(profile).toBeDefined();
145
- expect(profile?.bin).toBeTruthy();
146
- expect(profile?.envPassthrough).toContain("PATH");
147
- }
148
- });
149
- test("user override merges on top of built-in", async () => {
150
- const { resolveAgentProfile } = await import("../../src/integrations/agent/config");
151
- const merged = resolveAgentProfile("opencode", { args: ["--scripted"], stdio: "captured" });
152
- expect(merged?.bin).toBe("opencode"); // built-in default
153
- expect(merged?.args).toEqual(["--scripted"]); // override
154
- expect(merged?.stdio).toBe("captured"); // override
155
- expect(merged?.envPassthrough).toContain("PATH"); // built-in retained
156
- });
157
- test("user-defined profile (no built-in) requires bin", async () => {
158
- const { resolveAgentProfile } = await import("../../src/integrations/agent/config");
159
- expect(resolveAgentProfile("rover", undefined)).toBeUndefined();
160
- expect(resolveAgentProfile("rover", {})).toBeUndefined();
161
- const ok = resolveAgentProfile("rover", { bin: "rover-cli", args: ["--silent"] });
162
- expect(ok?.bin).toBe("rover-cli");
163
- expect(ok?.args).toEqual(["--silent"]);
164
- expect(ok?.stdio).toBe("captured");
165
- });
166
- test("envPassthrough merges base + override", async () => {
167
- const { resolveAgentProfile } = await import("../../src/integrations/agent/config");
168
- const merged = resolveAgentProfile("opencode", { envPassthrough: ["MY_TOKEN"] });
169
- expect(merged?.envPassthrough).toContain("PATH"); // from built-in
170
- expect(merged?.envPassthrough).toContain("MY_TOKEN"); // from override
171
- });
172
- test("listAgentProfileNames includes built-ins plus user-defined", async () => {
173
- const { listAgentProfileNames } = await import("../../src/integrations/agent/config");
174
- const names = listAgentProfileNames({ profiles: { rover: { bin: "rover" } } });
175
- expect(names).toContain("rover");
176
- expect(names).toContain("opencode");
177
- expect(names).toContain("claude");
178
- });
179
- });
180
- describe("requireAgentProfile", () => {
181
- test("throws ConfigError when the agent block is missing", async () => {
182
- const { requireAgentProfile } = await import("../../src/integrations/agent/config");
183
- const { ConfigError } = await import("../../src/core/errors");
184
- let caught;
185
- try {
186
- requireAgentProfile(undefined);
187
- }
188
- catch (err) {
189
- caught = err;
190
- }
191
- expect(caught).toBeInstanceOf(ConfigError);
192
- expect(caught.message).toContain("agent commands are disabled");
193
- const hint = caught.hint();
194
- expect(hint).toBeTruthy();
195
- expect(hint).toContain("akm setup");
196
- });
197
- test("throws when no default and no requested name", async () => {
198
- const { requireAgentProfile } = await import("../../src/integrations/agent/config");
199
- const { ConfigError } = await import("../../src/core/errors");
200
- let caught;
201
- try {
202
- requireAgentProfile({});
203
- }
204
- catch (err) {
205
- caught = err;
206
- }
207
- expect(caught).toBeInstanceOf(ConfigError);
208
- expect(caught.message).toContain("require a profile");
209
- });
210
- test("resolves the requested profile when valid", async () => {
211
- const { requireAgentProfile } = await import("../../src/integrations/agent/config");
212
- const profile = requireAgentProfile({ default: "claude" });
213
- expect(profile.name).toBe("claude");
214
- expect(profile.bin).toBe("claude");
215
- });
216
- test("explicit requested name beats config default", async () => {
217
- const { requireAgentProfile } = await import("../../src/integrations/agent/config");
218
- const profile = requireAgentProfile({ default: "claude" }, "codex");
219
- expect(profile.name).toBe("codex");
220
- });
221
- });
@@ -1,100 +0,0 @@
1
- /**
2
- * Tests for setup-time agent CLI detection.
3
- *
4
- * Acceptance coverage:
5
- * • Detects every built-in profile bin via the injected `which` probe.
6
- * • Picks the first available profile as the default.
7
- * • Honours an existing `agent.default` when that profile is still
8
- * available (round-trip stability).
9
- * • Returns `undefined` when nothing is installed.
10
- * • `stepAgentCliDetection` produces a config-shaped result the wizard
11
- * can `apply()`.
12
- */
13
- import { describe, expect, test } from "bun:test";
14
- import { detectAgentCliProfiles, pickDefaultAgentProfile } from "../../src/integrations/agent/detect";
15
- function whichOnly(installed) {
16
- const set = new Set(installed);
17
- return (bin) => (set.has(bin) ? `/usr/local/bin/${bin}` : undefined);
18
- }
19
- describe("detectAgentCliProfiles", () => {
20
- test("reports every built-in profile, available iff bin found", () => {
21
- const results = detectAgentCliProfiles(undefined, whichOnly(["claude", "codex"]));
22
- const names = results.map((r) => r.name).sort();
23
- expect(names).toEqual(["aider", "claude", "codex", "gemini", "opencode"]);
24
- expect(results.find((r) => r.name === "claude")?.available).toBe(true);
25
- expect(results.find((r) => r.name === "codex")?.available).toBe(true);
26
- expect(results.find((r) => r.name === "gemini")?.available).toBe(false);
27
- });
28
- test("includes user-defined profiles via the resolver", () => {
29
- const results = detectAgentCliProfiles({ profiles: { rover: { bin: "rover-cli" } } }, whichOnly(["rover-cli"]));
30
- const rover = results.find((r) => r.name === "rover");
31
- expect(rover?.available).toBe(true);
32
- expect(rover?.resolvedPath).toContain("rover-cli");
33
- });
34
- test("returns nothing-installed when the probe always says no", () => {
35
- const results = detectAgentCliProfiles(undefined, whichOnly([]));
36
- expect(results.every((r) => !r.available)).toBe(true);
37
- });
38
- });
39
- describe("pickDefaultAgentProfile", () => {
40
- test("picks the first available result when no existing default", () => {
41
- const picked = pickDefaultAgentProfile([
42
- { name: "aider", bin: "aider", available: false },
43
- { name: "claude", bin: "claude", available: true },
44
- { name: "codex", bin: "codex", available: true },
45
- ]);
46
- expect(picked).toBe("claude");
47
- });
48
- test("keeps an existing available default", () => {
49
- const picked = pickDefaultAgentProfile([
50
- { name: "claude", bin: "claude", available: true },
51
- { name: "codex", bin: "codex", available: true },
52
- ], "codex");
53
- expect(picked).toBe("codex");
54
- });
55
- test("falls back when the existing default is no longer available", () => {
56
- const picked = pickDefaultAgentProfile([
57
- { name: "claude", bin: "claude", available: true },
58
- { name: "codex", bin: "codex", available: false },
59
- ], "codex");
60
- expect(picked).toBe("claude");
61
- });
62
- test("returns undefined when nothing is available", () => {
63
- const picked = pickDefaultAgentProfile([
64
- { name: "claude", bin: "claude", available: false },
65
- { name: "codex", bin: "codex", available: false },
66
- ]);
67
- expect(picked).toBeUndefined();
68
- });
69
- });
70
- describe("stepAgentCliDetection (setup wizard)", () => {
71
- test("persists default + leaves block absent when nothing detected & no prior config", async () => {
72
- const { stepAgentCliDetection } = await import("../../src/setup/setup");
73
- const result = stepAgentCliDetection({ semanticSearchMode: "auto" }, () => [
74
- { name: "claude", bin: "claude", available: false },
75
- { name: "codex", bin: "codex", available: false },
76
- ]);
77
- expect(result.agent).toBeUndefined();
78
- expect(result.detections).toHaveLength(2);
79
- });
80
- test("writes agent.default to the first detected profile", async () => {
81
- const { stepAgentCliDetection } = await import("../../src/setup/setup");
82
- const result = stepAgentCliDetection({ semanticSearchMode: "auto" }, () => [
83
- { name: "claude", bin: "claude", available: false },
84
- { name: "codex", bin: "codex", available: true },
85
- ]);
86
- expect(result.agent?.default).toBe("codex");
87
- });
88
- test("preserves user-overridden default when still available", async () => {
89
- const { stepAgentCliDetection } = await import("../../src/setup/setup");
90
- const result = stepAgentCliDetection({
91
- semanticSearchMode: "auto",
92
- agent: { default: "aider", profiles: { aider: { args: ["--no-auto-commits"] } } },
93
- }, () => [
94
- { name: "claude", bin: "claude", available: true },
95
- { name: "aider", bin: "aider", available: true },
96
- ]);
97
- expect(result.agent?.default).toBe("aider");
98
- expect(result.agent?.profiles?.aider?.args).toEqual(["--no-auto-commits"]);
99
- });
100
- });
@@ -1,234 +0,0 @@
1
- /**
2
- * Tests for the agent CLI spawn wrapper (`runAgent`).
3
- *
4
- * Acceptance coverage:
5
- * • Captured stdio collects stdout/stderr.
6
- * • Hard timeout maps to `reason: "timeout"`.
7
- * • Non-zero exit maps to `reason: "non_zero_exit"`.
8
- * • Synchronous spawn failure maps to `reason: "spawn_failed"`.
9
- * • Malformed JSON output (when `parseOutput: "json"`) maps to
10
- * `reason: "parse_error"`.
11
- * • Successful run returns `ok: true`, captured `stdout`, parsed JSON.
12
- *
13
- * The wrapper takes a `spawn` injection point so we never touch real
14
- * binaries here. Where we do touch a real subprocess (one fast `bun -e`
15
- * timeout test) we keep the timeout small and deterministic.
16
- */
17
- import { describe, expect, test } from "bun:test";
18
- import { runAgent } from "../../src/integrations/agent/spawn";
19
- function makeProfile(overrides = {}) {
20
- return {
21
- name: "test-agent",
22
- bin: "test-agent",
23
- args: [],
24
- stdio: "captured",
25
- envPassthrough: ["PATH"],
26
- parseOutput: "text",
27
- ...overrides,
28
- };
29
- }
30
- function asReadableStream(text) {
31
- const bytes = new TextEncoder().encode(text);
32
- return new ReadableStream({
33
- start(controller) {
34
- controller.enqueue(bytes);
35
- controller.close();
36
- },
37
- });
38
- }
39
- function fakeSpawnFn(config) {
40
- const state = { kills: 0 };
41
- const spawn = () => {
42
- if (config.throwSync)
43
- throw config.throwSync;
44
- let resolveExit = () => { };
45
- const exited = new Promise((resolve, reject) => {
46
- resolveExit = resolve;
47
- if (config.rejectExit) {
48
- reject(config.rejectExit);
49
- }
50
- else if (!config.hangsUntilKilled) {
51
- resolve(config.exitCode);
52
- }
53
- });
54
- const proc = {
55
- exitCode: config.hangsUntilKilled ? null : config.exitCode,
56
- exited,
57
- stdout: asReadableStream(config.stdout ?? ""),
58
- stderr: asReadableStream(config.stderr ?? ""),
59
- stdin: null,
60
- kill() {
61
- state.kills += 1;
62
- // Simulate process exit on signal.
63
- resolveExit(143);
64
- },
65
- };
66
- return proc;
67
- };
68
- return { spawn, kills: 0 };
69
- }
70
- describe("runAgent — captured stdio", () => {
71
- test("returns ok:true with stdout/stderr on exit 0", async () => {
72
- const { spawn } = fakeSpawnFn({ exitCode: 0, stdout: "hello\n", stderr: "" });
73
- const result = await runAgent(makeProfile(), "go", { spawn });
74
- expect(result.ok).toBe(true);
75
- expect(result.exitCode).toBe(0);
76
- expect(result.stdout).toBe("hello\n");
77
- expect(result.reason).toBeUndefined();
78
- expect(typeof result.durationMs).toBe("number");
79
- });
80
- test("non-zero exit yields structured `non_zero_exit`", async () => {
81
- const { spawn } = fakeSpawnFn({ exitCode: 7, stderr: "boom" });
82
- const result = await runAgent(makeProfile(), "go", { spawn });
83
- expect(result.ok).toBe(false);
84
- expect(result.reason).toBe("non_zero_exit");
85
- expect(result.exitCode).toBe(7);
86
- expect(result.stderr).toBe("boom");
87
- expect(result.error).toContain("exited with code 7");
88
- });
89
- test("synchronous spawn failure yields `spawn_failed`", async () => {
90
- const { spawn } = fakeSpawnFn({ exitCode: 0, throwSync: new Error("ENOENT: command not found") });
91
- const result = await runAgent(makeProfile(), "go", { spawn });
92
- expect(result.ok).toBe(false);
93
- expect(result.reason).toBe("spawn_failed");
94
- expect(result.error).toContain("ENOENT");
95
- expect(result.exitCode).toBeNull();
96
- });
97
- test("rejected proc.exited yields `spawn_failed`", async () => {
98
- const { spawn } = fakeSpawnFn({ exitCode: 0, rejectExit: new Error("kernel ate it") });
99
- const result = await runAgent(makeProfile(), "go", { spawn });
100
- expect(result.ok).toBe(false);
101
- expect(result.reason).toBe("spawn_failed");
102
- });
103
- });
104
- describe("runAgent — timeout", () => {
105
- test("kills the subprocess and reports `timeout`", async () => {
106
- // Drive the timer manually so the assertion is deterministic.
107
- let timerCallback;
108
- const fakeSet = ((cb) => {
109
- timerCallback = cb;
110
- return 1;
111
- });
112
- const fakeClear = (() => { });
113
- const { spawn } = fakeSpawnFn({ exitCode: 0, hangsUntilKilled: true });
114
- const promise = runAgent(makeProfile(), "go", {
115
- spawn,
116
- setTimeoutFn: fakeSet,
117
- clearTimeoutFn: fakeClear,
118
- timeoutMs: 100,
119
- });
120
- // Kick the deadline.
121
- expect(timerCallback).toBeDefined();
122
- timerCallback?.();
123
- const result = await promise;
124
- expect(result.ok).toBe(false);
125
- expect(result.reason).toBe("timeout");
126
- expect(result.error).toContain("100ms");
127
- });
128
- test("real timeout against `bun -e` sleeping past the deadline (deterministic & fast)", async () => {
129
- const profile = makeProfile({ bin: "bun", args: ["-e", "await new Promise(r => setTimeout(r, 5000))"] });
130
- const start = Date.now();
131
- const result = await runAgent(profile, undefined, { timeoutMs: 250 });
132
- const elapsed = Date.now() - start;
133
- expect(result.ok).toBe(false);
134
- expect(result.reason).toBe("timeout");
135
- // Should bail well before the 5-second sleep would complete.
136
- expect(elapsed).toBeLessThan(2000);
137
- });
138
- });
139
- describe("runAgent — JSON parse mode", () => {
140
- test("parses JSON stdout and surfaces it via `parsed`", async () => {
141
- const { spawn } = fakeSpawnFn({ exitCode: 0, stdout: '{"role":"agent"}' });
142
- const result = await runAgent(makeProfile({ parseOutput: "json" }), "go", { spawn });
143
- expect(result.ok).toBe(true);
144
- expect(result.parsed).toEqual({ role: "agent" });
145
- });
146
- test("malformed JSON yields `parse_error`", async () => {
147
- const { spawn } = fakeSpawnFn({ exitCode: 0, stdout: "not json {" });
148
- const result = await runAgent(makeProfile({ parseOutput: "json" }), "go", { spawn });
149
- expect(result.ok).toBe(false);
150
- expect(result.reason).toBe("parse_error");
151
- expect(result.error).toBeTruthy();
152
- });
153
- // ── #284 GAP-HIGH 10: parseOutput=json + non-zero exit + non-JSON stderr ──
154
- test("parseOutput=json + non-zero exit: non_zero_exit precedence (parse_error suppressed)", async () => {
155
- // Non-zero exit must surface as `non_zero_exit`, not `parse_error`, even
156
- // when the stdout/stderr payload is malformed JSON. The exit code is the
157
- // primary failure signal; parse failures are downstream of a successful run.
158
- const { spawn } = fakeSpawnFn({
159
- exitCode: 5,
160
- stdout: "not json {",
161
- stderr: "agent panic: kernel ate my JSON",
162
- });
163
- const result = await runAgent(makeProfile({ parseOutput: "json" }), "go", { spawn });
164
- expect(result.ok).toBe(false);
165
- expect(result.reason).toBe("non_zero_exit");
166
- expect(result.exitCode).toBe(5);
167
- expect(result.stderr).toBe("agent panic: kernel ate my JSON");
168
- expect(result.parsed).toBeUndefined();
169
- });
170
- });
171
- // ── #284 GAP-HIGH 11: timeoutMs precedence ────────────────────────────────
172
- describe("runAgent — timeoutMs precedence", () => {
173
- test("options.timeoutMs overrides profile.timeoutMs", async () => {
174
- // Both profile and options carry a timeoutMs. Options must win.
175
- let timerCallback;
176
- let observedDeadlineMs;
177
- const fakeSet = ((cb, ms) => {
178
- timerCallback = cb;
179
- observedDeadlineMs = ms;
180
- return 1;
181
- });
182
- const fakeClear = (() => { });
183
- const { spawn } = fakeSpawnFn({ exitCode: 0, hangsUntilKilled: true });
184
- const profile = makeProfile({ timeoutMs: 999_999 });
185
- const promise = runAgent(profile, "go", {
186
- spawn,
187
- setTimeoutFn: fakeSet,
188
- clearTimeoutFn: fakeClear,
189
- timeoutMs: 250,
190
- });
191
- expect(observedDeadlineMs).toBe(250); // override won
192
- timerCallback?.();
193
- const result = await promise;
194
- expect(result.reason).toBe("timeout");
195
- });
196
- });
197
- describe("runAgent — argument and env construction", () => {
198
- test("appends prompt after profile.args and options.args", async () => {
199
- let capturedCmd;
200
- const spawn = (cmd) => {
201
- capturedCmd = cmd;
202
- return {
203
- exitCode: 0,
204
- exited: Promise.resolve(0),
205
- stdout: asReadableStream(""),
206
- stderr: asReadableStream(""),
207
- stdin: null,
208
- kill() { },
209
- };
210
- };
211
- await runAgent(makeProfile({ args: ["--profile-arg"] }), "the-prompt", { spawn, args: ["--call-arg"] });
212
- expect(capturedCmd).toEqual(["test-agent", "--profile-arg", "--call-arg", "the-prompt"]);
213
- });
214
- test("env is filtered by envPassthrough plus profile/options env", async () => {
215
- let capturedEnv;
216
- const spawn = (_cmd, opts) => {
217
- capturedEnv = opts.env;
218
- return {
219
- exitCode: 0,
220
- exited: Promise.resolve(0),
221
- stdout: asReadableStream(""),
222
- stderr: asReadableStream(""),
223
- stdin: null,
224
- kill() { },
225
- };
226
- };
227
- await runAgent(makeProfile({ envPassthrough: ["KEEP_ME"], env: { PROFILE_VAR: "1" } }), undefined, {
228
- spawn,
229
- env: { CALL_VAR: "2" },
230
- envSource: { KEEP_ME: "yes", DROP_ME: "no" },
231
- });
232
- expect(capturedEnv).toEqual({ KEEP_ME: "yes", PROFILE_VAR: "1", CALL_VAR: "2" });
233
- });
234
- });