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,12 +1,11 @@
1
1
  import { createHash } from "node:crypto";
2
2
  import fs from "node:fs";
3
3
  import path from "node:path";
4
- import { fetchWithRetry, ResponseTooLargeError, readBodyWithByteCap } from "../../core/common";
5
- import { ConfigError, UsageError } from "../../core/errors";
6
- import { getRegistryIndexCacheDir } from "../../core/paths";
7
- import { warn } from "../../core/warn";
8
- import { registerSourceProvider } from "../provider-factory";
9
- import { isExpired, sanitizeString } from "./provider-utils";
4
+ import { fetchWithRetry, ResponseTooLargeError, readBodyWithByteCap } from "../core/common";
5
+ import { ConfigError, UsageError } from "../core/errors";
6
+ import { getRegistryIndexCacheDir } from "../core/paths";
7
+ import { warn } from "../core/warn";
8
+ import { isExpired, sanitizeString } from "./providers/provider-utils";
10
9
  /** Refresh website snapshots every 12 hours to balance freshness with scraping load. */
11
10
  const CACHE_REFRESH_INTERVAL_MS = 12 * 60 * 60 * 1000;
12
11
  /** Allow up to 7 days of stale snapshots when refresh fails so search remains available during outages. */
@@ -28,36 +27,7 @@ const WEBSITE_PAGE_BYTE_CAP = 5 * 1024 * 1024;
28
27
  * whole crawl and return what we have when time runs out.
29
28
  */
30
29
  const WEBSITE_CRAWL_WALL_CLOCK_MS = 10 * 60 * 1000;
