akm-cli 0.6.1 → 0.7.0-rc1

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 (319) hide show
  1. package/CHANGELOG.md +66 -0
  2. package/dist/{cli.js → src/cli.js} +620 -26
  3. package/dist/{commands → src/commands}/config-cli.js +5 -4
  4. package/dist/src/commands/distill.js +283 -0
  5. package/dist/src/commands/events.js +108 -0
  6. package/dist/src/commands/history.js +120 -0
  7. package/dist/{commands → src/commands}/installed-stashes.js +1 -1
  8. package/dist/src/commands/proposal.js +119 -0
  9. package/dist/src/commands/propose.js +171 -0
  10. package/dist/src/commands/reflect.js +193 -0
  11. package/dist/{commands → src/commands}/registry-search.js +2 -1
  12. package/dist/{commands → src/commands}/remember.js +12 -0
  13. package/dist/{commands → src/commands}/search.js +74 -1
  14. package/dist/{commands → src/commands}/self-update.js +4 -3
  15. package/dist/{commands → src/commands}/show.js +44 -0
  16. package/dist/{core → src/core}/asset-ref.js +5 -5
  17. package/dist/{core → src/core}/asset-spec.js +12 -0
  18. package/dist/{core → src/core}/common.js +1 -1
  19. package/dist/{core → src/core}/config.js +175 -121
  20. package/dist/{core → src/core}/errors.js +4 -0
  21. package/dist/src/core/events.js +239 -0
  22. package/dist/src/core/lesson-lint.js +86 -0
  23. package/dist/src/core/proposals.js +406 -0
  24. package/dist/src/core/warn.js +72 -0
  25. package/dist/{core → src/core}/write-source.js +80 -5
  26. package/dist/{indexer → src/indexer}/db-search.js +113 -24
  27. package/dist/{indexer → src/indexer}/db.js +76 -23
  28. package/dist/{indexer → src/indexer}/file-context.js +0 -3
  29. package/dist/src/indexer/graph-boost.js +179 -0
  30. package/dist/src/indexer/graph-extraction.js +212 -0
  31. package/dist/{indexer → src/indexer}/indexer.js +73 -6
  32. package/dist/src/indexer/memory-inference.js +263 -0
  33. package/dist/{indexer → src/indexer}/metadata.js +111 -3
  34. package/dist/src/integrations/agent/config.js +292 -0
  35. package/dist/src/integrations/agent/detect.js +94 -0
  36. package/dist/src/integrations/agent/index.js +17 -0
  37. package/dist/src/integrations/agent/profiles.js +65 -0
  38. package/dist/src/integrations/agent/prompts.js +167 -0
  39. package/dist/src/integrations/agent/spawn.js +221 -0
  40. package/dist/{integrations → src/integrations}/lockfile.js +0 -26
  41. package/dist/{llm → src/llm}/client.js +33 -2
  42. package/dist/src/llm/feature-gate.js +108 -0
  43. package/dist/src/llm/graph-extract.js +107 -0
  44. package/dist/src/llm/index-passes.js +35 -0
  45. package/dist/src/llm/memory-infer.js +86 -0
  46. package/dist/{output → src/output}/renderers.js +60 -1
  47. package/dist/src/output/shapes.js +516 -0
  48. package/dist/{output → src/output}/text.js +447 -4
  49. package/dist/{registry → src/registry}/build-index.js +14 -4
  50. package/dist/{registry → src/registry}/factory.js +0 -8
  51. package/dist/{registry → src/registry}/providers/static-index.js +3 -2
  52. package/dist/{registry → src/registry}/resolve.js +68 -2
  53. package/dist/{setup → src/setup}/setup.js +43 -5
  54. package/dist/{sources → src/sources}/providers/git.js +7 -15
  55. package/dist/tests/add-website-source.test.js +119 -0
  56. package/dist/tests/agent/agent-config-loader.test.js +70 -0
  57. package/dist/tests/agent/agent-config.test.js +221 -0
  58. package/dist/tests/agent/agent-detect.test.js +100 -0
  59. package/dist/tests/agent/agent-spawn.test.js +234 -0
  60. package/dist/tests/agent-output.test.js +186 -0
  61. package/dist/tests/architecture/agent-no-llm-sdk-guard.test.js +103 -0
  62. package/dist/tests/architecture/agent-spawn-seam.test.js +193 -0
  63. package/dist/tests/architecture/llm-stateless-seam.test.js +112 -0
  64. package/dist/tests/asset-ref.test.js +192 -0
  65. package/dist/tests/asset-registry.test.js +103 -0
  66. package/dist/tests/asset-spec.test.js +241 -0
  67. package/dist/tests/bench/attribution.test.js +995 -0
  68. package/dist/tests/bench/cleanup-sigint.test.js +83 -0
  69. package/dist/tests/bench/cleanup.js +203 -0
  70. package/dist/tests/bench/cleanup.test.js +166 -0
  71. package/dist/tests/bench/cli.js +683 -0
  72. package/dist/tests/bench/cli.test.js +177 -0
  73. package/dist/tests/bench/compare.test.js +556 -0
  74. package/dist/tests/bench/corpus.js +314 -0
  75. package/dist/tests/bench/corpus.test.js +258 -0
  76. package/dist/tests/bench/driver.js +346 -0
  77. package/dist/tests/bench/driver.test.js +443 -0
  78. package/dist/tests/bench/evolve-metrics.js +179 -0
  79. package/dist/tests/bench/evolve-metrics.test.js +187 -0
  80. package/dist/tests/bench/evolve.js +580 -0
  81. package/dist/tests/bench/evolve.test.js +616 -0
  82. package/dist/tests/bench/failure-modes.test.js +300 -0
  83. package/dist/tests/bench/feedback-integrity.test.js +456 -0
  84. package/dist/tests/bench/leakage.test.js +125 -0
  85. package/dist/tests/bench/learning-curve.test.js +133 -0
  86. package/dist/tests/bench/metrics.js +2319 -0
  87. package/dist/tests/bench/metrics.test.js +1144 -0
  88. package/dist/tests/bench/no-os-tmpdir-invariant.test.js +43 -0
  89. package/dist/tests/bench/report.js +1821 -0
  90. package/dist/tests/bench/report.test.js +989 -0
  91. package/dist/tests/bench/runner.js +536 -0
  92. package/dist/tests/bench/runner.test.js +958 -0
  93. package/dist/tests/bench/search-bridge.test.js +331 -0
  94. package/dist/tests/bench/tmp.js +41 -0
  95. package/dist/tests/bench/trajectory.js +116 -0
  96. package/dist/tests/bench/trajectory.test.js +127 -0
  97. package/dist/tests/bench/verifier.js +109 -0
  98. package/dist/tests/bench/verifier.test.js +118 -0
  99. package/dist/tests/bench/workflow-evaluator.js +557 -0
  100. package/dist/tests/bench/workflow-evaluator.test.js +421 -0
  101. package/dist/tests/bench/workflow-spec.js +358 -0
  102. package/dist/tests/bench/workflow-spec.test.js +363 -0
  103. package/dist/tests/bench/workflow-trace.js +438 -0
  104. package/dist/tests/bench/workflow-trace.test.js +254 -0
  105. package/dist/tests/benchmark-search-quality.js +536 -0
  106. package/dist/tests/benchmark-suite.js +1441 -0
  107. package/dist/tests/capture-cli.test.js +112 -0
  108. package/dist/tests/cli-errors.test.js +203 -0
  109. package/dist/tests/commands/events.test.js +370 -0
  110. package/dist/tests/commands/history.test.js +223 -0
  111. package/dist/tests/commands/import.test.js +103 -0
  112. package/dist/tests/commands/proposal-cli.test.js +209 -0
  113. package/dist/tests/commands/reflect-propose-cli.test.js +333 -0
  114. package/dist/tests/commands/remember.test.js +97 -0
  115. package/dist/tests/commands/scope-flags.test.js +300 -0
  116. package/dist/tests/commands/search.test.js +537 -0
  117. package/dist/tests/commands/show-indexer-parity.test.js +117 -0
  118. package/dist/tests/commands/show.test.js +294 -0
  119. package/dist/tests/common.test.js +266 -0
  120. package/dist/tests/completions.test.js +142 -0
  121. package/dist/tests/config-cli.test.js +193 -0
  122. package/dist/tests/config-llm-features.test.js +139 -0
  123. package/dist/tests/config.test.js +544 -0
  124. package/dist/tests/contracts/migration-baseline.test.js +43 -0
  125. package/dist/tests/contracts/reflect-propose-envelope.test.js +139 -0
  126. package/dist/tests/contracts/spec-helpers.js +46 -0
  127. package/dist/tests/contracts/v1-spec-section-11-proposal-queue.test.js +228 -0
  128. package/dist/tests/contracts/v1-spec-section-12-agent-config.test.js +56 -0
  129. package/dist/tests/contracts/v1-spec-section-13-lesson-type.test.js +34 -0
  130. package/dist/tests/contracts/v1-spec-section-14-llm-features.test.js +94 -0
  131. package/dist/tests/contracts/v1-spec-section-4-1-asset-types.test.js +39 -0
  132. package/dist/tests/contracts/v1-spec-section-4-2-quality-rules.test.js +44 -0
  133. package/dist/tests/contracts/v1-spec-section-5-configuration.test.js +47 -0
  134. package/dist/tests/contracts/v1-spec-section-6-orchestration.test.js +40 -0
  135. package/dist/tests/contracts/v1-spec-section-7-module-layout.test.js +58 -0
  136. package/dist/tests/contracts/v1-spec-section-8-extension-points.test.js +34 -0
  137. package/dist/tests/contracts/v1-spec-section-9-4-cli-surface.test.js +75 -0
  138. package/dist/tests/contracts/v1-spec-section-9-7-llm-agent-boundary.test.js +36 -0
  139. package/dist/tests/core/write-source.test.js +366 -0
  140. package/dist/tests/curate-command.test.js +87 -0
  141. package/dist/tests/db-scoring.test.js +201 -0
  142. package/dist/tests/db.test.js +654 -0
  143. package/dist/tests/distill-cli-flag.test.js +208 -0
  144. package/dist/tests/distill.test.js +515 -0
  145. package/dist/tests/docker-install.test.js +120 -0
  146. package/dist/tests/e2e.test.js +1398 -0
  147. package/dist/tests/embedder.test.js +340 -0
  148. package/dist/tests/embedding-model-config.test.js +379 -0
  149. package/dist/tests/feedback-command.test.js +172 -0
  150. package/dist/tests/file-context.test.js +552 -0
  151. package/dist/tests/fixtures/scripts/git/summarize-diff.js +9 -0
  152. package/dist/tests/fixtures/scripts/lint/eslint-check.js +7 -0
  153. package/dist/tests/fixtures/stashes/load.js +166 -0
  154. package/dist/tests/fixtures/stashes/load.test.js +88 -0
  155. package/dist/tests/fixtures/stashes/ranking-baseline/scripts/mem0-search.js +12 -0
  156. package/dist/tests/frontmatter.test.js +190 -0
  157. package/dist/tests/fts-field-weighting.test.js +254 -0
  158. package/dist/tests/fuzzy-search.test.js +230 -0
  159. package/dist/tests/git-provider-clone.test.js +45 -0
  160. package/dist/tests/github.test.js +161 -0
  161. package/dist/tests/graph-boost-ranking.test.js +305 -0
  162. package/dist/tests/graph-extraction.test.js +282 -0
  163. package/dist/tests/helpers/usage-events.js +8 -0
  164. package/dist/tests/index-pass-llm.test.js +161 -0
  165. package/dist/tests/indexer.test.js +559 -0
  166. package/dist/tests/info-command.test.js +166 -0
  167. package/dist/tests/init.test.js +69 -0
  168. package/dist/tests/install-script.test.js +246 -0
  169. package/dist/tests/integration/agent-real-profile.test.js +94 -0
  170. package/dist/tests/issue-36-repro.test.js +304 -0
  171. package/dist/tests/issues-191-194.test.js +160 -0
  172. package/dist/tests/lesson-lint.test.js +111 -0
  173. package/dist/tests/llm-client.test.js +115 -0
  174. package/dist/tests/llm-feature-gate.test.js +151 -0
  175. package/dist/tests/llm.test.js +139 -0
  176. package/dist/tests/lockfile.test.js +216 -0
  177. package/dist/tests/manifest.test.js +205 -0
  178. package/dist/tests/markdown.test.js +126 -0
  179. package/dist/tests/matchers-unit.test.js +189 -0
  180. package/dist/tests/memory-inference.test.js +299 -0
  181. package/dist/tests/merge-scoring.test.js +136 -0
  182. package/dist/tests/metadata.test.js +313 -0
  183. package/dist/tests/migration-help.test.js +89 -0
  184. package/dist/tests/origin-resolve.test.js +124 -0
  185. package/dist/tests/output-baseline.test.js +217 -0
  186. package/dist/tests/output-shapes-unit.test.js +476 -0
  187. package/dist/tests/parallel-search.test.js +272 -0
  188. package/dist/tests/parameter-metadata.test.js +365 -0
  189. package/dist/tests/paths.test.js +177 -0
  190. package/dist/tests/progressive-disclosure.test.js +280 -0
  191. package/dist/tests/proposals.test.js +279 -0
  192. package/dist/tests/proposed-quality.test.js +271 -0
  193. package/dist/tests/provider-registry.test.js +32 -0
  194. package/dist/tests/ranking-regression.test.js +548 -0
  195. package/dist/tests/reflect-propose.test.js +455 -0
  196. package/dist/tests/registry-build-index.test.js +378 -0
  197. package/dist/tests/registry-cli.test.js +290 -0
  198. package/dist/tests/registry-index-v2.test.js +430 -0
  199. package/dist/tests/registry-install.test.js +728 -0
  200. package/dist/tests/registry-providers/parity.test.js +189 -0
  201. package/dist/tests/registry-providers/skills-sh.test.js +309 -0
  202. package/dist/tests/registry-providers/static-index.test.js +204 -0
  203. package/dist/tests/registry-resolve.test.js +126 -0
  204. package/dist/tests/registry-search.test.js +723 -0
  205. package/dist/tests/remember-frontmatter.test.js +380 -0
  206. package/dist/tests/remember-unit.test.js +123 -0
  207. package/dist/tests/ripgrep-install.test.js +251 -0
  208. package/dist/tests/ripgrep-resolve.test.js +108 -0
  209. package/dist/tests/ripgrep.test.js +163 -0
  210. package/dist/tests/save-command.test.js +94 -0
  211. package/dist/tests/save-trust-qa-fixes.test.js +270 -0
  212. package/dist/tests/scoring-pipeline.test.js +648 -0
  213. package/dist/tests/search-include-proposed-cli.test.js +118 -0
  214. package/dist/tests/self-update.test.js +442 -0
  215. package/dist/tests/semantic-search-e2e.test.js +512 -0
  216. package/dist/tests/semantic-status.test.js +471 -0
  217. package/dist/tests/setup-run.integration.js +877 -0
  218. package/dist/tests/setup-wizard.test.js +198 -0
  219. package/dist/tests/setup.test.js +131 -0
  220. package/dist/tests/source-add.test.js +11 -0
  221. package/dist/tests/source-clone.test.js +254 -0
  222. package/dist/tests/source-manage.test.js +366 -0
  223. package/dist/tests/source-providers/filesystem.test.js +82 -0
  224. package/dist/tests/source-providers/git.test.js +252 -0
  225. package/dist/tests/source-providers/website.test.js +128 -0
  226. package/dist/tests/source-qa-fixes.test.js +268 -0
  227. package/dist/tests/source-registry.test.js +350 -0
  228. package/dist/tests/source-resolve.test.js +100 -0
  229. package/dist/tests/source-source.test.js +221 -0
  230. package/dist/tests/source.test.js +533 -0
  231. package/dist/tests/tar-utils-scan.test.js +73 -0
  232. package/dist/tests/toggle-components.test.js +73 -0
  233. package/dist/tests/usage-telemetry.test.js +265 -0
  234. package/dist/tests/utility-scoring.test.js +558 -0
  235. package/dist/tests/vault-load-error.test.js +78 -0
  236. package/dist/tests/vault-qa-fixes.test.js +194 -0
  237. package/dist/tests/vault.test.js +429 -0
  238. package/dist/tests/vector-search.test.js +608 -0
  239. package/dist/tests/walker.test.js +252 -0
  240. package/dist/tests/wave2-cluster-bc.test.js +228 -0
  241. package/dist/tests/wave2-cluster-d.test.js +180 -0
  242. package/dist/tests/wave2-cluster-e.test.js +179 -0
  243. package/dist/tests/wiki-qa-fixes.test.js +270 -0
  244. package/dist/tests/wiki.test.js +529 -0
  245. package/dist/tests/workflow-cli.test.js +271 -0
  246. package/dist/tests/workflow-markdown.test.js +171 -0
  247. package/dist/tests/workflow-path-escape.test.js +132 -0
  248. package/dist/tests/workflow-qa-fixes.test.js +377 -0
  249. package/dist/tests/workflows/indexer-rejection.test.js +213 -0
  250. package/docs/README.md +8 -0
  251. package/docs/migration/release-notes/0.7.0.md +244 -0
  252. package/package.json +2 -2
  253. package/dist/core/warn.js +0 -27
  254. package/dist/output/shapes.js +0 -212
  255. /package/dist/{commands → src/commands}/completions.js +0 -0
  256. /package/dist/{commands → src/commands}/curate.js +0 -0
  257. /package/dist/{commands → src/commands}/info.js +0 -0
  258. /package/dist/{commands → src/commands}/init.js +0 -0
  259. /package/dist/{commands → src/commands}/install-audit.js +0 -0
  260. /package/dist/{commands → src/commands}/migration-help.js +0 -0
  261. /package/dist/{commands → src/commands}/source-add.js +0 -0
  262. /package/dist/{commands → src/commands}/source-clone.js +0 -0
  263. /package/dist/{commands → src/commands}/source-manage.js +0 -0
  264. /package/dist/{commands → src/commands}/vault.js +0 -0
  265. /package/dist/{core → src/core}/asset-registry.js +0 -0
  266. /package/dist/{core → src/core}/frontmatter.js +0 -0
  267. /package/dist/{core → src/core}/markdown.js +0 -0
  268. /package/dist/{core → src/core}/paths.js +0 -0
  269. /package/dist/{indexer → src/indexer}/manifest.js +0 -0
  270. /package/dist/{indexer → src/indexer}/matchers.js +0 -0
  271. /package/dist/{indexer → src/indexer}/search-fields.js +0 -0
  272. /package/dist/{indexer → src/indexer}/search-source.js +0 -0
  273. /package/dist/{indexer → src/indexer}/semantic-status.js +0 -0
  274. /package/dist/{indexer → src/indexer}/usage-events.js +0 -0
  275. /package/dist/{indexer → src/indexer}/walker.js +0 -0
  276. /package/dist/{integrations → src/integrations}/github.js +0 -0
  277. /package/dist/{llm → src/llm}/embedder.js +0 -0
  278. /package/dist/{llm → src/llm}/embedders/cache.js +0 -0
  279. /package/dist/{llm → src/llm}/embedders/local.js +0 -0
  280. /package/dist/{llm → src/llm}/embedders/remote.js +0 -0
  281. /package/dist/{llm → src/llm}/embedders/types.js +0 -0
  282. /package/dist/{llm → src/llm}/metadata-enhance.js +0 -0
  283. /package/dist/{output → src/output}/cli-hints.js +0 -0
  284. /package/dist/{output → src/output}/context.js +0 -0
  285. /package/dist/{registry → src/registry}/create-provider-registry.js +0 -0
  286. /package/dist/{registry → src/registry}/origin-resolve.js +0 -0
  287. /package/dist/{registry → src/registry}/providers/index.js +0 -0
  288. /package/dist/{registry → src/registry}/providers/skills-sh.js +0 -0
  289. /package/dist/{registry → src/registry}/providers/types.js +0 -0
  290. /package/dist/{registry → src/registry}/types.js +0 -0
  291. /package/dist/{setup → src/setup}/detect.js +0 -0
  292. /package/dist/{setup → src/setup}/ripgrep-install.js +0 -0
  293. /package/dist/{setup → src/setup}/ripgrep-resolve.js +0 -0
  294. /package/dist/{setup → src/setup}/steps.js +0 -0
  295. /package/dist/{sources → src/sources}/include.js +0 -0
  296. /package/dist/{sources → src/sources}/provider-factory.js +0 -0
  297. /package/dist/{sources → src/sources}/provider.js +0 -0
  298. /package/dist/{sources → src/sources}/providers/filesystem.js +0 -0
  299. /package/dist/{sources → src/sources}/providers/index.js +0 -0
  300. /package/dist/{sources → src/sources}/providers/install-types.js +0 -0
  301. /package/dist/{sources → src/sources}/providers/npm.js +0 -0
  302. /package/dist/{sources → src/sources}/providers/provider-utils.js +0 -0
  303. /package/dist/{sources → src/sources}/providers/sync-from-ref.js +0 -0
  304. /package/dist/{sources → src/sources}/providers/tar-utils.js +0 -0
  305. /package/dist/{sources → src/sources}/providers/website.js +0 -0
  306. /package/dist/{sources → src/sources}/resolve.js +0 -0
  307. /package/dist/{sources → src/sources}/types.js +0 -0
  308. /package/dist/{templates → src/templates}/wiki-templates.js +0 -0
  309. /package/dist/{version.js → src/version.js} +0 -0
  310. /package/dist/{wiki → src/wiki}/wiki.js +0 -0
  311. /package/dist/{workflows → src/workflows}/authoring.js +0 -0
  312. /package/dist/{workflows → src/workflows}/cli.js +0 -0
  313. /package/dist/{workflows → src/workflows}/db.js +0 -0
  314. /package/dist/{workflows → src/workflows}/document-cache.js +0 -0
  315. /package/dist/{workflows → src/workflows}/parser.js +0 -0
  316. /package/dist/{workflows → src/workflows}/renderer.js +0 -0
  317. /package/dist/{workflows → src/workflows}/runs.js +0 -0
  318. /package/dist/{workflows → src/workflows}/schema.js +0 -0
  319. /package/dist/{workflows → src/workflows}/validator.js +0 -0
@@ -0,0 +1,208 @@
1
+ /**
2
+ * Tests for the `akm distill --exclude-feedback-from` CLI flag (#267).
3
+ *
4
+ * The flag and the `AKM_DISTILL_EXCLUDE_FEEDBACK_FROM` env var both feed
5
+ * the same `excludeFeedbackFromRefs` option on `akmDistill`. We exercise
6
+ * the CLI dispatcher as a real subprocess so flag parsing + validation
7
+ * runs end-to-end, including the UsageError → exit 2 contract for invalid
8
+ * refs.
9
+ */
10
+ import { afterAll, describe, expect, test } from "bun:test";
11
+ import { spawnSync } from "node:child_process";
12
+ import fs from "node:fs";
13
+ import os from "node:os";
14
+ import path from "node:path";
15
+ const tempDirs = [];
16
+ function makeTempDir(prefix = "akm-distill-cli-") {
17
+ const dir = fs.mkdtempSync(path.join(os.tmpdir(), prefix));
18
+ tempDirs.push(dir);
19
+ return dir;
20
+ }
21
+ afterAll(() => {
22
+ for (const dir of tempDirs) {
23
+ fs.rmSync(dir, { recursive: true, force: true });
24
+ }
25
+ });
26
+ const repoRoot = path.resolve(import.meta.dir, "..");
27
+ const cliPath = path.join(repoRoot, "src", "cli.ts");
28
+ function runCli(args, options) {
29
+ const xdgCache = makeTempDir("akm-distill-cli-cache-");
30
+ const xdgConfig = makeTempDir("akm-distill-cli-config-");
31
+ const home = makeTempDir("akm-distill-cli-home-");
32
+ const result = spawnSync("bun", [cliPath, ...args], {
33
+ encoding: "utf8",
34
+ timeout: 15_000,
35
+ cwd: repoRoot,
36
+ env: {
37
+ ...process.env,
38
+ AKM_STASH_DIR: undefined,
39
+ HOME: home,
40
+ XDG_CACHE_HOME: xdgCache,
41
+ XDG_CONFIG_HOME: xdgConfig,
42
+ ...options?.env,
43
+ },
44
+ });
45
+ return {
46
+ stdout: result.stdout ?? "",
47
+ stderr: result.stderr ?? "",
48
+ status: result.status ?? -1,
49
+ };
50
+ }
51
+ describe("akm distill --exclude-feedback-from flag (#267)", () => {
52
+ test("invalid ref in --exclude-feedback-from → exits 2 (USAGE)", () => {
53
+ const result = runCli(["distill", "skill:foo", "--exclude-feedback-from", "not-a-ref"]);
54
+ expect(result.status).toBe(2);
55
+ // Error envelope is JSON on stderr.
56
+ expect(result.stderr).toContain("Invalid --exclude-feedback-from ref");
57
+ expect(result.stderr).toContain("not-a-ref");
58
+ });
59
+ test("invalid ref in env var fallback → also exits 2", () => {
60
+ const result = runCli(["distill", "skill:foo"], {
61
+ env: { AKM_DISTILL_EXCLUDE_FEEDBACK_FROM: "this-is-not-a-ref" },
62
+ });
63
+ expect(result.status).toBe(2);
64
+ expect(result.stderr).toContain("Invalid --exclude-feedback-from ref");
65
+ });
66
+ test("multiple invalid refs surface the first failure", () => {
67
+ const result = runCli(["distill", "skill:foo", "--exclude-feedback-from", "skill:ok,bad-ref,memory:also-ok"]);
68
+ expect(result.status).toBe(2);
69
+ expect(result.stderr).toContain("bad-ref");
70
+ });
71
+ test("valid CSV refs parse without flag-parse panic (smoke)", () => {
72
+ // The command will likely fail downstream because no llm config exists
73
+ // and no asset is indexed, but flag parsing must not be the failure
74
+ // mode — assert exit != 2 (anything but USAGE), or accept 0/1.
75
+ const result = runCli(["distill", "skill:foo", "--exclude-feedback-from", "skill:bar,memory:baz"]);
76
+ expect(result.status).not.toBe(2);
77
+ });
78
+ test("env var with valid CSV parses without crash", () => {
79
+ const result = runCli(["distill", "skill:foo"], {
80
+ env: { AKM_DISTILL_EXCLUDE_FEEDBACK_FROM: "skill:a,memory:b" },
81
+ });
82
+ expect(result.status).not.toBe(2);
83
+ });
84
+ test("origin-prefixed refs are accepted", () => {
85
+ const result = runCli(["distill", "skill:foo", "--exclude-feedback-from", "team//skill:bar,npm:pkg//memory:baz"]);
86
+ expect(result.status).not.toBe(2);
87
+ });
88
+ test("empty --exclude-feedback-from value is treated as no exclusion (no parse error)", () => {
89
+ const result = runCli(["distill", "skill:foo", "--exclude-feedback-from", ""]);
90
+ expect(result.status).not.toBe(2);
91
+ });
92
+ test("CLI flag takes precedence over env var (the flag is parsed regardless of env value)", () => {
93
+ // If precedence were wrong, the invalid env var would surface first.
94
+ // With correct precedence, the valid flag wins and no UsageError fires.
95
+ const result = runCli(["distill", "skill:foo", "--exclude-feedback-from", "skill:valid"], {
96
+ env: { AKM_DISTILL_EXCLUDE_FEEDBACK_FROM: "this-would-be-invalid" },
97
+ });
98
+ expect(result.status).not.toBe(2);
99
+ });
100
+ // ── #284 GAP-CRIT 3 backfill ──────────────────────────────────────────────
101
+ test("--source-run flag is accepted by the CLI parser (flag wiring smoke)", () => {
102
+ // No llm config → command exits non-zero (0/1) but must not be a USAGE
103
+ // error — flag parsing for `--source-run` is the only thing under test.
104
+ const result = runCli(["distill", "skill:foo", "--source-run", "run-abc-123"]);
105
+ expect(result.status).not.toBe(2);
106
+ // stderr (if present) should NOT mention --source-run as an unknown flag.
107
+ expect(result.stderr).not.toMatch(/unknown.*--source-run|invalid.*--source-run/i);
108
+ });
109
+ test("AKM_DISTILL_EXCLUDE_FEEDBACK_FROM env-fallback is read when --exclude-feedback-from is omitted", () => {
110
+ // Drives the env-fallback branch in src/cli.ts:
111
+ // const excludeRaw = excludeFlag ?? excludeEnv;
112
+ // An invalid env value must surface as USAGE (exit 2) → proves the fallback ran.
113
+ const result = runCli(["distill", "skill:foo"], {
114
+ env: { AKM_DISTILL_EXCLUDE_FEEDBACK_FROM: "this-is-not-a-ref" },
115
+ });
116
+ expect(result.status).toBe(2);
117
+ expect(result.stderr).toContain("Invalid --exclude-feedback-from ref");
118
+ });
119
+ });
120
+ // ── #284 GAP-CRIT 3: distill happy-path via injected chat seam ─────────────
121
+ //
122
+ // Spawning the real CLI cannot exercise the LLM happy path without a real
123
+ // endpoint, so we drive `akmDistill` with the same seams as `tests/distill.test.ts`
124
+ // to lock the success contract: outcome=queued, exit=0 (when wrapped via
125
+ // runWithJsonErrors in the CLI), proposal materialised in the queue.
126
+ import { afterEach as afterEachHappy, beforeEach as beforeEachHappy, describe as describeHappy, expect as expectHappy, test as testHappy, } from "bun:test";
127
+ import { akmDistill } from "../src/commands/distill";
128
+ import { listProposals } from "../src/core/proposals";
129
+ const happyTempDirs = [];
130
+ function happyTempDir(prefix) {
131
+ const dir = fs.mkdtempSync(path.join(os.tmpdir(), prefix));
132
+ happyTempDirs.push(dir);
133
+ return dir;
134
+ }
135
+ function happyStash() {
136
+ const stash = happyTempDir("akm-distill-happy-stash-");
137
+ for (const sub of ["lessons", "skills", "memories"]) {
138
+ fs.mkdirSync(path.join(stash, sub), { recursive: true });
139
+ }
140
+ return stash;
141
+ }
142
+ const HAPPY_LESSON = `---
143
+ description: Prefer ripgrep over grep on large repos
144
+ when_to_use: Searching for symbols across a multi-thousand-file repo
145
+ ---
146
+
147
+ Use rg.
148
+ `;
149
+ beforeEachHappy(() => {
150
+ process.env.XDG_CACHE_HOME = happyTempDir("akm-distill-happy-cache-");
151
+ process.env.XDG_CONFIG_HOME = happyTempDir("akm-distill-happy-config-");
152
+ });
153
+ afterEachHappy(() => {
154
+ for (const dir of happyTempDirs.splice(0)) {
155
+ fs.rmSync(dir, { recursive: true, force: true });
156
+ }
157
+ });
158
+ describeHappy("akm distill happy-path (#284 CRIT 3)", () => {
159
+ testHappy("LLM stub returns valid lesson → outcome=queued, proposal in queue", async () => {
160
+ const stash = happyStash();
161
+ const config = {
162
+ stashDir: stash,
163
+ sources: [{ type: "filesystem", name: "stash", path: stash, writable: true }],
164
+ defaultWriteTarget: "stash",
165
+ llm: {
166
+ endpoint: "http://localhost:11434/v1/chat/completions",
167
+ model: "test-model",
168
+ features: { feedback_distillation: true },
169
+ },
170
+ };
171
+ const result = await akmDistill({
172
+ ref: "skill:deploy",
173
+ config,
174
+ stashDir: stash,
175
+ chat: async () => HAPPY_LESSON,
176
+ lookupFn: async () => null,
177
+ readEventsFn: (() => ({ events: [], nextOffset: 0 })),
178
+ });
179
+ expectHappy(result.outcome).toBe("queued");
180
+ expectHappy(typeof result.proposalId).toBe("string");
181
+ expectHappy(listProposals(stash).length).toBe(1);
182
+ });
183
+ testHappy("--source-run sourceRun param threads onto the queued proposal", async () => {
184
+ const stash = happyStash();
185
+ const config = {
186
+ stashDir: stash,
187
+ sources: [{ type: "filesystem", name: "stash", path: stash, writable: true }],
188
+ defaultWriteTarget: "stash",
189
+ llm: {
190
+ endpoint: "http://localhost:11434/v1/chat/completions",
191
+ model: "test-model",
192
+ features: { feedback_distillation: true },
193
+ },
194
+ };
195
+ const result = await akmDistill({
196
+ ref: "skill:deploy",
197
+ config,
198
+ stashDir: stash,
199
+ chat: async () => HAPPY_LESSON,
200
+ lookupFn: async () => null,
201
+ readEventsFn: (() => ({ events: [], nextOffset: 0 })),
202
+ sourceRun: "run-abc-123",
203
+ });
204
+ expectHappy(result.outcome).toBe("queued");
205
+ const proposals = listProposals(stash);
206
+ expectHappy(proposals[0]?.sourceRun).toBe("run-abc-123");
207
+ });
208
+ });