31
- /**
32
- * Website source provider — scrapes pages into a local mirror so the FTS5
33
- * indexer can walk them. Implements the v1 {@link SourceProvider} interface
34
- * (spec §2.1): `{ name, kind, init, path, sync }`.
35
- *
36
- * Reading is the indexer's job — this class doesn't implement `search` or
37
- * `show`.
38
- */
39
- class WebsiteSourceProvider {
40
- kind = "website";
41
- name;
42
- #config;
43
- #url;
44
- constructor(config) {
45
- this.#config = config;
46
- this.name = config.name ?? "website";
47
- this.#url = validateWebsiteUrl(config.url ?? "");
48
- }
49
- async init(_ctx) {
50
- // URL validation already happens in the constructor; nothing else to do.
51
- }
52
- path() {
53
- return getCachePaths(this.#url).stashDir;
54
- }
55
- async sync() {
56
- await ensureWebsiteMirror(this.#config, { requireStashDir: true });
57
- }
58
- }
59
- registerSourceProvider("website", (config) => new WebsiteSourceProvider(config));
60
- function getCachePaths(siteUrl) {
30
+ export function getWebsiteCachePaths(siteUrl) {
61
31
  const key = createHash("sha256").update(normalizeSiteUrl(siteUrl)).digest("hex").slice(0, 16);
62
32
  const rootDir = path.join(getRegistryIndexCacheDir(), `website-${key}`);
63
33
  return {
@@ -66,10 +36,10 @@ function getCachePaths(siteUrl) {
66
36
  manifestPath: path.join(rootDir, "manifest.json"),
67
37
  };
68
38
  }
69
- async function ensureWebsiteMirror(config, options) {
39
+ export async function ensureWebsiteMirror(config, options) {
70
40
  const rawUrl = config.url ?? "";
71
41
  const normalizedUrl = validateWebsiteUrl(rawUrl);
72
- const cachePaths = getCachePaths(normalizedUrl);
42
+ const cachePaths = getWebsiteCachePaths(normalizedUrl);
73
43
  const requireStashDir = options?.requireStashDir === true;
74
44
  const force = options?.force === true;
75
45
  let mtime = 0;
@@ -106,7 +76,6 @@ function hasExtractedSite(stashDir) {
106
76
  const knowledgeDir = path.join(stashDir, "knowledge");
107
77
  if (!fs.statSync(stashDir).isDirectory() || !fs.statSync(knowledgeDir).isDirectory())
108
78
  return false;
109
- // Check top-level and one level of subdirectories for .md files
110
79
  for (const entry of fs.readdirSync(knowledgeDir, { withFileTypes: true })) {
111
80
  if (entry.isFile() && entry.name.endsWith(".md"))
112
81
  return true;
@@ -142,6 +111,22 @@ async function scrapeWebsiteToStash(startUrl, stashDir, options) {
142
111
  fs.writeFileSync(filePath, buildMarkdownSnapshot(page, slug), "utf8");
143
112
  }
144
113
  }
114
+ export async function fetchWebsiteMarkdownSnapshot(rawUrl) {
115
+ const normalizedUrl = validateWebsiteInputUrl(rawUrl);
116
+ const fetched = await fetchWebsitePage(normalizedUrl);
117
+ if (!fetched) {
118
+ throw new UsageError(`No content could be fetched from ${normalizedUrl}`);
119
+ }
120
+ const preferredName = deriveImportPath(fetched.page.url);
121
+ const slug = preferredName.split("/").pop() ?? preferredName;
122
+ return {
123
+ url: fetched.page.url,
124
+ title: fetched.page.title,
125
+ markdown: fetched.page.markdown,
126
+ preferredName,
127
+ content: buildMarkdownSnapshot(fetched.page, slug || "website"),
128
+ };
129
+ }
145
130
  async function crawlWebsite(startUrl, options) {
146
131
  const start = new URL(normalizeSiteUrl(startUrl));
147
132
  const allowedOrigin = start.origin;
@@ -199,10 +184,8 @@ async function fetchWebsitePage(pageUrl) {
199
184
  body = await readBodyWithByteCap(response, WEBSITE_PAGE_BYTE_CAP);
200
185
  }
201
186
  catch (err) {
202
- if (err instanceof ResponseTooLargeError) {
203
- // Skip oversized pages rather than aborting the whole crawl.
187
+ if (err instanceof ResponseTooLargeError)
204
188
  return null;
205
- }
206
189
  throw err;
207
190
  }
208
191
  const finalUrl = normalizeCrawlUrl(response.url || pageUrl) ?? pageUrl;
@@ -250,10 +233,10 @@ function buildMarkdownSnapshot(page, slug) {
250
233
  "",
251
234
  ].join("\n");
252
235
  }
253
- function validateWebsiteUrl(rawUrl) {
236
+ export function validateWebsiteUrl(rawUrl) {
254
237
  return validateWebsiteUrlWithError(rawUrl, ConfigError);
255
238
  }
256
- function validateWebsiteInputUrl(rawUrl) {
239
+ export function validateWebsiteInputUrl(rawUrl) {
257
240
  return validateWebsiteUrlWithError(rawUrl, UsageError);
258
241
  }
259
242
  function validateWebsiteUrlWithError(rawUrl, ErrorType) {
@@ -299,10 +282,6 @@ function normalizeCrawlUrl(rawUrl) {
299
282
  return null;
300
283
  }
301
284
  }
302
- /** Convert a page URL into a relative file path preserving the URL hierarchy.
303
- * e.g. https://example.com/docs/guide → docs/guide
304
- * https://example.com/ → index
305
- */
306
285
  function urlToRelativePath(rawUrl) {
307
286
  const parsed = new URL(rawUrl);
308
287
  const segments = parsed.pathname
@@ -318,6 +297,17 @@ function urlToRelativePath(rawUrl) {
318
297
  }
319
298
  return segments.length > 0 ? segments.join("/") : "index";
320
299
  }
300
+ function deriveImportPath(rawUrl) {
301
+ const parsed = new URL(rawUrl);
302
+ const relativePath = urlToRelativePath(rawUrl);
303
+ if (relativePath !== "index")
304
+ return relativePath;
305
+ const host = slugifySegment(parsed.hostname) || "website";
306
+ if (!parsed.search)
307
+ return host;
308
+ const querySuffix = slugifySegment(parsed.search.slice(1));
309
+ return querySuffix ? `${host}-${querySuffix}` : host;
310
+ }
321
311
  function slugifySegment(value) {
322
312
  return sanitizeString(value, 200)
323
313
  .toLowerCase()
@@ -459,8 +449,6 @@ function decodeHtmlEntities(value) {
459
449
  });
460
450
  }
461
451
  function isAssetLikePath(pathname) {
462
- // Keep this list intentionally conservative so docs paths are still crawled
463
- // unless they clearly point at static assets/binaries.
464
452
  return /\.(css|js|json|png|jpe?g|gif|svg|ico|webp|pdf|zip|tar|gz|mp4|mp3|woff2?)$/i.test(pathname);
465
453
  }
466
454
  function isSafeLinkUrl(url) {
@@ -480,4 +468,3 @@ function safeCodePointToString(value) {
480
468
  return undefined;
481
469
  }
482
470
  }
483
- export { ensureWebsiteMirror, getCachePaths, validateWebsiteInputUrl, validateWebsiteUrl, WebsiteSourceProvider };
package/docs/README.md CHANGED
@@ -21,6 +21,13 @@
21
21
  - [Configuration](configuration.md) -- Providers, settings, and Ollama setup
22
22
  - [Filesystem](technical/filesystem.md) -- Directory layout and `.stash.json` schema
23
23
 
24
+ ## Official Ecosystem Repositories
25
+
26
+ - [itlackey/akm-stash](https://github.com/itlackey/akm-stash) -- the official onboarding stash with ready-made assets you can install with `akm add`
27
+ - [itlackey/akm-registry](https://github.com/itlackey/akm-registry) -- the official registry index that powers built-in discovery
28
+ - [itlackey/akm-plugins](https://github.com/itlackey/akm-plugins) -- optional integrations for tools like OpenCode
29
+ - [itlackey/akm-bench](https://github.com/itlackey/akm-bench) -- the standalone benchmark and evaluation repo for akm
30
+
24
31
  ## Internals
25
32
 
26
33
  - [Search](technical/search.md) -- Hybrid search architecture and scoring
@@ -150,6 +150,20 @@ This is the surface 0.7.0 commits to maintain through 0.8.x / 0.9.x.
150
150
  Renaming or removing any of these commands at 1.0 GA would be a major
151
151
  version bump.
152
152
 
153
+ ## Post-0.7.0 additive surfaces
154
+
155
+ These landed after the 0.7.0 cut without changing the existing command grammar:
156
+
157
+ - `akm import <url>` now fetches one HTTP/HTTPS URL, converts it to markdown,
158
+ and writes it into `knowledge/` using a URL-path-derived default name.
159
+ - `akm wiki stash <name> <url>` now fetches one HTTP/HTTPS URL, converts it to
160
+ markdown, and writes it into `wikis/<name>/raw/`.
161
+ - Both flows are one-shot ingest only: they do not register a persistent
162
+ website source and they do not crawl linked pages.
163
+ - Website source sync (`akm add <url> --provider website`) and one-shot URL
164
+ ingest now share the same `src/sources/website-ingest.ts` module for URL
165
+ validation, fetch/convert, and mirror generation behavior.
166
+
153
167
  ## Pre-prod hardening (PR #275)
154
168
 
155
169
  PR #275 batched five issues plus the bench tmp follow-up that operators
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "akm-cli",
3
- "version": "0.7.0",
3
+ "version": "0.7.2",
4
4
  "type": "module",
5
5
  "description": "akm (Agent Kit Manager) — A package manager for AI agent skills, commands, tools, and knowledge. Works with Claude Code, OpenCode, Cursor, and any AI coding assistant.",
6
6
  "keywords": [
@@ -42,10 +42,13 @@
42
42
  "akm": "dist/cli.js"
43
43
  },
44
44
  "scripts": {
45
- "build": "rm -rf dist && bun run tsc --project ./tsconfig.json --outDir dist",
45
+ "build": "rm -rf dist && bun run tsc --project ./tsconfig.build.json",
46
46
  "check": "bun run lint && bunx tsc --noEmit && bun test ./tests",
47
47
  "check:changed": "bun test tests/output-baseline.test.ts tests/e2e.test.ts tests/stash-search.test.ts && bun run lint && bunx tsc --noEmit",
48
48
  "test": "bun test ./tests",
49
+ "lint:devto-posts": "bun scripts/lint-devto-posts.ts",
50
+ "lint:devto-posts:fix": "bun scripts/lint-devto-posts.ts --fix",
51
+ "publish:devto": "npx -y @sinedied/devto-cli push \"docs/posts/**/*.md\" --token \"$DEVTO_TOKEN\" --repo \"$GITHUB_REPOSITORY\" --branch \"${GITHUB_REF_NAME:-main}\" --reconcile",
49
52
  "release:check": "./tests/release-check.sh",
50
53
  "lint": "bunx biome check src/ tests/",
51
54
  "lint:fix": "bunx biome check --write src/ tests/",
@@ -57,9 +60,9 @@
57
60
  "access": "public"
58
61
  },
59
62
  "devDependencies": {
60
- "@biomejs/biome": "^2.4.6",
61
- "@types/node": "^22.0.0",
62
- "bun-types": "^1.3.10",
63
+ "@biomejs/biome": "^2.4.14",
64
+ "@types/node": "^22.19.17",
65
+ "bun-types": "^1.3.13",
63
66
  "typescript": "^5.9.3"
64
67
  },
65
68
  "optionalDependencies": {
@@ -70,9 +73,9 @@
70
73
  "bun": ">=1.0.0"
71
74
  },
72
75
  "dependencies": {
73
- "@clack/prompts": "^1.1.0",
74
- "citty": "^0.2.1",
76
+ "@clack/prompts": "^1.3.0",
77
+ "citty": "^0.2.2",
75
78
  "dotenv": "^17.4.2",
76
- "yaml": "^2.8.2"
79
+ "yaml": "^2.8.4"
77
80
  }
78
81
  }
@@ -1,86 +0,0 @@
1
- /**
2
- * LLM helper for the `akm index` memory-inference pass (#201).
3
- *
4
- * Splits a single memory body into a list of atomic facts. The pass itself
5
- * (in `src/indexer/memory-inference.ts`) is responsible for deciding which
6
- * memories are pending, persisting the resulting atomic memories with the
7
- * correct frontmatter (`inferred: true`, `source: <parent-ref>`), and
8
- * marking the parent as processed for idempotency.
9
- *
10
- * This module is intentionally tiny and stateless so tests can stub it via
11
- * `mock.module("../src/llm/memory-infer", ...)` without hitting a network.
12
- *
13
- * Locked v1 contract (#208): the LLM connection always comes from the
14
- * shared `akm.llm` block — never from a per-pass override. Callers obtain
15
- * the connection via `resolveIndexPassLLM("memory", config)` and pass it
16
- * straight through.
17
- */
18
- import { toErrorMessage } from "../core/common";
19
- import { warn } from "../core/warn";
20
- import { chatCompletion, parseJsonResponse } from "./client";
21
- /** Hard cap on body chars sent to the model — pragmatic and matches `runLlmEnrich`. */
22
- const MAX_BODY_CHARS = 4000;
23
- /** Hard cap on the number of atomic facts returned per memory. */
24
- const MAX_FACTS_PER_MEMORY = 16;
25
- /** Hard timeout for the LLM call. The index run must not hang on a misbehaving endpoint. */
26
- const LLM_TIMEOUT_MS = 30_000;
27
- const SYSTEM_PROMPT = "You split a developer memory into atomic, self-contained facts. " +
28
- "Return only valid JSON. No prose, no markdown fences.";
29
- const USER_PROMPT_PREFIX = `Split the memory below into a JSON array of short, self-contained atomic facts.
30
-
31
- Rules:
32
- - Output ONLY a JSON object: {"facts": ["fact one", "fact two", ...]}.
33
- - Each fact is a single complete sentence, decontextualized so it stands alone.
34
- - Drop pleasantries, meta-commentary, and timestamps.
35
- - Preserve technical specifics (names, versions, identifiers) verbatim.
36
- - If the memory is already a single atomic fact, return it as the only entry.
37
- - Limit to at most ${MAX_FACTS_PER_MEMORY} facts.
38
-
39
- Memory:
40
- `;
41
- /**
42
- * Split a single memory body into atomic facts via the configured LLM.
43
- *
44
- * Returns `[]` on any failure (timeout, invalid JSON, empty response). Errors
45
- * are logged via `warn()` but never thrown — a failed split for one memory
46
- * must not abort the rest of the index pass.
47
- */
48
- export async function splitMemoryIntoAtomicFacts(llmConfig, body) {
49
- const trimmedBody = body.trim();
50
- if (!trimmedBody)
51
- return [];
52
- const userPrompt = `${USER_PROMPT_PREFIX}${trimmedBody.slice(0, MAX_BODY_CHARS)}`;
53
- let timeoutHandle;
54
- try {
55
- const raw = await Promise.race([
56
- chatCompletion(llmConfig, [
57
- { role: "system", content: SYSTEM_PROMPT },
58
- { role: "user", content: userPrompt },
59
- ], { maxTokens: 768, temperature: 0.1 }),
60
- new Promise((_, reject) => {
61
- timeoutHandle = setTimeout(() => reject(new Error("memory inference timed out")), LLM_TIMEOUT_MS);
62
- }),
63
- ]);
64
- if (!raw)
65
- return [];
66
- const parsed = parseJsonResponse(raw);
67
- if (!parsed || !Array.isArray(parsed.facts)) {
68
- warn("memory inference: invalid JSON response from LLM; skipping memory.");
69
- return [];
70
- }
71
- const facts = parsed.facts
72
- .filter((f) => typeof f === "string")
73
- .map((f) => f.trim())
74
- .filter((f) => f.length > 0)
75
- .slice(0, MAX_FACTS_PER_MEMORY);
76
- return facts;
77
- }
78
- catch (err) {
79
- warn(`memory inference failed: ${toErrorMessage(err)}`);
80
- return [];
81
- }
82
- finally {
83
- if (timeoutHandle !== undefined)
84
- clearTimeout(timeoutHandle);
85
- }
86
- }
@@ -1,119 +0,0 @@
1
- import { afterAll, afterEach, describe, expect, test } from "bun:test";
2
- import { spawn } from "node:child_process";
3
- import fs from "node:fs";
4
- import os from "node:os";
5
- import path from "node:path";
6
- const CLI = path.join(__dirname, "..", "src", "cli.ts");
7
- const tempDirs = [];
8
- const servers = [];
9
- const CLI_TIMEOUT_MS = 30_000;
10
- const TEST_TIMEOUT_MS = 60_000;
11
- function makeTempDir(prefix) {
12
- const dir = fs.mkdtempSync(path.join(os.tmpdir(), prefix));
13
- tempDirs.push(dir);
14
- return dir;
15
- }
16
- function createWorkingStash() {
17
- const dir = makeTempDir("akm-add-website-stash-");
18
- for (const sub of ["skills", "commands", "agents", "knowledge", "scripts"]) {
19
- fs.mkdirSync(path.join(dir, sub), { recursive: true });
20
- }
21
- return dir;
22
- }
23
- function serveWebsite() {
24
- const server = Bun.serve({
25
- port: 0,
26
- fetch(request) {
27
- const url = new URL(request.url);
28
- if (url.pathname === "/") {
29
- return new Response("<html><head><title>Example Docs</title></head><body><h1>Example Docs</h1><p>Welcome to the docs.</p><a href='/getting-started'>Getting started</a></body></html>", {
30
- headers: { "Content-Type": "text/html; charset=utf-8" },
31
- });
32
- }
33
- if (url.pathname === "/getting-started") {
34
- return new Response("<html><body><h1>Getting started</h1><p>Run setup first.</p></body></html>", {
35
- headers: { "Content-Type": "text/html; charset=utf-8" },
36
- });
37
- }
38
- return new Response("not found", { status: 404 });
39
- },
40
- });
41
- servers.push(server);
42
- return `http://127.0.0.1:${server.port}`;
43
- }
44
- afterEach(() => {
45
- for (const server of servers.splice(0)) {
46
- server.stop(true);
47
- }
48
- for (const dir of tempDirs.splice(0)) {
49
- fs.rmSync(dir, { recursive: true, force: true });
50
- }
51
- });
52
- afterAll(() => {
53
- for (const server of servers.splice(0)) {
54
- server.stop(true);
55
- }
56
- });
57
- describe("akm add website", () => {
58
- test("adds a website stash source, caches markdown, and indexes it", async () => {
59
- const stashDir = createWorkingStash();
60
- const xdgCache = makeTempDir("akm-add-website-cache-");
61
- const xdgConfig = makeTempDir("akm-add-website-config-");
62
- const websiteUrl = serveWebsite();
63
- const configDir = path.join(xdgConfig, "akm");
64
- fs.mkdirSync(configDir, { recursive: true });
65
- fs.writeFileSync(path.join(configDir, "config.json"), `${JSON.stringify({ semanticSearchMode: "off" }, null, 2)}\n`);
66
- const child = spawn("bun", [CLI, "add", websiteUrl, "--name", "docs-site", "--format=json"], {
67
- stdio: ["ignore", "pipe", "pipe"],
68
- env: {
69
- ...process.env,
70
- AKM_STASH_DIR: stashDir,
71
- XDG_CACHE_HOME: xdgCache,
72
- XDG_CONFIG_HOME: xdgConfig,
73
- },
74
- });
75
- let stdout = "";
76
- let stderr = "";
77
- child.stdout.on("data", (chunk) => {
78
- stdout += String(chunk);
79
- });
80
- child.stderr.on("data", (chunk) => {
81
- stderr += String(chunk);
82
- });
83
- const exitCode = await new Promise((resolve, reject) => {
84
- const timer = setTimeout(() => {
85
- child.kill("SIGKILL");
86
- reject(new Error("CLI website add timed out"));
87
- }, CLI_TIMEOUT_MS);
88
- child.on("error", (err) => {
89
- clearTimeout(timer);
90
- reject(err);
91
- });
92
- child.on("close", (code) => {
93
- clearTimeout(timer);
94
- resolve(code ?? 1);
95
- });
96
- });
97
- expect(exitCode).toBe(0);
98
- expect(stderr.trim()).toBe("");
99
- const parsed = JSON.parse(stdout.trim());
100
- const normalizedWebsiteUrl = `${websiteUrl}/`;
101
- expect(parsed.sourceAdded).toBeDefined();
102
- expect(parsed.sourceAdded?.type).toBe("website");
103
- expect(parsed.sourceAdded?.url).toBe(normalizedWebsiteUrl);
104
- expect(parsed.sourceAdded?.name).toBe("docs-site");
105
- expect(parsed.index?.totalEntries).toBeGreaterThanOrEqual(2);
106
- const configPath = path.join(xdgConfig, "akm", "config.json");
107
- const config = JSON.parse(fs.readFileSync(configPath, "utf8"));
108
- expect(config.sources).toContainEqual({
109
- type: "website",
110
- url: normalizedWebsiteUrl,
111
- name: "docs-site",
112
- });
113
- expect(parsed.sourceAdded?.stashRoot).toBeDefined();
114
- const knowledgeFiles = fs.readdirSync(path.join(parsed.sourceAdded?.stashRoot, "knowledge")).sort();
115
- expect(knowledgeFiles).toEqual(["getting-started.md", "index.md"]);
116
- const homeDoc = fs.readFileSync(path.join(parsed.sourceAdded?.stashRoot, "knowledge", "index.md"), "utf8");
117
- expect(homeDoc).toContain("Example Docs");
118
- }, { timeout: TEST_TIMEOUT_MS });
119
- });
@@ -1,70 +0,0 @@
1
- /**
2
- * Integration test: the AkmConfig loader propagates the `agent` block
3
- * through `loadConfig()` (and through the on-disk JSONC parser, exercising
4
- * the `pickKnownKeys` path).
5
- *
6
- * The acceptance criterion "config schema accepts an optional agent block"
7
- * lives at the loader boundary, not just the parser; this test pins the
8
- * end-to-end shape.
9
- */
10
- import { afterEach, beforeEach, describe, expect, test } from "bun:test";
11
- import fs from "node:fs";
12
- import os from "node:os";
13
- import path from "node:path";
14
- let tmpHome;
15
- let originalHome;
16
- let originalXdg;
17
- beforeEach(() => {
18
- tmpHome = fs.mkdtempSync(path.join(os.tmpdir(), "akm-agent-cfg-"));
19
- originalHome = process.env.HOME;
20
- originalXdg = process.env.XDG_CONFIG_HOME;
21
- process.env.HOME = tmpHome;
22
- process.env.XDG_CONFIG_HOME = path.join(tmpHome, ".config");
23
- });
24
- afterEach(() => {
25
- if (originalHome === undefined)
26
- delete process.env.HOME;
27
- else
28
- process.env.HOME = originalHome;
29
- if (originalXdg === undefined)
30
- delete process.env.XDG_CONFIG_HOME;
31
- else
32
- process.env.XDG_CONFIG_HOME = originalXdg;
33
- fs.rmSync(tmpHome, { recursive: true, force: true });
34
- });
35
- describe("AkmConfig loader — agent block", () => {
36
- test("loads agent.default + agent.profiles from disk", async () => {
37
- const { getConfigPath, loadUserConfig, resetConfigCache } = await import("../../src/core/config");
38
- const cfgPath = getConfigPath();
39
- fs.mkdirSync(path.dirname(cfgPath), { recursive: true });
40
- fs.writeFileSync(cfgPath, JSON.stringify({
41
- semanticSearchMode: "auto",
42
- agent: {
43
- default: "claude",
44
- timeoutMs: 45000,
45
- profiles: {
46
- claude: { args: ["--print"] },
47
- rover: { bin: "rover-cli", parseOutput: "json" },
48
- },
49
- // Unknown key — must not throw at load.
50
- mystery: 1,
51
- },
52
- }, null, 2));
53
- resetConfigCache();
54
- const cfg = loadUserConfig();
55
- expect(cfg.agent?.default).toBe("claude");
56
- expect(cfg.agent?.timeoutMs).toBe(45000);
57
- expect(cfg.agent?.profiles?.claude?.args).toEqual(["--print"]);
58
- expect(cfg.agent?.profiles?.rover?.bin).toBe("rover-cli");
59
- expect(cfg.agent?.profiles?.rover?.parseOutput).toBe("json");
60
- });
61
- test("agent block absent → cfg.agent is undefined → requireAgentProfile throws", async () => {
62
- const { loadUserConfig, resetConfigCache } = await import("../../src/core/config");
63
- const { requireAgentProfile } = await import("../../src/integrations/agent/config");
64
- const { ConfigError } = await import("../../src/core/errors");
65
- resetConfigCache();
66
- const cfg = loadUserConfig();
67
- expect(cfg.agent).toBeUndefined();
68
- expect(() => requireAgentProfile(cfg.agent)).toThrow(ConfigError);
69
- });
70
- });