@smeltjs/core 0.2.0 → 0.3.0

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/README.md +3 -3
  2. package/dist/apply.d.ts.map +1 -1
  3. package/dist/apply.js.map +1 -1
  4. package/dist/cache/prefix.d.ts.map +1 -1
  5. package/dist/cache/prefix.js.map +1 -1
  6. package/dist/cli/args.d.ts +16 -70
  7. package/dist/cli/args.d.ts.map +1 -1
  8. package/dist/cli/args.js +18 -338
  9. package/dist/cli/args.js.map +1 -1
  10. package/dist/cli/bin.d.ts.map +1 -1
  11. package/dist/cli/bin.js.map +1 -1
  12. package/dist/cli/config.d.ts +40 -0
  13. package/dist/cli/config.d.ts.map +1 -1
  14. package/dist/cli/config.js +55 -1
  15. package/dist/cli/config.js.map +1 -1
  16. package/dist/cli/hooks.d.ts +33 -38
  17. package/dist/cli/hooks.d.ts.map +1 -1
  18. package/dist/cli/hooks.js +140 -485
  19. package/dist/cli/hooks.js.map +1 -1
  20. package/dist/cli/init.d.ts +30 -15
  21. package/dist/cli/init.d.ts.map +1 -1
  22. package/dist/cli/init.js +167 -38
  23. package/dist/cli/init.js.map +1 -1
  24. package/dist/cli/report.d.ts.map +1 -1
  25. package/dist/cli/report.js +2 -2
  26. package/dist/cli/report.js.map +1 -1
  27. package/dist/cli/run.d.ts +25 -88
  28. package/dist/cli/run.d.ts.map +1 -1
  29. package/dist/cli/run.js +32 -341
  30. package/dist/cli/run.js.map +1 -1
  31. package/dist/cli/shell.d.ts +106 -0
  32. package/dist/cli/shell.d.ts.map +1 -0
  33. package/dist/cli/shell.js +100 -0
  34. package/dist/cli/shell.js.map +1 -0
  35. package/dist/cli/subcommands/flags.d.ts +141 -0
  36. package/dist/cli/subcommands/flags.d.ts.map +1 -0
  37. package/dist/cli/subcommands/flags.js +208 -0
  38. package/dist/cli/subcommands/flags.js.map +1 -0
  39. package/dist/cli/subcommands/hooks.d.ts +18 -0
  40. package/dist/cli/subcommands/hooks.d.ts.map +1 -0
  41. package/dist/cli/subcommands/hooks.js +64 -0
  42. package/dist/cli/subcommands/hooks.js.map +1 -0
  43. package/dist/cli/subcommands/init.d.ts +19 -0
  44. package/dist/cli/subcommands/init.d.ts.map +1 -0
  45. package/dist/cli/subcommands/init.js +44 -0
  46. package/dist/cli/subcommands/init.js.map +1 -0
  47. package/dist/cli/subcommands/map.d.ts +75 -0
  48. package/dist/cli/subcommands/map.d.ts.map +1 -0
  49. package/dist/cli/subcommands/map.js +132 -0
  50. package/dist/cli/subcommands/map.js.map +1 -0
  51. package/dist/cli/subcommands/registry.d.ts +80 -0
  52. package/dist/cli/subcommands/registry.d.ts.map +1 -0
  53. package/dist/cli/subcommands/registry.js +138 -0
  54. package/dist/cli/subcommands/registry.js.map +1 -0
  55. package/dist/cli/subcommands/retrieve.d.ts +74 -0
  56. package/dist/cli/subcommands/retrieve.d.ts.map +1 -0
  57. package/dist/cli/subcommands/retrieve.js +84 -0
  58. package/dist/cli/subcommands/retrieve.js.map +1 -0
  59. package/dist/cli/subcommands/smelt.d.ts +107 -0
  60. package/dist/cli/subcommands/smelt.d.ts.map +1 -0
  61. package/dist/cli/subcommands/smelt.js +304 -0
  62. package/dist/cli/subcommands/smelt.js.map +1 -0
  63. package/dist/cli/subcommands/stats.d.ts +43 -0
  64. package/dist/cli/subcommands/stats.d.ts.map +1 -0
  65. package/dist/cli/subcommands/stats.js +62 -0
  66. package/dist/cli/subcommands/stats.js.map +1 -0
  67. package/dist/cli/subcommands/subcommand.d.ts +113 -0
  68. package/dist/cli/subcommands/subcommand.d.ts.map +1 -0
  69. package/dist/cli/subcommands/subcommand.js +3 -0
  70. package/dist/cli/subcommands/subcommand.js.map +1 -0
  71. package/dist/cli/usage.d.ts +3 -0
  72. package/dist/cli/usage.d.ts.map +1 -0
  73. package/dist/cli/usage.js +95 -0
  74. package/dist/cli/usage.js.map +1 -0
  75. package/dist/detect.d.ts.map +1 -1
  76. package/dist/detect.js.map +1 -1
  77. package/dist/errors.d.ts +21 -1
  78. package/dist/errors.d.ts.map +1 -1
  79. package/dist/errors.js +33 -1
  80. package/dist/errors.js.map +1 -1
  81. package/dist/harness/aider.d.ts +10 -0
  82. package/dist/harness/aider.d.ts.map +1 -0
  83. package/dist/harness/aider.js +21 -0
  84. package/dist/harness/aider.js.map +1 -0
  85. package/dist/harness/claude-code.d.ts +3 -0
  86. package/dist/harness/claude-code.d.ts.map +1 -0
  87. package/dist/harness/claude-code.js +68 -0
  88. package/dist/harness/claude-code.js.map +1 -0
  89. package/dist/harness/cline.d.ts +3 -0
  90. package/dist/harness/cline.d.ts.map +1 -0
  91. package/dist/harness/cline.js +54 -0
  92. package/dist/harness/cline.js.map +1 -0
  93. package/dist/harness/codex.d.ts +3 -0
  94. package/dist/harness/codex.d.ts.map +1 -0
  95. package/dist/harness/codex.js +91 -0
  96. package/dist/harness/codex.js.map +1 -0
  97. package/dist/harness/cursor.d.ts +3 -0
  98. package/dist/harness/cursor.d.ts.map +1 -0
  99. package/dist/harness/cursor.js +54 -0
  100. package/dist/harness/cursor.js.map +1 -0
  101. package/dist/harness/gemini.d.ts +3 -0
  102. package/dist/harness/gemini.d.ts.map +1 -0
  103. package/dist/harness/gemini.js +59 -0
  104. package/dist/harness/gemini.js.map +1 -0
  105. package/dist/harness/grok.d.ts +3 -0
  106. package/dist/harness/grok.d.ts.map +1 -0
  107. package/dist/harness/grok.js +46 -0
  108. package/dist/harness/grok.js.map +1 -0
  109. package/dist/harness/hermes.d.ts +3 -0
  110. package/dist/harness/hermes.d.ts.map +1 -0
  111. package/dist/harness/hermes.js +71 -0
  112. package/dist/harness/hermes.js.map +1 -0
  113. package/dist/harness/kilocode.d.ts +3 -0
  114. package/dist/harness/kilocode.d.ts.map +1 -0
  115. package/dist/harness/kilocode.js +35 -0
  116. package/dist/harness/kilocode.js.map +1 -0
  117. package/dist/harness/opencode.d.ts +3 -0
  118. package/dist/harness/opencode.d.ts.map +1 -0
  119. package/dist/harness/opencode.js +97 -0
  120. package/dist/harness/opencode.js.map +1 -0
  121. package/dist/harness/paths.d.ts +17 -0
  122. package/dist/harness/paths.d.ts.map +1 -0
  123. package/dist/harness/paths.js +45 -0
  124. package/dist/harness/paths.js.map +1 -0
  125. package/dist/harness/profile.d.ts +184 -0
  126. package/dist/harness/profile.d.ts.map +1 -0
  127. package/dist/harness/profile.js +26 -0
  128. package/dist/harness/profile.js.map +1 -0
  129. package/dist/harness/registry.d.ts +51 -0
  130. package/dist/harness/registry.d.ts.map +1 -0
  131. package/dist/harness/registry.js +87 -0
  132. package/dist/harness/registry.js.map +1 -0
  133. package/dist/harness/snippet.d.ts +19 -0
  134. package/dist/harness/snippet.d.ts.map +1 -0
  135. package/dist/harness/snippet.js +41 -0
  136. package/dist/harness/snippet.js.map +1 -0
  137. package/dist/hash.d.ts.map +1 -1
  138. package/dist/hash.js.map +1 -1
  139. package/dist/hooks/guard-core.d.ts +14 -14
  140. package/dist/hooks/guard-core.d.ts.map +1 -1
  141. package/dist/hooks/guard-core.js +15 -37
  142. package/dist/hooks/guard-core.js.map +1 -1
  143. package/dist/hooks/shim.d.ts +95 -4
  144. package/dist/hooks/shim.d.ts.map +1 -1
  145. package/dist/hooks/shim.js +87 -2
  146. package/dist/hooks/shim.js.map +1 -1
  147. package/dist/hooks/shims/claude-code.d.ts +5 -18
  148. package/dist/hooks/shims/claude-code.d.ts.map +1 -1
  149. package/dist/hooks/shims/claude-code.js +9 -56
  150. package/dist/hooks/shims/claude-code.js.map +1 -1
  151. package/dist/hooks/shims/cline.d.ts +5 -12
  152. package/dist/hooks/shims/cline.d.ts.map +1 -1
  153. package/dist/hooks/shims/cline.js +9 -34
  154. package/dist/hooks/shims/cline.js.map +1 -1
  155. package/dist/hooks/shims/codex.d.ts +5 -18
  156. package/dist/hooks/shims/codex.d.ts.map +1 -1
  157. package/dist/hooks/shims/codex.js +9 -51
  158. package/dist/hooks/shims/codex.js.map +1 -1
  159. package/dist/hooks/shims/cursor.d.ts +5 -14
  160. package/dist/hooks/shims/cursor.d.ts.map +1 -1
  161. package/dist/hooks/shims/cursor.js +9 -42
  162. package/dist/hooks/shims/cursor.js.map +1 -1
  163. package/dist/hooks/shims/gemini.d.ts +5 -18
  164. package/dist/hooks/shims/gemini.d.ts.map +1 -1
  165. package/dist/hooks/shims/gemini.js +9 -48
  166. package/dist/hooks/shims/gemini.js.map +1 -1
  167. package/dist/hooks/shims/grok.d.ts +5 -13
  168. package/dist/hooks/shims/grok.d.ts.map +1 -1
  169. package/dist/hooks/shims/grok.js +9 -32
  170. package/dist/hooks/shims/grok.js.map +1 -1
  171. package/dist/hooks/shims/hermes.d.ts +5 -17
  172. package/dist/hooks/shims/hermes.d.ts.map +1 -1
  173. package/dist/hooks/shims/hermes.js +9 -45
  174. package/dist/hooks/shims/hermes.js.map +1 -1
  175. package/dist/index.d.ts +33 -76
  176. package/dist/index.d.ts.map +1 -1
  177. package/dist/index.js +13 -67
  178. package/dist/index.js.map +1 -1
  179. package/dist/lang/bash.d.ts.map +1 -1
  180. package/dist/lang/bash.js.map +1 -1
  181. package/dist/lang/c.d.ts.map +1 -1
  182. package/dist/lang/c.js.map +1 -1
  183. package/dist/lang/c_sharp.d.ts.map +1 -1
  184. package/dist/lang/c_sharp.js.map +1 -1
  185. package/dist/lang/cpp.d.ts.map +1 -1
  186. package/dist/lang/cpp.js.map +1 -1
  187. package/dist/lang/go.d.ts.map +1 -1
  188. package/dist/lang/go.js.map +1 -1
  189. package/dist/lang/java.d.ts.map +1 -1
  190. package/dist/lang/java.js.map +1 -1
  191. package/dist/lang/javascript.d.ts.map +1 -1
  192. package/dist/lang/javascript.js.map +1 -1
  193. package/dist/lang/kotlin.d.ts.map +1 -1
  194. package/dist/lang/kotlin.js.map +1 -1
  195. package/dist/lang/php.d.ts.map +1 -1
  196. package/dist/lang/php.js.map +1 -1
  197. package/dist/lang/profile.d.ts.map +1 -1
  198. package/dist/lang/profile.js.map +1 -1
  199. package/dist/lang/python.d.ts.map +1 -1
  200. package/dist/lang/python.js.map +1 -1
  201. package/dist/lang/registry.d.ts.map +1 -1
  202. package/dist/lang/registry.js.map +1 -1
  203. package/dist/lang/ruby.d.ts.map +1 -1
  204. package/dist/lang/ruby.js.map +1 -1
  205. package/dist/lang/rust.d.ts.map +1 -1
  206. package/dist/lang/rust.js.map +1 -1
  207. package/dist/lang/swift.d.ts.map +1 -1
  208. package/dist/lang/swift.js.map +1 -1
  209. package/dist/lang/tsx.d.ts.map +1 -1
  210. package/dist/lang/tsx.js.map +1 -1
  211. package/dist/lang/typescript.d.ts.map +1 -1
  212. package/dist/lang/typescript.js.map +1 -1
  213. package/dist/net/policy.d.ts +18 -1
  214. package/dist/net/policy.d.ts.map +1 -1
  215. package/dist/net/policy.js +6 -4
  216. package/dist/net/policy.js.map +1 -1
  217. package/dist/ops/index.d.ts +39 -0
  218. package/dist/ops/index.d.ts.map +1 -0
  219. package/dist/ops/index.js +37 -0
  220. package/dist/ops/index.js.map +1 -0
  221. package/dist/ops/inputs.d.ts +170 -0
  222. package/dist/ops/inputs.d.ts.map +1 -0
  223. package/dist/ops/inputs.js +142 -0
  224. package/dist/ops/inputs.js.map +1 -0
  225. package/dist/ops/verbs.d.ts +136 -0
  226. package/dist/ops/verbs.d.ts.map +1 -0
  227. package/dist/ops/verbs.js +76 -0
  228. package/dist/ops/verbs.js.map +1 -0
  229. package/dist/plan/auto.d.ts +69 -0
  230. package/dist/plan/auto.d.ts.map +1 -0
  231. package/dist/plan/auto.js +70 -0
  232. package/dist/plan/auto.js.map +1 -0
  233. package/dist/plan/budget.d.ts +21 -0
  234. package/dist/plan/budget.d.ts.map +1 -0
  235. package/dist/plan/budget.js +26 -0
  236. package/dist/plan/budget.js.map +1 -0
  237. package/dist/plan/grammar.d.ts +14 -0
  238. package/dist/plan/grammar.d.ts.map +1 -1
  239. package/dist/plan/grammar.js +47 -6
  240. package/dist/plan/grammar.js.map +1 -1
  241. package/dist/plan/lexical.d.ts.map +1 -1
  242. package/dist/plan/lexical.js +1 -7
  243. package/dist/plan/lexical.js.map +1 -1
  244. package/dist/plan/planners.d.ts +35 -2
  245. package/dist/plan/planners.d.ts.map +1 -1
  246. package/dist/plan/planners.js +35 -2
  247. package/dist/plan/planners.js.map +1 -1
  248. package/dist/plan/structural.d.ts +19 -5
  249. package/dist/plan/structural.d.ts.map +1 -1
  250. package/dist/plan/structural.js +180 -33
  251. package/dist/plan/structural.js.map +1 -1
  252. package/dist/repomap/cache.d.ts +48 -0
  253. package/dist/repomap/cache.d.ts.map +1 -1
  254. package/dist/repomap/cache.js +112 -13
  255. package/dist/repomap/cache.js.map +1 -1
  256. package/dist/repomap/io.d.ts +24 -0
  257. package/dist/repomap/io.d.ts.map +1 -0
  258. package/dist/repomap/io.js +34 -0
  259. package/dist/repomap/io.js.map +1 -0
  260. package/dist/repomap/map.d.ts +69 -6
  261. package/dist/repomap/map.d.ts.map +1 -1
  262. package/dist/repomap/map.js +104 -22
  263. package/dist/repomap/map.js.map +1 -1
  264. package/dist/repomap/rank.d.ts +26 -2
  265. package/dist/repomap/rank.d.ts.map +1 -1
  266. package/dist/repomap/rank.js +20 -0
  267. package/dist/repomap/rank.js.map +1 -1
  268. package/dist/repomap/reader.d.ts +73 -0
  269. package/dist/repomap/reader.d.ts.map +1 -0
  270. package/dist/repomap/reader.js +30 -0
  271. package/dist/repomap/reader.js.map +1 -0
  272. package/dist/repomap/tags.d.ts.map +1 -1
  273. package/dist/repomap/tags.js.map +1 -1
  274. package/dist/retrieve.d.ts +8 -0
  275. package/dist/retrieve.d.ts.map +1 -1
  276. package/dist/retrieve.js +12 -1
  277. package/dist/retrieve.js.map +1 -1
  278. package/dist/smelter.d.ts +79 -0
  279. package/dist/smelter.d.ts.map +1 -0
  280. package/dist/smelter.js +65 -0
  281. package/dist/smelter.js.map +1 -0
  282. package/dist/stages.d.ts.map +1 -1
  283. package/dist/stages.js +2 -2
  284. package/dist/stages.js.map +1 -1
  285. package/dist/stats.d.ts +2 -1
  286. package/dist/stats.d.ts.map +1 -1
  287. package/dist/stats.js +2 -1
  288. package/dist/stats.js.map +1 -1
  289. package/dist/store-dir.d.ts +43 -4
  290. package/dist/store-dir.d.ts.map +1 -1
  291. package/dist/store-dir.js +48 -5
  292. package/dist/store-dir.js.map +1 -1
  293. package/dist/store.d.ts +6 -0
  294. package/dist/store.d.ts.map +1 -1
  295. package/dist/store.js +6 -0
  296. package/dist/store.js.map +1 -1
  297. package/dist/types.d.ts +35 -3
  298. package/dist/types.d.ts.map +1 -1
  299. package/dist/types.js.map +1 -1
  300. package/grammars/tree-sitter-bash.wasm +0 -0
  301. package/grammars/tree-sitter-c.wasm +0 -0
  302. package/grammars/tree-sitter-c_sharp.wasm +0 -0
  303. package/grammars/tree-sitter-cpp.wasm +0 -0
  304. package/grammars/tree-sitter-go.wasm +0 -0
  305. package/grammars/tree-sitter-java.wasm +0 -0
  306. package/grammars/tree-sitter-javascript.wasm +0 -0
  307. package/grammars/tree-sitter-kotlin.wasm +0 -0
  308. package/grammars/tree-sitter-php.wasm +0 -0
  309. package/grammars/tree-sitter-python.wasm +0 -0
  310. package/grammars/tree-sitter-ruby.wasm +0 -0
  311. package/grammars/tree-sitter-rust.wasm +0 -0
  312. package/grammars/tree-sitter-swift.wasm +0 -0
  313. package/grammars/tree-sitter-tsx.wasm +0 -0
  314. package/grammars/tree-sitter-typescript.wasm +0 -0
  315. package/package.json +11 -11
  316. package/dist/cli/resolve.d.ts +0 -103
  317. package/dist/cli/resolve.d.ts.map +0 -1
  318. package/dist/cli/resolve.js +0 -106
  319. package/dist/cli/resolve.js.map +0 -1
package/dist/cli/init.js CHANGED
@@ -1,10 +1,10 @@
1
1
  import { existsSync, readFileSync, writeFileSync } from 'node:fs';
2
- import { dirname, join } from 'node:path';
3
- import { createInterface } from 'node:readline/promises';
2
+ import { dirname, join, resolve } from 'node:path';
4
3
  import { CliUsageError } from '../errors.js';
4
+ import { DEFAULT_STRATEGY, STRATEGIES } from '../plan/planners.js';
5
5
  import { STRUCTURAL_LANGUAGES } from '../plan/structural.js';
6
- import { CLI_NAME } from './args.js';
7
- import { CONFIG_FILE_NAME, CONFIG_VERSION, findConfigFile, parseConfig } from './config.js';
6
+ import { answerReader, CLI_NAME } from './shell.js';
7
+ import { CONFIG_FILE_NAME, CONFIG_VERSION, findConfigFile, parseConfig, renderConfig, } from './config.js';
8
8
  /**
9
9
  * `smelt init` — the setup wizard.
10
10
  *
@@ -20,7 +20,15 @@ import { CONFIG_FILE_NAME, CONFIG_VERSION, findConfigFile, parseConfig } from '.
20
20
  * a global "overwrite all", not a default — one question per existing file, and
21
21
  * anything but a literal `yes` skips it. Guarded by
22
22
  * `test/guards/init-wizard.test.ts`, with a mutation proving the guard goes red.
23
- * 3. **Every step accepts `back`.** A wizard you cannot reverse inside is a form.
23
+ * 3. **Every step accepts `back`.** A wizard you cannot reverse inside is a form. That
24
+ * includes the directory question a fresh run asks inside a workspace: `back` from
25
+ * the first step returns to it, keeping the answers given since.
26
+ * 4. **Everything lands in one named directory.** A fresh run inside a workspace asks
27
+ * which end of config discovery to write to (see `chooseDirectory`) and an edit run
28
+ * writes beside the config it found; either way the directory is printed in the
29
+ * "About to write" listing before the confirm, and nothing is ever written outside
30
+ * it. A wizard that writes where the user cannot see is a wizard writing somewhere
31
+ * they did not agree to.
24
32
  *
25
33
  * Law 4 note: the wizard's copy states what each choice *does*, never what it saves —
26
34
  * no percentages, no rates, no numbers smelt has not measured.
@@ -37,16 +45,18 @@ export const RERANK_STUB_FILE = 'smelt.rerank.ts';
37
45
  * the wizard finishes — both are usage-shaped, and nothing further is written.
38
46
  */
39
47
  export async function runInit(io) {
40
- const rl = createInterface({ input: io.input });
41
- const lines = rl[Symbol.asyncIterator]();
48
+ // `answerReader` not `Readable.from` + readline — because the wizard must *let go*
49
+ // of stdin when it is done. See the note on `answerReader` for the hang that shape
50
+ // caused: files written, `Done.` printed, and the process never exiting.
51
+ const lines = answerReader(io.input);
42
52
  const ask = async (prompt) => {
43
53
  io.output(prompt);
44
54
  const next = await lines.next();
45
- if (next.done === true) {
55
+ if (next === undefined) {
46
56
  throw new CliUsageError(`${CLI_NAME} init: input ended before the wizard finished. ` +
47
57
  `Files already confirmed and written stay; nothing further was written.`);
48
58
  }
49
- return next.value.trim();
59
+ return next.trim();
50
60
  };
51
61
  try {
52
62
  const existing = loadExisting(io.cwd);
@@ -55,7 +65,7 @@ export async function runInit(io) {
55
65
  : await editRun(io, ask, existing.path, existing.config);
56
66
  }
57
67
  finally {
58
- rl.close();
68
+ await lines.release();
59
69
  }
60
70
  }
61
71
  function loadExisting(cwd) {
@@ -74,43 +84,144 @@ const STEPS = [
74
84
  { id: 'rerank', run: stepRerank },
75
85
  ];
76
86
  async function freshRun(io, ask) {
77
- io.output(`${CLI_NAME} init — sets up ${CONFIG_FILE_NAME} in ${io.cwd}.\n` +
78
- `Answer \`back\` at any step to return to the previous one. ` +
79
- `Nothing is written until you confirm at the end.\n\n`);
80
87
  const choices = {
81
88
  budgetBytes: undefined,
82
89
  store: { kind: 'memory' },
83
- strategy: 'lexical',
90
+ strategy: DEFAULT_STRATEGY,
84
91
  measureStub: false,
85
92
  rerankStub: false,
86
93
  hooks: undefined,
87
94
  };
95
+ // Outside a workspace there is no directory question, so the first step really is the
96
+ // first thing asked. Inside one there is, and `back` from the first step returns to it
97
+ // — with every answer so far carried along, because reversing is not restarting.
98
+ const root = findWorkspaceRoot(io.cwd);
99
+ for (;;) {
100
+ const dir = root === undefined ? io.cwd : await chooseDirectory(io, ask, root);
101
+ io.output(`${CLI_NAME} init — sets up ${CONFIG_FILE_NAME} in ${dir}.\n` +
102
+ `A run reads the nearest ${CONFIG_FILE_NAME}, walking UP from the directory it ` +
103
+ `is run in, so this one is found from ${dir} and everything below it.\n` +
104
+ `Answer \`back\` at any step to return to the previous one. ` +
105
+ `Nothing is written until you confirm at the end.\n\n`);
106
+ if ((await runSteps(io, ask, choices, dir, root !== undefined)) === 'done')
107
+ return 0;
108
+ }
109
+ }
110
+ /**
111
+ * The step loop for one chosen directory: every step, then the confirm, with `back`
112
+ * reversing all the way through both. Returns `'directory'` when `back` walks off the
113
+ * front and there is a directory question to walk back into — `freshRun` re-asks it and
114
+ * calls this again with the same {@link WizardChoices}.
115
+ */
116
+ async function runSteps(io, ask, choices, dir, canReopenDirectory) {
88
117
  let index = 0;
89
118
  for (;;) {
90
119
  while (index < STEPS.length) {
91
- const outcome = await STEPS[index].run(io, ask, choices, io.cwd);
92
- if (outcome === 'back') {
93
- if (index === 0)
94
- io.output(`This is the first step — there is nothing before it.\n`);
95
- else
96
- index -= 1;
120
+ const outcome = await STEPS[index].run(io, ask, choices, dir);
121
+ if (outcome !== 'back') {
122
+ index += 1;
123
+ }
124
+ else if (index > 0) {
125
+ index -= 1;
126
+ }
127
+ else if (canReopenDirectory) {
128
+ return 'directory';
97
129
  }
98
130
  else {
99
- index += 1;
131
+ io.output(`This is the first step — there is nothing before it.\n`);
100
132
  }
101
133
  }
102
- const verdict = await confirmAndWrite(io, ask, choices, io.cwd);
134
+ const verdict = await confirmAndWrite(io, ask, choices, dir);
103
135
  if (verdict !== 'back')
104
- return 0;
136
+ return 'done';
105
137
  index = STEPS.length - 1;
106
138
  }
107
139
  }
140
+ /**
141
+ * Which directory this fresh run writes into — and the wizard's answer to the
142
+ * monorepo trap.
143
+ *
144
+ * `smelt init` in `packages/web` used to write a config in `packages/web`, silently,
145
+ * while discovery walks **up**: every run from the repo root then found no config and
146
+ * used none, and the user had watched themselves set a budget. So when the working
147
+ * directory sits inside a workspace (`pnpm-workspace.yaml`, or a `package.json` with a
148
+ * `workspaces` field, in any ancestor), the wizard states the discovery rule and asks
149
+ * which end of it to write to, defaulting to the root that covers the whole tree.
150
+ *
151
+ * The answer becomes the directory every later step, the "About to write" listing and
152
+ * every `writeFileSync` uses — so the wizard still writes only inside the one directory
153
+ * the user was shown and confirmed, here as much as anywhere else. Outside a workspace
154
+ * there is nothing to choose and nothing is asked; the discovery rule is stated either
155
+ * way, because "where will runs look for this?" is not a question a user should have to
156
+ * infer from a path.
157
+ *
158
+ * Rule 3 holds here too: this is genuinely the first question, so `back` at it has
159
+ * nowhere to go — but `back` from the first *step* comes back to it (see `freshRun`),
160
+ * carrying the answers already given. The most consequential question in the wizard is
161
+ * not the one you cannot reverse into.
162
+ */
163
+ async function chooseDirectory(io, ask, root) {
164
+ io.output(`${CLI_NAME} init — ${io.cwd} is inside a workspace rooted at ${root}.\n` +
165
+ `A run reads the nearest ${CONFIG_FILE_NAME}, walking UP from the directory it is ` +
166
+ `run in. A config written here is found from here and below; a run from ${root} ` +
167
+ `would not find it. One at the workspace root is found from every package in it.\n` +
168
+ ` 1. ${root} (the workspace root)\n` +
169
+ ` 2. ${io.cwd} (here — this package only)\n`);
170
+ for (;;) {
171
+ const answer = await ask(`where should ${CONFIG_FILE_NAME} go? (1/2) [1]> `);
172
+ if (answer === 'back') {
173
+ io.output(`This is the first question — there is nothing before it.\n`);
174
+ continue;
175
+ }
176
+ const pick = answer === '' ? '1' : answer;
177
+ if (pick === '1')
178
+ return root;
179
+ if (pick === '2')
180
+ return io.cwd;
181
+ io.output(`1 for the workspace root, 2 for here.\n`);
182
+ }
183
+ }
184
+ /**
185
+ * The nearest **ancestor** of `cwd` that declares a workspace, or `undefined`.
186
+ *
187
+ * Ancestors only: a `cwd` that is itself the workspace root has nothing to choose
188
+ * between, so it is asked nothing. Two markers, because those are the two the
189
+ * ecosystem writes — pnpm's `pnpm-workspace.yaml`, and the `workspaces` field npm,
190
+ * yarn and bun read out of `package.json`. Detection never reads a lockfile and never
191
+ * shells out; a `package.json` it cannot parse claims nothing, so it is not a root.
192
+ */
193
+ export function findWorkspaceRoot(cwd) {
194
+ let dir = resolve(cwd);
195
+ for (;;) {
196
+ const parent = dirname(dir);
197
+ if (parent === dir)
198
+ return undefined;
199
+ dir = parent;
200
+ if (declaresWorkspace(dir))
201
+ return dir;
202
+ }
203
+ }
204
+ function declaresWorkspace(dir) {
205
+ if (existsSync(join(dir, 'pnpm-workspace.yaml')))
206
+ return true;
207
+ const manifest = join(dir, 'package.json');
208
+ if (!existsSync(manifest))
209
+ return false;
210
+ let workspaces;
211
+ try {
212
+ ({ workspaces } = JSON.parse(readFileSync(manifest, 'utf8')));
213
+ }
214
+ catch {
215
+ return false; // a package.json smelt cannot read is not a claim about anything
216
+ }
217
+ return Array.isArray(workspaces) || (typeof workspaces === 'object' && workspaces !== null);
218
+ }
108
219
  async function editRun(io, ask, configPath, config) {
109
220
  const dir = dirname(configPath);
110
221
  const choices = {
111
222
  budgetBytes: config.defaultBudgetBytes,
112
223
  store: config.store ?? { kind: 'memory' },
113
- strategy: config.strategy ?? 'lexical',
224
+ strategy: config.strategy ?? DEFAULT_STRATEGY,
114
225
  measureStub: false,
115
226
  rerankStub: false,
116
227
  hooks: config.hooks,
@@ -202,23 +313,37 @@ async function stepStore(io, ask, choices) {
202
313
  io.output(`1 for memory, 2 for directory, or back.\n`);
203
314
  }
204
315
  }
316
+ /**
317
+ * One sentence per strategy, for the wizard's menu — `Record<Strategy, string>`, so a
318
+ * strategy added to the `PLANNERS` registry without a line here is a compile error
319
+ * rather than an option the wizard silently never offers. The menu itself, its
320
+ * numbering and the re-prompt are all rendered from {@link STRATEGIES}, which is why
321
+ * the third choice cost one entry in this table.
322
+ */
323
+ const STRATEGY_BLURB = {
324
+ lexical: 'line windows around your focus terms; works on any text',
325
+ structural: `parses ${String(STRUCTURAL_LANGUAGES.length)} languages with bundled grammars ` +
326
+ `(${STRUCTURAL_LANGUAGES.join(', ')}) and collapses siblings by name; refuses ` +
327
+ `other languages rather than approximating`,
328
+ auto: 'structural for those languages and lexical for everything else; the result ' +
329
+ 'names whichever one actually ran',
330
+ };
205
331
  async function stepStrategy(io, ask, choices) {
332
+ const picks = STRATEGIES.map((_, index) => String(index + 1));
206
333
  io.output(`\nDefault planner strategy — used when a run omits --strategy:\n` +
207
- ` 1. lexical line windows around your focus terms; works on any text\n` +
208
- ` 2. structural — parses ${String(STRUCTURAL_LANGUAGES.length)} languages with ` +
209
- `bundled grammars (${STRUCTURAL_LANGUAGES.join(', ')}) and ` +
210
- `collapses siblings by name; refuses other languages rather than approximating\n`);
334
+ STRATEGIES.map((name, index) => ` ${picks[index]}. ${name.padEnd(12)}${STRATEGY_BLURB[name]}\n`).join(''));
211
335
  for (;;) {
212
- const current = choices.strategy === 'lexical' ? '1' : '2';
213
- const answer = await ask(`strategy (1/2) [${current}] (or back)> `);
336
+ const current = picks[STRATEGIES.indexOf(choices.strategy)];
337
+ const answer = await ask(`strategy (${picks.join('/')}) [${current}] (or back)> `);
214
338
  if (answer === 'back')
215
339
  return 'back';
216
340
  const pick = answer === '' ? current : answer;
217
- if (pick === '1' || pick === '2') {
218
- choices.strategy = pick === '1' ? 'lexical' : 'structural';
341
+ const index = picks.indexOf(pick);
342
+ if (index >= 0) {
343
+ choices.strategy = STRATEGIES[index];
219
344
  return 'ok';
220
345
  }
221
- io.output(`1 for lexical, 2 for structural, or back.\n`);
346
+ io.output(`${STRATEGIES.map((name, i) => `${picks[i]} for ${name}`).join(', ')}, or back.\n`);
222
347
  }
223
348
  }
224
349
  async function stepMeasure(io, ask, choices, dir) {
@@ -327,23 +452,27 @@ function plannedWrites(choices, dir) {
327
452
  const unchanged = exists && readFileSync(path, 'utf8') === content;
328
453
  return { name, path, content, exists, unchanged };
329
454
  };
330
- const writes = [plan(CONFIG_FILE_NAME, renderConfig(choices))];
455
+ const writes = [plan(CONFIG_FILE_NAME, renderConfig(chosenConfig(choices)))];
331
456
  if (choices.measureStub)
332
457
  writes.push(plan(MEASURE_STUB_FILE, measureStubSource()));
333
458
  if (choices.rerankStub)
334
459
  writes.push(plan(RERANK_STUB_FILE, rerankStubSource()));
335
460
  return writes;
336
461
  }
337
- /** The config file, serialized with a stable key order so re-runs diff cleanly. */
338
- export function renderConfig(choices) {
339
- const config = {
462
+ /**
463
+ * The config the wizard's choices mean — the wizard's *policy*, handed to the one
464
+ * writer in `config.ts`. `strategy` and `store` are always written: the wizard asked
465
+ * about both, and a chosen value left out of the file would be a setting the user
466
+ * watched themselves pick and never got.
467
+ */
468
+ function chosenConfig(choices) {
469
+ return {
340
470
  smeltConfig: CONFIG_VERSION,
341
471
  ...(choices.budgetBytes === undefined ? {} : { defaultBudgetBytes: choices.budgetBytes }),
342
472
  strategy: choices.strategy,
343
473
  store: choices.store,
344
474
  ...(choices.hooks === undefined ? {} : { hooks: choices.hooks }),
345
475
  };
346
- return `${JSON.stringify(config, null, 2)}\n`;
347
476
  }
348
477
  // ---------------------------------------------------------------------------
349
478
  // The generated stubs. String literals on purpose: smelt's own import graph must not
@@ -1 +1 @@
1
- {"version":3,"file":"init.js","sourceRoot":"","sources":["../../src/cli/init.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"init.js","sourceRoot":"","sources":["../../src/cli/init.ts"],"names":[],"mappings":"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","sourcesContent":["import { existsSync, readFileSync, writeFileSync } from 'node:fs';\nimport { dirname, join, resolve } from 'node:path';\n\nimport { CliUsageError } from '../errors.ts';\nimport { DEFAULT_STRATEGY, STRATEGIES } from '../plan/planners.ts';\nimport type { Strategy } from '../plan/planners.ts';\nimport { STRUCTURAL_LANGUAGES } from '../plan/structural.ts';\n\nimport { answerReader, CLI_NAME } from './shell.ts';\nimport type { AnswerStream } from './shell.ts';\nimport {\n CONFIG_FILE_NAME,\n CONFIG_VERSION,\n findConfigFile,\n parseConfig,\n renderConfig,\n} from './config.ts';\nimport type { SmeltConfig, SmeltConfigHooks, SmeltConfigStore } from './config.ts';\n\n/**\n * `smelt init` — the setup wizard.\n *\n * The same testability pattern as `run.ts`: the wizard is a pure function over an\n * input/output pair, so every flow — fresh run, back-navigation, re-run editing,\n * declined overwrites — runs in-process in tests, and `bin.ts` wires the real stdio.\n *\n * Three rules shape everything here:\n *\n * 1. **Nothing is written until the final confirm**, which lists exactly what will be\n * written or changed. A wizard that writes as it goes cannot be backed out of.\n * 2. **An existing file is never overwritten without an explicit per-file yes.** Not\n * a global \"overwrite all\", not a default — one question per existing file, and\n * anything but a literal `yes` skips it. Guarded by\n * `test/guards/init-wizard.test.ts`, with a mutation proving the guard goes red.\n * 3. **Every step accepts `back`.** A wizard you cannot reverse inside is a form. That\n * includes the directory question a fresh run asks inside a workspace: `back` from\n * the first step returns to it, keeping the answers given since.\n * 4. **Everything lands in one named directory.** A fresh run inside a workspace asks\n * which end of config discovery to write to (see `chooseDirectory`) and an edit run\n * writes beside the config it found; either way the directory is printed in the\n * \"About to write\" listing before the confirm, and nothing is ever written outside\n * it. A wizard that writes where the user cannot see is a wizard writing somewhere\n * they did not agree to.\n *\n * Law 4 note: the wizard's copy states what each choice *does*, never what it saves —\n * no percentages, no rates, no numbers smelt has not measured.\n */\n\n/** The generated measure-hook stub's file name. */\nexport const MEASURE_STUB_FILE = 'smelt.measure.ts';\n\n/** The generated reranker stub's file name. */\nexport const RERANK_STUB_FILE = 'smelt.rerank.ts';\n\n/** Where the wizard's bytes come from and go. Injected so `runInit` is testable in-process. */\nexport interface InitIo {\n /**\n * Interactive input — the real stdin in `bin.ts`, a scripted stream in tests.\n * Structural on purpose; see {@link AnswerStream}.\n */\n readonly input: AnswerStream;\n readonly output: (text: string) => void;\n /**\n * Where config discovery starts, and where a fresh run's files land — unless `cwd`\n * is inside a workspace and the user picks its root instead (`chooseDirectory`). An\n * edit run writes next to the discovered config, which may be an ancestor of `cwd`.\n * In every flow the \"About to write\" listing names the directory before anything is\n * written, and nothing is written outside it.\n */\n readonly cwd: string;\n}\n\n/** Everything the wizard decides. Pure data until the final confirm writes it. */\ninterface WizardChoices {\n budgetBytes: number | undefined;\n store: SmeltConfigStore;\n strategy: Strategy;\n /** Generate {@link MEASURE_STUB_FILE}? Never deletes an existing one. */\n measureStub: boolean;\n /** Generate {@link RERANK_STUB_FILE}? Never deletes an existing one. */\n rerankStub: boolean;\n /**\n * An existing config's `hooks` block, carried through verbatim. This wizard never\n * edits it — `smelt hooks install` owns those choices — but a re-run that silently\n * dropped it would be an edit the user never made.\n */\n hooks: SmeltConfigHooks | undefined;\n}\n\ntype StepOutcome = 'ok' | 'back';\n\ninterface PlannedWrite {\n readonly name: string;\n readonly path: string;\n readonly content: string;\n readonly exists: boolean;\n /** The file already holds exactly these bytes — nothing to write. */\n readonly unchanged: boolean;\n}\n\n/**\n * The wizard, start to finish. Returns an exit code (0 in every completed flow,\n * including \"declined to write anything\").\n *\n * @throws {CliUsageError} on a malformed existing config, or when input ends before\n * the wizard finishes — both are usage-shaped, and nothing further is written.\n */\nexport async function runInit(io: InitIo): Promise<number> {\n // `answerReader` — not `Readable.from` + readline — because the wizard must *let go*\n // of stdin when it is done. See the note on `answerReader` for the hang that shape\n // caused: files written, `Done.` printed, and the process never exiting.\n const lines = answerReader(io.input);\n const ask = async (prompt: string): Promise<string> => {\n io.output(prompt);\n const next = await lines.next();\n if (next === undefined) {\n throw new CliUsageError(\n `${CLI_NAME} init: input ended before the wizard finished. ` +\n `Files already confirmed and written stay; nothing further was written.`,\n );\n }\n return next.trim();\n };\n\n try {\n const existing = loadExisting(io.cwd);\n return existing === undefined\n ? await freshRun(io, ask)\n : await editRun(io, ask, existing.path, existing.config);\n } finally {\n await lines.release();\n }\n}\n\nfunction loadExisting(cwd: string): { path: string; config: SmeltConfig } | undefined {\n const path = findConfigFile(cwd);\n if (path === undefined) return undefined;\n // Malformed is a loud usage error, not a silent fresh start: overwriting a config\n // the user wrote, because it had a typo, would be the wizard deciding for them.\n return { path, config: parseConfig(readFileSync(path, 'utf8'), path) };\n}\n\n// ---------------------------------------------------------------------------\n// The two flows\n// ---------------------------------------------------------------------------\n\ntype Asker = (prompt: string) => Promise<string>;\n\ninterface Step {\n readonly id: 'budget' | 'store' | 'strategy' | 'measure' | 'rerank';\n run(io: InitIo, ask: Asker, choices: WizardChoices, dir: string): Promise<StepOutcome>;\n}\n\nconst STEPS: readonly Step[] = [\n { id: 'budget', run: stepBudget },\n { id: 'store', run: stepStore },\n { id: 'strategy', run: stepStrategy },\n { id: 'measure', run: stepMeasure },\n { id: 'rerank', run: stepRerank },\n];\n\nasync function freshRun(io: InitIo, ask: Asker): Promise<number> {\n const choices: WizardChoices = {\n budgetBytes: undefined,\n store: { kind: 'memory' },\n strategy: DEFAULT_STRATEGY,\n measureStub: false,\n rerankStub: false,\n hooks: undefined,\n };\n\n // Outside a workspace there is no directory question, so the first step really is the\n // first thing asked. Inside one there is, and `back` from the first step returns to it\n // — with every answer so far carried along, because reversing is not restarting.\n const root = findWorkspaceRoot(io.cwd);\n for (;;) {\n const dir = root === undefined ? io.cwd : await chooseDirectory(io, ask, root);\n io.output(\n `${CLI_NAME} init — sets up ${CONFIG_FILE_NAME} in ${dir}.\\n` +\n `A run reads the nearest ${CONFIG_FILE_NAME}, walking UP from the directory it ` +\n `is run in, so this one is found from ${dir} and everything below it.\\n` +\n `Answer \\`back\\` at any step to return to the previous one. ` +\n `Nothing is written until you confirm at the end.\\n\\n`,\n );\n if ((await runSteps(io, ask, choices, dir, root !== undefined)) === 'done') return 0;\n }\n}\n\n/**\n * The step loop for one chosen directory: every step, then the confirm, with `back`\n * reversing all the way through both. Returns `'directory'` when `back` walks off the\n * front and there is a directory question to walk back into — `freshRun` re-asks it and\n * calls this again with the same {@link WizardChoices}.\n */\nasync function runSteps(\n io: InitIo,\n ask: Asker,\n choices: WizardChoices,\n dir: string,\n canReopenDirectory: boolean,\n): Promise<'done' | 'directory'> {\n let index = 0;\n for (;;) {\n while (index < STEPS.length) {\n const outcome = await STEPS[index]!.run(io, ask, choices, dir);\n if (outcome !== 'back') {\n index += 1;\n } else if (index > 0) {\n index -= 1;\n } else if (canReopenDirectory) {\n return 'directory';\n } else {\n io.output(`This is the first step — there is nothing before it.\\n`);\n }\n }\n const verdict = await confirmAndWrite(io, ask, choices, dir);\n if (verdict !== 'back') return 'done';\n index = STEPS.length - 1;\n }\n}\n\n/**\n * Which directory this fresh run writes into — and the wizard's answer to the\n * monorepo trap.\n *\n * `smelt init` in `packages/web` used to write a config in `packages/web`, silently,\n * while discovery walks **up**: every run from the repo root then found no config and\n * used none, and the user had watched themselves set a budget. So when the working\n * directory sits inside a workspace (`pnpm-workspace.yaml`, or a `package.json` with a\n * `workspaces` field, in any ancestor), the wizard states the discovery rule and asks\n * which end of it to write to, defaulting to the root that covers the whole tree.\n *\n * The answer becomes the directory every later step, the \"About to write\" listing and\n * every `writeFileSync` uses — so the wizard still writes only inside the one directory\n * the user was shown and confirmed, here as much as anywhere else. Outside a workspace\n * there is nothing to choose and nothing is asked; the discovery rule is stated either\n * way, because \"where will runs look for this?\" is not a question a user should have to\n * infer from a path.\n *\n * Rule 3 holds here too: this is genuinely the first question, so `back` at it has\n * nowhere to go — but `back` from the first *step* comes back to it (see `freshRun`),\n * carrying the answers already given. The most consequential question in the wizard is\n * not the one you cannot reverse into.\n */\nasync function chooseDirectory(io: InitIo, ask: Asker, root: string): Promise<string> {\n io.output(\n `${CLI_NAME} init — ${io.cwd} is inside a workspace rooted at ${root}.\\n` +\n `A run reads the nearest ${CONFIG_FILE_NAME}, walking UP from the directory it is ` +\n `run in. A config written here is found from here and below; a run from ${root} ` +\n `would not find it. One at the workspace root is found from every package in it.\\n` +\n ` 1. ${root} (the workspace root)\\n` +\n ` 2. ${io.cwd} (here — this package only)\\n`,\n );\n for (;;) {\n const answer = await ask(`where should ${CONFIG_FILE_NAME} go? (1/2) [1]> `);\n if (answer === 'back') {\n io.output(`This is the first question — there is nothing before it.\\n`);\n continue;\n }\n const pick = answer === '' ? '1' : answer;\n if (pick === '1') return root;\n if (pick === '2') return io.cwd;\n io.output(`1 for the workspace root, 2 for here.\\n`);\n }\n}\n\n/**\n * The nearest **ancestor** of `cwd` that declares a workspace, or `undefined`.\n *\n * Ancestors only: a `cwd` that is itself the workspace root has nothing to choose\n * between, so it is asked nothing. Two markers, because those are the two the\n * ecosystem writes — pnpm's `pnpm-workspace.yaml`, and the `workspaces` field npm,\n * yarn and bun read out of `package.json`. Detection never reads a lockfile and never\n * shells out; a `package.json` it cannot parse claims nothing, so it is not a root.\n */\nexport function findWorkspaceRoot(cwd: string): string | undefined {\n let dir = resolve(cwd);\n for (;;) {\n const parent = dirname(dir);\n if (parent === dir) return undefined;\n dir = parent;\n if (declaresWorkspace(dir)) return dir;\n }\n}\n\nfunction declaresWorkspace(dir: string): boolean {\n if (existsSync(join(dir, 'pnpm-workspace.yaml'))) return true;\n const manifest = join(dir, 'package.json');\n if (!existsSync(manifest)) return false;\n let workspaces: unknown;\n try {\n ({ workspaces } = JSON.parse(readFileSync(manifest, 'utf8')) as { workspaces?: unknown });\n } catch {\n return false; // a package.json smelt cannot read is not a claim about anything\n }\n return Array.isArray(workspaces) || (typeof workspaces === 'object' && workspaces !== null);\n}\n\nasync function editRun(\n io: InitIo,\n ask: Asker,\n configPath: string,\n config: SmeltConfig,\n): Promise<number> {\n const dir = dirname(configPath);\n const choices: WizardChoices = {\n budgetBytes: config.defaultBudgetBytes,\n store: config.store ?? { kind: 'memory' },\n strategy: config.strategy ?? DEFAULT_STRATEGY,\n measureStub: false,\n rerankStub: false,\n hooks: config.hooks,\n };\n\n io.output(\n `${CLI_NAME} init — ${CONFIG_FILE_NAME} already exists at ${configPath}.\\n` +\n `Change one setting at a time; nothing is written until you confirm.\\n`,\n );\n\n for (;;) {\n io.output(`\\nCurrent values:\\n${summary(choices, dir)}\\n`);\n const answer = await ask(\n `Change which setting? (budget / store / strategy / measure / rerank, ` +\n `\\`done\\` to review and confirm, \\`back\\` to leave without writing)\\n> `,\n );\n if (answer === 'back') {\n io.output(`Left as it was. Nothing has been written.\\n`);\n return 0;\n }\n if (answer === 'done') {\n const verdict = await confirmAndWrite(io, ask, choices, dir);\n if (verdict !== 'back') return 0;\n continue; // back from confirm returns to this menu\n }\n const step = STEPS.find((candidate) => candidate.id === answer);\n if (step === undefined) {\n io.output(`Not a setting: \"${answer}\". One of: budget, store, strategy, measure, rerank.\\n`);\n continue;\n }\n await step.run(io, ask, choices, dir); // its own `back` returns here\n }\n}\n\nfunction summary(choices: WizardChoices, dir: string): string {\n const stubLine = (file: string, generate: boolean): string => {\n if (generate) return `generate ${file}`;\n return existsSync(join(dir, file)) ? `${file} exists (kept as is)` : 'none';\n };\n return [\n ` budget: ${choices.budgetBytes === undefined ? '(not set)' : `${String(choices.budgetBytes)} bytes`}`,\n ` store: ${choices.store.kind === 'memory' ? 'memory' : `directory (${choices.store.path})`}`,\n ` strategy: ${choices.strategy}`,\n ` measure: ${stubLine(MEASURE_STUB_FILE, choices.measureStub)}`,\n ` rerank: ${stubLine(RERANK_STUB_FILE, choices.rerankStub)}`,\n ].join('\\n');\n}\n\n// ---------------------------------------------------------------------------\n// The steps. Each one accepts `back`.\n// ---------------------------------------------------------------------------\n\nasync function stepBudget(io: InitIo, ask: Asker, choices: WizardChoices): Promise<StepOutcome> {\n io.output(\n `\\nDefault byte budget — used when a \\`${CLI_NAME}\\` run omits --budget.\\n` +\n `Budgets are UTF-8 bytes, permanently; an explicit --budget always wins.\\n` +\n `There is no suggested number: the right budget depends on your traffic, and ` +\n `smelt does not invent numbers it has not measured.\\n`,\n );\n for (;;) {\n const current = choices.budgetBytes === undefined ? '' : ` [${String(choices.budgetBytes)}]`;\n const answer = await ask(`budget in bytes${current} (or back)> `);\n if (answer === 'back') return 'back';\n if (answer === '' && choices.budgetBytes !== undefined) return 'ok';\n if (/^\\d+$/.test(answer) && Number(answer) > 0) {\n choices.budgetBytes = Number(answer);\n return 'ok';\n }\n io.output(`A whole number of bytes greater than zero, e.g. 4000.\\n`);\n }\n}\n\nasync function stepStore(io: InitIo, ask: Asker, choices: WizardChoices): Promise<StepOutcome> {\n io.output(\n `\\nWhere elided bytes live. Every elision is reversible only while a store holds ` +\n `its bytes (Law 3):\\n` +\n ` 1. memory — per-process; retrievals do not survive the process\\n` +\n ` 2. directory — persistent, content-addressed, on disk; retrieval counters ` +\n `survive restarts\\n`,\n );\n for (;;) {\n const current = choices.store.kind === 'memory' ? '1' : '2';\n const answer = await ask(`store (1/2) [${current}] (or back)> `);\n if (answer === 'back') return 'back';\n const pick = answer === '' ? current : answer;\n if (pick === '1') {\n choices.store = { kind: 'memory' };\n return 'ok';\n }\n if (pick === '2') {\n const previous = choices.store.kind === 'directory' ? choices.store.path : '.smelt/store';\n const path = await ask(`store directory, relative to ${CONFIG_FILE_NAME} [${previous}]> `);\n if (path === 'back') continue; // back to the store choice, not out of the step\n choices.store = { kind: 'directory', path: path === '' ? previous : path };\n return 'ok';\n }\n io.output(`1 for memory, 2 for directory, or back.\\n`);\n }\n}\n\n/**\n * One sentence per strategy, for the wizard's menu — `Record<Strategy, string>`, so a\n * strategy added to the `PLANNERS` registry without a line here is a compile error\n * rather than an option the wizard silently never offers. The menu itself, its\n * numbering and the re-prompt are all rendered from {@link STRATEGIES}, which is why\n * the third choice cost one entry in this table.\n */\nconst STRATEGY_BLURB: Readonly<Record<Strategy, string>> = {\n lexical: 'line windows around your focus terms; works on any text',\n structural:\n `parses ${String(STRUCTURAL_LANGUAGES.length)} languages with bundled grammars ` +\n `(${STRUCTURAL_LANGUAGES.join(', ')}) and collapses siblings by name; refuses ` +\n `other languages rather than approximating`,\n auto:\n 'structural for those languages and lexical for everything else; the result ' +\n 'names whichever one actually ran',\n};\n\nasync function stepStrategy(io: InitIo, ask: Asker, choices: WizardChoices): Promise<StepOutcome> {\n const picks = STRATEGIES.map((_, index) => String(index + 1));\n io.output(\n `\\nDefault planner strategy — used when a run omits --strategy:\\n` +\n STRATEGIES.map(\n (name, index) => ` ${picks[index]!}. ${name.padEnd(12)}— ${STRATEGY_BLURB[name]}\\n`,\n ).join(''),\n );\n for (;;) {\n const current = picks[STRATEGIES.indexOf(choices.strategy)]!;\n const answer = await ask(`strategy (${picks.join('/')}) [${current}] (or back)> `);\n if (answer === 'back') return 'back';\n const pick = answer === '' ? current : answer;\n const index = picks.indexOf(pick);\n if (index >= 0) {\n choices.strategy = STRATEGIES[index]!;\n return 'ok';\n }\n io.output(`${STRATEGIES.map((name, i) => `${picks[i]!} for ${name}`).join(', ')}, or back.\\n`);\n }\n}\n\nasync function stepMeasure(\n io: InitIo,\n ask: Asker,\n choices: WizardChoices,\n dir: string,\n): Promise<StepOutcome> {\n const exists = existsSync(join(dir, MEASURE_STUB_FILE));\n io.output(\n `\\nMeasure hook — your own counter (a tokenizer, usually), so results carry a ` +\n `second, labelled number next to the byte counts. smelt ships none: a token ` +\n `count without its tokenizer named is not a measurement.\\n` +\n ` 1. none\\n` +\n ` 2. generate ${MEASURE_STUB_FILE}, a typed stub you fill in\\n` +\n (exists ? `(${MEASURE_STUB_FILE} already exists; it is never deleted from here.)\\n` : ``),\n );\n for (;;) {\n const answer = await ask(`measure (1/2) [${choices.measureStub ? '2' : '1'}] (or back)> `);\n if (answer === 'back') return 'back';\n const pick = answer === '' ? (choices.measureStub ? '2' : '1') : answer;\n if (pick === '1' || pick === '2') {\n choices.measureStub = pick === '2';\n return 'ok';\n }\n io.output(`1 for none, 2 to generate the stub, or back.\\n`);\n }\n}\n\nasync function stepRerank(\n io: InitIo,\n ask: Asker,\n choices: WizardChoices,\n dir: string,\n): Promise<StepOutcome> {\n const exists = existsSync(join(dir, RERANK_STUB_FILE));\n io.output(\n `\\nReranker — a RerankStage of your own. smelt never bundles one and never will: ` +\n `an outbound call must live in your code, under your key, visible in your own ` +\n `review (Law 1).\\n` +\n ` 1. none\\n` +\n ` 2. generate ${RERANK_STUB_FILE}, a typed stub with the HTTP call sketched as a TODO\\n` +\n (exists ? `(${RERANK_STUB_FILE} already exists; it is never deleted from here.)\\n` : ``),\n );\n for (;;) {\n const answer = await ask(`rerank (1/2) [${choices.rerankStub ? '2' : '1'}] (or back)> `);\n if (answer === 'back') return 'back';\n const pick = answer === '' ? (choices.rerankStub ? '2' : '1') : answer;\n if (pick === '1' || pick === '2') {\n choices.rerankStub = pick === '2';\n return 'ok';\n }\n io.output(`1 for none, 2 to generate the stub, or back.\\n`);\n }\n}\n\n// ---------------------------------------------------------------------------\n// The confirm step: the only place anything is written\n// ---------------------------------------------------------------------------\n\nconst writeLabel = (write: PlannedWrite): string => {\n if (write.unchanged) return 'unchanged — nothing to write';\n return write.exists ? 'exists — will ask before overwriting' : 'new';\n};\n\nasync function confirmAndWrite(\n io: InitIo,\n ask: Asker,\n choices: WizardChoices,\n dir: string,\n): Promise<'done' | 'back'> {\n if (choices.budgetBytes === undefined) {\n // Unreachable in the fresh flow (the budget step requires a number) but reachable\n // from an edit of a config that never had one — `defaultBudgetBytes` is optional,\n // so such a config parses fine. The wizard still insists: a confirm without a\n // budget would write a file this wizard just called incomplete. `back` here is a\n // real `back` — it returns to the caller, never falls forward into the confirm.\n io.output(`No budget is set yet — set one before confirming.\\n`);\n if ((await stepBudget(io, ask, choices)) === 'back') return 'back';\n }\n\n const writes = plannedWrites(choices, dir);\n io.output(\n `\\nAbout to write, into ${dir}:\\n` +\n writes.map((write) => ` ${write.name.padEnd(20)} (${writeLabel(write)})\\n`).join('') +\n `Nothing has been written yet.\\n`,\n );\n\n for (;;) {\n const answer = await ask(`confirm (yes / no / back)> `);\n if (answer === 'back') return 'back';\n if (answer === 'no') {\n io.output(`Nothing was written.\\n`);\n return 'done';\n }\n if (answer === 'yes') break;\n io.output(`yes to write, no to leave everything untouched, back to change a setting.\\n`);\n }\n\n for (const write of writes) {\n if (write.unchanged) {\n io.output(` ${write.name} — unchanged, not rewritten\\n`);\n continue;\n }\n if (write.exists) {\n // The per-file consent rule: one explicit question per existing file, and only\n // a literal `yes` overwrites. This is the line the mutation\n // `init-overwrite-without-consent` breaks to prove the guard can go red.\n const answer = await ask(` ${write.name} exists — overwrite it? (yes/no)> `);\n if (answer !== 'yes') {\n io.output(` skipped ${write.name} — the existing file was not touched\\n`);\n continue;\n }\n }\n writeFileSync(write.path, write.content);\n io.output(` wrote ${write.name}\\n`);\n }\n io.output(`Done.\\n`);\n io.output(\n `Also: \\`${CLI_NAME} hooks install\\` wires the smelt guard into agent-harness ` +\n `hooks (Claude Code, Codex, and more) — it detects installed harnesses and asks ` +\n `before writing anything.\\n`,\n );\n return 'done';\n}\n\nfunction plannedWrites(choices: WizardChoices, dir: string): readonly PlannedWrite[] {\n const plan = (name: string, content: string): PlannedWrite => {\n const path = join(dir, name);\n const exists = existsSync(path);\n const unchanged = exists && readFileSync(path, 'utf8') === content;\n return { name, path, content, exists, unchanged };\n };\n const writes = [plan(CONFIG_FILE_NAME, renderConfig(chosenConfig(choices)))];\n if (choices.measureStub) writes.push(plan(MEASURE_STUB_FILE, measureStubSource()));\n if (choices.rerankStub) writes.push(plan(RERANK_STUB_FILE, rerankStubSource()));\n return writes;\n}\n\n/**\n * The config the wizard's choices mean — the wizard's *policy*, handed to the one\n * writer in `config.ts`. `strategy` and `store` are always written: the wizard asked\n * about both, and a chosen value left out of the file would be a setting the user\n * watched themselves pick and never got.\n */\nfunction chosenConfig(choices: {\n readonly budgetBytes: number | undefined;\n readonly store: SmeltConfigStore;\n readonly strategy: Strategy;\n /** Carried through from an existing config; this wizard never edits it. */\n readonly hooks?: SmeltConfigHooks | undefined;\n}): SmeltConfig {\n return {\n smeltConfig: CONFIG_VERSION,\n ...(choices.budgetBytes === undefined ? {} : { defaultBudgetBytes: choices.budgetBytes }),\n strategy: choices.strategy,\n store: choices.store,\n ...(choices.hooks === undefined ? {} : { hooks: choices.hooks }),\n };\n}\n\n// ---------------------------------------------------------------------------\n// The generated stubs. String literals on purpose: smelt's own import graph must not\n// gain an HTTP client, and the zero-network guard's string-stripper ignores string\n// bodies — the sketched fetch below lives in the CONSUMER'S file, never in smelt's.\n//\n// The comment token between `from` and the package name in each stub's import line is\n// deliberate: the guard's import scanner reads raw source, so spelling that import\n// plainly inside this template would register as an edge in smelt's own graph — which\n// it is not. The comment keeps the generated file valid TypeScript while keeping this\n// data out of the guard's walk.\n// ---------------------------------------------------------------------------\n\n/** The `smelt.measure.ts` the wizard writes. Exported so tests can compile it. */\nexport function measureStubSource(): string {\n return `/**\n * Measure hook — generated by \\`smelt init\\`.\n *\n * smelt's budgets are UTF-8 bytes, permanently; this hook adds a second, labelled\n * number to every result in YOUR unit, counted by YOUR tokenizer. Both \\`id\\` and\n * \\`unit\\` are required: a count without the counter named is not a measurement.\n *\n * Wire it in, in your own code:\n *\n * const smelter = createSmelter({ defaultBudgetBytes: 8_000, measure });\n *\n * with createSmelter imported from your @smeltjs/core install and measure from here.\n */\nimport type { Measure } from /* your install */ '@smeltjs/core';\n\nexport const measure: Measure = {\n // TODO: name the counter that produces these numbers, e.g. 'tiktoken/o200k_base'.\n id: 'TODO/your-tokenizer',\n unit: 'tokens',\n count(text: string): number {\n // TODO: replace with your real tokenizer. It must be local and synchronous —\n // a count() that calls an API would make your process call an API on every smelt.\n // e.g. return encode(text).length;\n throw new Error(\n 'smelt.measure.ts: count() is not implemented yet — ' +\n 'fill it in with your tokenizer (length of input: ' + String(text.length) + ')',\n );\n },\n};\n`;\n}\n\n/** The `smelt.rerank.ts` the wizard writes. Exported so tests can compile it. */\nexport function rerankStubSource(): string {\n return `/**\n * Reranker stub — generated by \\`smelt init\\`.\n *\n * smelt itself makes zero network calls and never bundles a reranker (Law 1): the\n * moment one ships as a default, every consumer's source code leaves the machine and\n * they find out from a changelog, or never. So the outbound call lives HERE, in your\n * file, reading your env var, visible in your own review.\n *\n * Wire it into your own pipeline; smelt never calls this for you.\n */\nimport type { RerankCandidate, RerankedCandidate, RerankStage } from /* your install */ '@smeltjs/core';\n\n/** The env var YOUR code reads. Rename it to match your vendor. */\nconst API_KEY_ENV = 'RERANKER_API_KEY';\n\nexport const rerank: RerankStage = {\n id: 'my-reranker/v1',\n async rerank(\n candidates: readonly RerankCandidate[],\n query: string,\n ): Promise<readonly RerankedCandidate[]> {\n const apiKey = process.env[API_KEY_ENV];\n if (apiKey === undefined || apiKey === '') {\n throw new Error(\n 'smelt.rerank.ts: ' + API_KEY_ENV + ' is not set. This stage makes an outbound ' +\n 'HTTP call from YOUR code with YOUR key; without a key it refuses to pretend.',\n );\n }\n\n // TODO: the outbound call. Voyage AI is one example vendor; any reranker with an\n // HTTP API fits this shape:\n //\n // const response = await fetch('https://api.voyageai.com/v1/rerank', {\n // method: 'POST',\n // headers: {\n // 'content-type': 'application/json',\n // authorization: \\`Bearer \\${apiKey}\\`,\n // },\n // body: JSON.stringify({\n // query,\n // documents: candidates.map((candidate) => candidate.text),\n // }),\n // });\n // if (!response.ok) throw new Error('rerank failed: ' + String(response.status));\n // const body = (await response.json()) as {\n // data: { index: number; relevance_score: number }[];\n // };\n // return body.data.map(({ index, relevance_score }) => ({\n // ...candidates[index]!,\n // score: relevance_score,\n // }));\n //\n void candidates;\n void query;\n throw new Error(\n 'smelt.rerank.ts: implement the outbound call sketched above, then delete this throw.',\n );\n },\n};\n`;\n}\n"]}
@@ -1 +1 @@
1
- {"version":3,"file":"report.d.ts","sourceRoot":"","sources":["../../src/cli/report.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,mBAAmB,CAAC;AACjD,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,aAAa,CAAC;AAI/C,MAAM,WAAW,WAAW;IAC1B,QAAQ,CAAC,MAAM,EAAE,WAAW,CAAC;IAC7B,oEAAoE;IACpE,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;IACxB,iFAAiF;IACjF,QAAQ,CAAC,WAAW,EAAE,MAAM,CAAC;IAC7B,mFAAmF;IACnF,QAAQ,CAAC,SAAS,EAAE,MAAM,CAAC;CAC5B;AAKD;;;;;;;;GAQG;AACH,wBAAgB,YAAY,CAAC,EAAE,MAAM,EAAE,MAAM,EAAE,WAAW,EAAE,SAAS,EAAE,EAAE,WAAW,GAAG,MAAM,CAsE5F;AAED,yCAAyC;AACzC,MAAM,WAAW,cAAc;IAC7B,QAAQ,CAAC,GAAG,EAAE,OAAO,CAAC;IACtB,6EAA6E;IAC7E,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;IACxB;;;;OAIG;IACH,QAAQ,CAAC,YAAY,EAAE,MAAM,GAAG,QAAQ,CAAC;CAC1C;AAED;;;;;;;;GAQG;AACH,wBAAgB,eAAe,CAAC,EAAE,GAAG,EAAE,MAAM,EAAE,YAAY,EAAE,EAAE,cAAc,GAAG,MAAM,CA+BrF"}
1
+ {"version":3,"file":"report.d.ts","sourceRoot":"","sources":["../../src/cli/report.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,mBAAmB,CAAC;AACjD,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,aAAa,CAAC;AAI/C,MAAM,WAAW,WAAW;IAC1B,QAAQ,CAAC,MAAM,EAAE,WAAW,CAAC;IAC7B,oEAAoE;IACpE,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;IACxB,iFAAiF;IACjF,QAAQ,CAAC,WAAW,EAAE,MAAM,CAAC;IAC7B,mFAAmF;IACnF,QAAQ,CAAC,SAAS,EAAE,MAAM,CAAC;CAC5B;AAKD;;;;;;;;GAQG;AACH,wBAAgB,YAAY,CAAC,EAAE,MAAM,EAAE,MAAM,EAAE,WAAW,EAAE,SAAS,EAAE,EAAE,WAAW,GAAG,MAAM,CAsE5F;AAED,yCAAyC;AACzC,MAAM,WAAW,cAAc;IAC7B,QAAQ,CAAC,GAAG,EAAE,OAAO,CAAC;IACtB,6EAA6E;IAC7E,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;IACxB;;;;OAIG;IACH,QAAQ,CAAC,YAAY,EAAE,MAAM,GAAG,QAAQ,CAAC;CAC1C;AAED;;;;;;;;GAQG;AACH,wBAAgB,eAAe,CAAC,EAAE,GAAG,EAAE,MAAM,EAAE,YAAY,EAAE,EAAE,cAAc,GAAG,MAAM,CA+BrF","sourcesContent":["import type { RepoMap } from '../repomap/map.ts';\nimport type { SmeltResult } from '../types.ts';\n\nimport { CLI_NAME } from './shell.ts';\n\nexport interface ReportInput {\n readonly result: SmeltResult;\n /** What to call the input in the header: a path, or `'<stdin>'`. */\n readonly source: string;\n /** The budget the caller asked for, so the report can say when it was missed. */\n readonly budgetBytes: number;\n /** The exact text that was smelted. Used only to count lines inside each range. */\n readonly inputText: string;\n}\n\n/** Longest explanation printed in full before it gets an ellipsis. */\nconst EXPLANATION_WIDTH = 46;\n\n/**\n * The report, for stderr.\n *\n * Every total here is read straight off the {@link SmeltResult} — `inputBytes`,\n * `outputBytes`, `elisions.length`. The CLI keeps no counters of its own, because two\n * pieces of code counting the same bytes is how a report ends up disagreeing with the\n * library it is reporting on, and the report is the thing a human believes.\n * `test/cli.test.ts` asserts the printed numbers equal the result's fields.\n */\nexport function formatReport({ result, source, budgetBytes, inputText }: ReportInput): string {\n const lines: string[] = [];\n\n lines.push([CLI_NAME, source, result.language, result.planner].join(' '));\n lines.push(\n `in ${group(result.inputBytes)} B → out ${group(result.outputBytes)} B ` +\n `(${delta(result.inputBytes, result.outputBytes)}, ${count(result.elisions.length, 'elision')})`,\n );\n\n if (result.measured !== undefined) {\n const { input, output, unit, measure } = result.measured;\n lines.push(`in ${group(input)} → out ${group(output)} ${unit} (${measure})`);\n }\n\n if (result.outputBytes > budgetBytes) {\n lines.push('');\n lines.push(\n `OVER BUDGET ${group(result.outputBytes)} B against a ${group(budgetBytes)} B budget ` +\n `— over by ${group(result.outputBytes - budgetBytes)} B.`,\n );\n lines.push(' The plan is reported as it came back. smelt did not cut the regions');\n lines.push(' you asked to keep in order to make a number look right.');\n }\n\n if (result.elisions.length === 0) {\n lines.push('');\n lines.push(' nothing elided — the input already fits, or every run was too small to');\n lines.push(' be worth a marker (a marker that costs more than the lines it replaces');\n lines.push(' makes the output bigger).');\n return `${lines.join('\\n')}\\n`;\n }\n\n const rows = result.elisions.map((elision) => ({\n rule: elision.reason.rule,\n lines: String(lineSpan(inputText, elision.range.start, elision.range.end)),\n bytes: group(elision.bytes),\n hash: elision.hash,\n explanation: clip(elision.reason.explanation, EXPLANATION_WIDTH),\n }));\n\n const ruleWidth = width(\n 'rule',\n rows.map((row) => row.rule),\n );\n const linesWidth = width(\n 'lines',\n rows.map((row) => row.lines),\n );\n const bytesWidth = width(\n 'bytes',\n rows.map((row) => row.bytes),\n );\n const hashWidth = width(\n 'hash',\n rows.map((row) => row.hash),\n );\n\n lines.push('');\n lines.push(\n ` ${'rule'.padEnd(ruleWidth)} ${'lines'.padStart(linesWidth)} ` +\n `${'bytes'.padStart(bytesWidth)} ${'hash'.padEnd(hashWidth)} explanation`,\n );\n for (const row of rows) {\n lines.push(\n ` ${row.rule.padEnd(ruleWidth)} ${row.lines.padStart(linesWidth)} ` +\n `${row.bytes.padStart(bytesWidth)} ${row.hash.padEnd(hashWidth)} ${row.explanation}`,\n );\n }\n\n return `${lines.join('\\n')}\\n`;\n}\n\n/** What `smelt map` prints to stderr. */\nexport interface MapReportInput {\n readonly map: RepoMap;\n /** The directory named on the command line, exactly as the user wrote it. */\n readonly source: string;\n /**\n * Where the budget came from — the `ResolvedMapRun.budgetSource` receipt, printed\n * beside the budget so a surprising number can be traced to the flag or the config\n * file that set it without re-deriving the precedence by hand.\n */\n readonly budgetSource: 'flag' | 'config';\n}\n\n/**\n * The map report, for stderr — same law as {@link formatReport}: every number is\n * read straight off the {@link RepoMap} the library returned. In particular the\n * \"bytes used\" figure is `map.outputBytes`, which the library measured off the\n * rendered text — the CLI counts nothing itself, because a report that keeps its\n * own tally is a report that can disagree with the map it describes.\n * `test/guards/repo-map.test.ts` asserts the printed figure equals the actual byte\n * length of what landed on stdout, and a mutation proves the assertion can go red.\n */\nexport function formatMapReport({ map, source, budgetSource }: MapReportInput): string {\n const lines: string[] = [];\n\n lines.push([`${CLI_NAME} map`, source, map.id].join(' '));\n lines.push(\n `files scanned ${group(map.filesScanned)}` +\n (map.binarySkipped === 0 ? '' : ` (${count(map.binarySkipped, 'binary file')} skipped)`) +\n ` symbols ranked ${group(map.definitionsTotal)}`,\n );\n lines.push(\n `included ${group(map.entries.length)} of ${group(map.definitionsTotal)} symbols` +\n (map.pathOnlyTotal === 0\n ? ''\n : ` + ${group(map.pathOnly.length)} of ${group(map.pathOnlyTotal)} path-only files`),\n );\n lines.push(\n `bytes used ${group(map.outputBytes)} of ${group(map.budgetBytes)} budget (${budgetSource}) ` +\n `— the map fits itself to the budget by construction, so there is no over-budget exit`,\n );\n\n if (map.cache !== undefined) {\n lines.push(\n `cache ${count(map.cache.hits, 'hit')}, ${count(map.cache.misses, 'miss', 'es')}, ` +\n `${group(map.cache.discarded)} discarded, ${group(map.cache.pruned)} pruned`,\n );\n }\n for (const warning of map.warnings) {\n lines.push(`warning ${warning.rule}: ${warning.explanation}`);\n }\n\n return `${lines.join('\\n')}\\n`;\n}\n\n/** How many lines a byte range covers in the input. Derived, never tallied separately. */\nfunction lineSpan(text: string, start: number, end: number): number {\n const slice = Buffer.from(text, 'utf8').subarray(start, end).toString('utf8');\n return slice.split('\\n').length;\n}\n\nfunction width(header: string, values: readonly string[]): number {\n return values.reduce((widest, value) => Math.max(widest, value.length), header.length);\n}\n\n/** Thousands separators without pulling in ICU, so the output is identical everywhere. */\nfunction group(n: number): string {\n const digits = String(Math.abs(Math.trunc(n)));\n const grouped = digits.replace(/\\B(?=(\\d{3})+(?!\\d))/g, ',');\n return n < 0 ? `-${grouped}` : grouped;\n}\n\nfunction delta(inputBytes: number, outputBytes: number): string {\n if (inputBytes === 0) return 'empty input';\n const percent = ((outputBytes - inputBytes) / inputBytes) * 100;\n const sign = percent > 0 ? '+' : '';\n return `${sign}${percent.toFixed(1)}%`;\n}\n\nfunction count(n: number, noun: string, pluralSuffix = 's'): string {\n return `${group(n)} ${noun}${n === 1 ? '' : pluralSuffix}`;\n}\n\nfunction clip(text: string, max: number): string {\n return text.length <= max ? text : `${text.slice(0, max - 1)}…`;\n}\n"]}
@@ -1,4 +1,4 @@
1
- import { CLI_NAME } from './args.js';
1
+ import { CLI_NAME } from './shell.js';
2
2
  /** Longest explanation printed in full before it gets an ellipsis. */
3
3
  const EXPLANATION_WIDTH = 46;
4
4
  /**
@@ -76,7 +76,7 @@ export function formatMapReport({ map, source, budgetSource }) {
76
76
  `— the map fits itself to the budget by construction, so there is no over-budget exit`);
77
77
  if (map.cache !== undefined) {
78
78
  lines.push(`cache ${count(map.cache.hits, 'hit')}, ${count(map.cache.misses, 'miss', 'es')}, ` +
79
- `${group(map.cache.discarded)} discarded`);
79
+ `${group(map.cache.discarded)} discarded, ${group(map.cache.pruned)} pruned`);
80
80
  }
81
81
  for (const warning of map.warnings) {
82
82
  lines.push(`warning ${warning.rule}: ${warning.explanation}`);
@@ -1 +1 @@
1
- {"version":3,"file":"report.js","sourceRoot":"","sources":["../../src/cli/report.ts"],"names":[],"mappings":"AAGA,OAAO,EAAE,QAAQ,EAAE,MAAM,WAAW,CAAC;AAYrC,sEAAsE;AACtE,MAAM,iBAAiB,GAAG,EAAE,CAAC;AAE7B;;;;;;;;GAQG;AACH,MAAM,UAAU,YAAY,CAAC,EAAE,MAAM,EAAE,MAAM,EAAE,WAAW,EAAE,SAAS,EAAe;IAClF,MAAM,KAAK,GAAa,EAAE,CAAC;IAE3B,KAAK,CAAC,IAAI,CAAC,CAAC,QAAQ,EAAE,MAAM,EAAE,MAAM,CAAC,QAAQ,EAAE,MAAM,CAAC,OAAO,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,CAAC;IAC3E,KAAK,CAAC,IAAI,CACR,MAAM,KAAK,CAAC,MAAM,CAAC,UAAU,CAAC,YAAY,KAAK,CAAC,MAAM,CAAC,WAAW,CAAC,OAAO;QACxE,IAAI,KAAK,CAAC,MAAM,CAAC,UAAU,EAAE,MAAM,CAAC,WAAW,CAAC,KAAK,KAAK,CAAC,MAAM,CAAC,QAAQ,CAAC,MAAM,EAAE,SAAS,CAAC,GAAG,CACnG,CAAC;IAEF,IAAI,MAAM,CAAC,QAAQ,KAAK,SAAS,EAAE,CAAC;QAClC,MAAM,EAAE,KAAK,EAAE,MAAM,EAAE,IAAI,EAAE,OAAO,EAAE,GAAG,MAAM,CAAC,QAAQ,CAAC;QACzD,KAAK,CAAC,IAAI,CAAC,MAAM,KAAK,CAAC,KAAK,CAAC,UAAU,KAAK,CAAC,MAAM,CAAC,IAAI,IAAI,KAAK,OAAO,GAAG,CAAC,CAAC;IAC/E,CAAC;IAED,IAAI,MAAM,CAAC,WAAW,GAAG,WAAW,EAAE,CAAC;QACrC,KAAK,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;QACf,KAAK,CAAC,IAAI,CACR,gBAAgB,KAAK,CAAC,MAAM,CAAC,WAAW,CAAC,gBAAgB,KAAK,CAAC,WAAW,CAAC,YAAY;YACrF,aAAa,KAAK,CAAC,MAAM,CAAC,WAAW,GAAG,WAAW,CAAC,KAAK,CAC5D,CAAC;QACF,KAAK,CAAC,IAAI,CAAC,kFAAkF,CAAC,CAAC;QAC/F,KAAK,CAAC,IAAI,CAAC,sEAAsE,CAAC,CAAC;IACrF,CAAC;IAED,IAAI,MAAM,CAAC,QAAQ,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;QACjC,KAAK,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;QACf,KAAK,CAAC,IAAI,CAAC,0EAA0E,CAAC,CAAC;QACvF,KAAK,CAAC,IAAI,CAAC,0EAA0E,CAAC,CAAC;QACvF,KAAK,CAAC,IAAI,CAAC,6BAA6B,CAAC,CAAC;QAC1C,OAAO,GAAG,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,IAAI,CAAC;IACjC,CAAC;IAED,MAAM,IAAI,GAAG,MAAM,CAAC,QAAQ,CAAC,GAAG,CAAC,CAAC,OAAO,EAAE,EAAE,CAAC,CAAC;QAC7C,IAAI,EAAE,OAAO,CAAC,MAAM,CAAC,IAAI;QACzB,KAAK,EAAE,MAAM,CAAC,QAAQ,CAAC,SAAS,EAAE,OAAO,CAAC,KAAK,CAAC,KAAK,EAAE,OAAO,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC;QAC1E,KAAK,EAAE,KAAK,CAAC,OAAO,CAAC,KAAK,CAAC;QAC3B,IAAI,EAAE,OAAO,CAAC,IAAI;QAClB,WAAW,EAAE,IAAI,CAAC,OAAO,CAAC,MAAM,CAAC,WAAW,EAAE,iBAAiB,CAAC;KACjE,CAAC,CAAC,CAAC;IAEJ,MAAM,SAAS,GAAG,KAAK,CACrB,MAAM,EACN,IAAI,CAAC,GAAG,CAAC,CAAC,GAAG,EAAE,EAAE,CAAC,GAAG,CAAC,IAAI,CAAC,CAC5B,CAAC;IACF,MAAM,UAAU,GAAG,KAAK,CACtB,OAAO,EACP,IAAI,CAAC,GAAG,CAAC,CAAC,GAAG,EAAE,EAAE,CAAC,GAAG,CAAC,KAAK,CAAC,CAC7B,CAAC;IACF,MAAM,UAAU,GAAG,KAAK,CACtB,OAAO,EACP,IAAI,CAAC,GAAG,CAAC,CAAC,GAAG,EAAE,EAAE,CAAC,GAAG,CAAC,KAAK,CAAC,CAC7B,CAAC;IACF,MAAM,SAAS,GAAG,KAAK,CACrB,MAAM,EACN,IAAI,CAAC,GAAG,CAAC,CAAC,GAAG,EAAE,EAAE,CAAC,GAAG,CAAC,IAAI,CAAC,CAC5B,CAAC;IAEF,KAAK,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;IACf,KAAK,CAAC,IAAI,CACR,KAAK,MAAM,CAAC,MAAM,CAAC,SAAS,CAAC,KAAK,OAAO,CAAC,QAAQ,CAAC,UAAU,CAAC,IAAI;QAChE,GAAG,OAAO,CAAC,QAAQ,CAAC,UAAU,CAAC,KAAK,MAAM,CAAC,MAAM,CAAC,SAAS,CAAC,eAAe,CAC9E,CAAC;IACF,KAAK,MAAM,GAAG,IAAI,IAAI,EAAE,CAAC;QACvB,KAAK,CAAC,IAAI,CACR,KAAK,GAAG,CAAC,IAAI,CAAC,MAAM,CAAC,SAAS,CAAC,KAAK,GAAG,CAAC,KAAK,CAAC,QAAQ,CAAC,UAAU,CAAC,IAAI;YACpE,GAAG,GAAG,CAAC,KAAK,CAAC,QAAQ,CAAC,UAAU,CAAC,KAAK,GAAG,CAAC,IAAI,CAAC,MAAM,CAAC,SAAS,CAAC,KAAK,GAAG,CAAC,WAAW,EAAE,CACzF,CAAC;IACJ,CAAC;IAED,OAAO,GAAG,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,IAAI,CAAC;AACjC,CAAC;AAeD;;;;;;;;GAQG;AACH,MAAM,UAAU,eAAe,CAAC,EAAE,GAAG,EAAE,MAAM,EAAE,YAAY,EAAkB;IAC3E,MAAM,KAAK,GAAa,EAAE,CAAC;IAE3B,KAAK,CAAC,IAAI,CAAC,CAAC,GAAG,QAAQ,MAAM,EAAE,MAAM,EAAE,GAAG,CAAC,EAAE,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,CAAC;IAC3D,KAAK,CAAC,IAAI,CACR,iBAAiB,KAAK,CAAC,GAAG,CAAC,YAAY,CAAC,EAAE;QACxC,CAAC,GAAG,CAAC,aAAa,KAAK,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,KAAK,KAAK,CAAC,GAAG,CAAC,aAAa,EAAE,aAAa,CAAC,WAAW,CAAC;QACxF,qBAAqB,KAAK,CAAC,GAAG,CAAC,gBAAgB,CAAC,EAAE,CACrD,CAAC;IACF,KAAK,CAAC,IAAI,CACR,YAAY,KAAK,CAAC,GAAG,CAAC,OAAO,CAAC,MAAM,CAAC,OAAO,KAAK,CAAC,GAAG,CAAC,gBAAgB,CAAC,UAAU;QAC/E,CAAC,GAAG,CAAC,aAAa,KAAK,CAAC;YACtB,CAAC,CAAC,EAAE;YACJ,CAAC,CAAC,MAAM,KAAK,CAAC,GAAG,CAAC,QAAQ,CAAC,MAAM,CAAC,OAAO,KAAK,CAAC,GAAG,CAAC,aAAa,CAAC,kBAAkB,CAAC,CACzF,CAAC;IACF,KAAK,CAAC,IAAI,CACR,cAAc,KAAK,CAAC,GAAG,CAAC,WAAW,CAAC,OAAO,KAAK,CAAC,GAAG,CAAC,WAAW,CAAC,YAAY,YAAY,IAAI;QAC3F,sFAAsF,CACzF,CAAC;IAEF,IAAI,GAAG,CAAC,KAAK,KAAK,SAAS,EAAE,CAAC;QAC5B,KAAK,CAAC,IAAI,CACR,UAAU,KAAK,CAAC,GAAG,CAAC,KAAK,CAAC,IAAI,EAAE,KAAK,CAAC,KAAK,KAAK,CAAC,GAAG,CAAC,KAAK,CAAC,MAAM,EAAE,MAAM,EAAE,IAAI,CAAC,IAAI;YAClF,GAAG,KAAK,CAAC,GAAG,CAAC,KAAK,CAAC,SAAS,CAAC,YAAY,CAC5C,CAAC;IACJ,CAAC;IACD,KAAK,MAAM,OAAO,IAAI,GAAG,CAAC,QAAQ,EAAE,CAAC;QACnC,KAAK,CAAC,IAAI,CAAC,YAAY,OAAO,CAAC,IAAI,KAAK,OAAO,CAAC,WAAW,EAAE,CAAC,CAAC;IACjE,CAAC;IAED,OAAO,GAAG,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,IAAI,CAAC;AACjC,CAAC;AAED,0FAA0F;AAC1F,SAAS,QAAQ,CAAC,IAAY,EAAE,KAAa,EAAE,GAAW;IACxD,MAAM,KAAK,GAAG,MAAM,CAAC,IAAI,CAAC,IAAI,EAAE,MAAM,CAAC,CAAC,QAAQ,CAAC,KAAK,EAAE,GAAG,CAAC,CAAC,QAAQ,CAAC,MAAM,CAAC,CAAC;IAC9E,OAAO,KAAK,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC,MAAM,CAAC;AAClC,CAAC;AAED,SAAS,KAAK,CAAC,MAAc,EAAE,MAAyB;IACtD,OAAO,MAAM,CAAC,MAAM,CAAC,CAAC,MAAM,EAAE,KAAK,EAAE,EAAE,CAAC,IAAI,CAAC,GAAG,CAAC,MAAM,EAAE,KAAK,CAAC,MAAM,CAAC,EAAE,MAAM,CAAC,MAAM,CAAC,CAAC;AACzF,CAAC;AAED,0FAA0F;AAC1F,SAAS,KAAK,CAAC,CAAS;IACtB,MAAM,MAAM,GAAG,MAAM,CAAC,IAAI,CAAC,GAAG,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;IAC/C,MAAM,OAAO,GAAG,MAAM,CAAC,OAAO,CAAC,uBAAuB,EAAE,GAAG,CAAC,CAAC;IAC7D,OAAO,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,IAAI,OAAO,EAAE,CAAC,CAAC,CAAC,OAAO,CAAC;AACzC,CAAC;AAED,SAAS,KAAK,CAAC,UAAkB,EAAE,WAAmB;IACpD,IAAI,UAAU,KAAK,CAAC;QAAE,OAAO,aAAa,CAAC;IAC3C,MAAM,OAAO,GAAG,CAAC,CAAC,WAAW,GAAG,UAAU,CAAC,GAAG,UAAU,CAAC,GAAG,GAAG,CAAC;IAChE,MAAM,IAAI,GAAG,OAAO,GAAG,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,CAAC;IACpC,OAAO,GAAG,IAAI,GAAG,OAAO,CAAC,OAAO,CAAC,CAAC,CAAC,GAAG,CAAC;AACzC,CAAC;AAED,SAAS,KAAK,CAAC,CAAS,EAAE,IAAY,EAAE,YAAY,GAAG,GAAG;IACxD,OAAO,GAAG,KAAK,CAAC,CAAC,CAAC,IAAI,IAAI,GAAG,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,YAAY,EAAE,CAAC;AAC7D,CAAC;AAED,SAAS,IAAI,CAAC,IAAY,EAAE,GAAW;IACrC,OAAO,IAAI,CAAC,MAAM,IAAI,GAAG,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,GAAG,IAAI,CAAC,KAAK,CAAC,CAAC,EAAE,GAAG,GAAG,CAAC,CAAC,GAAG,CAAC;AAClE,CAAC"}
1
+ {"version":3,"file":"report.js","sourceRoot":"","sources":["../../src/cli/report.ts"],"names":[],"mappings":"AAGA,OAAO,EAAE,QAAQ,EAAE,MAAM,YAAY,CAAC;AAYtC,sEAAsE;AACtE,MAAM,iBAAiB,GAAG,EAAE,CAAC;AAE7B;;;;;;;;GAQG;AACH,MAAM,UAAU,YAAY,CAAC,EAAE,MAAM,EAAE,MAAM,EAAE,WAAW,EAAE,SAAS,EAAe;IAClF,MAAM,KAAK,GAAa,EAAE,CAAC;IAE3B,KAAK,CAAC,IAAI,CAAC,CAAC,QAAQ,EAAE,MAAM,EAAE,MAAM,CAAC,QAAQ,EAAE,MAAM,CAAC,OAAO,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,CAAC;IAC3E,KAAK,CAAC,IAAI,CACR,MAAM,KAAK,CAAC,MAAM,CAAC,UAAU,CAAC,YAAY,KAAK,CAAC,MAAM,CAAC,WAAW,CAAC,OAAO;QACxE,IAAI,KAAK,CAAC,MAAM,CAAC,UAAU,EAAE,MAAM,CAAC,WAAW,CAAC,KAAK,KAAK,CAAC,MAAM,CAAC,QAAQ,CAAC,MAAM,EAAE,SAAS,CAAC,GAAG,CACnG,CAAC;IAEF,IAAI,MAAM,CAAC,QAAQ,KAAK,SAAS,EAAE,CAAC;QAClC,MAAM,EAAE,KAAK,EAAE,MAAM,EAAE,IAAI,EAAE,OAAO,EAAE,GAAG,MAAM,CAAC,QAAQ,CAAC;QACzD,KAAK,CAAC,IAAI,CAAC,MAAM,KAAK,CAAC,KAAK,CAAC,UAAU,KAAK,CAAC,MAAM,CAAC,IAAI,IAAI,KAAK,OAAO,GAAG,CAAC,CAAC;IAC/E,CAAC;IAED,IAAI,MAAM,CAAC,WAAW,GAAG,WAAW,EAAE,CAAC;QACrC,KAAK,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;QACf,KAAK,CAAC,IAAI,CACR,gBAAgB,KAAK,CAAC,MAAM,CAAC,WAAW,CAAC,gBAAgB,KAAK,CAAC,WAAW,CAAC,YAAY;YACrF,aAAa,KAAK,CAAC,MAAM,CAAC,WAAW,GAAG,WAAW,CAAC,KAAK,CAC5D,CAAC;QACF,KAAK,CAAC,IAAI,CAAC,kFAAkF,CAAC,CAAC;QAC/F,KAAK,CAAC,IAAI,CAAC,sEAAsE,CAAC,CAAC;IACrF,CAAC;IAED,IAAI,MAAM,CAAC,QAAQ,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;QACjC,KAAK,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;QACf,KAAK,CAAC,IAAI,CAAC,0EAA0E,CAAC,CAAC;QACvF,KAAK,CAAC,IAAI,CAAC,0EAA0E,CAAC,CAAC;QACvF,KAAK,CAAC,IAAI,CAAC,6BAA6B,CAAC,CAAC;QAC1C,OAAO,GAAG,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,IAAI,CAAC;IACjC,CAAC;IAED,MAAM,IAAI,GAAG,MAAM,CAAC,QAAQ,CAAC,GAAG,CAAC,CAAC,OAAO,EAAE,EAAE,CAAC,CAAC;QAC7C,IAAI,EAAE,OAAO,CAAC,MAAM,CAAC,IAAI;QACzB,KAAK,EAAE,MAAM,CAAC,QAAQ,CAAC,SAAS,EAAE,OAAO,CAAC,KAAK,CAAC,KAAK,EAAE,OAAO,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC;QAC1E,KAAK,EAAE,KAAK,CAAC,OAAO,CAAC,KAAK,CAAC;QAC3B,IAAI,EAAE,OAAO,CAAC,IAAI;QAClB,WAAW,EAAE,IAAI,CAAC,OAAO,CAAC,MAAM,CAAC,WAAW,EAAE,iBAAiB,CAAC;KACjE,CAAC,CAAC,CAAC;IAEJ,MAAM,SAAS,GAAG,KAAK,CACrB,MAAM,EACN,IAAI,CAAC,GAAG,CAAC,CAAC,GAAG,EAAE,EAAE,CAAC,GAAG,CAAC,IAAI,CAAC,CAC5B,CAAC;IACF,MAAM,UAAU,GAAG,KAAK,CACtB,OAAO,EACP,IAAI,CAAC,GAAG,CAAC,CAAC,GAAG,EAAE,EAAE,CAAC,GAAG,CAAC,KAAK,CAAC,CAC7B,CAAC;IACF,MAAM,UAAU,GAAG,KAAK,CACtB,OAAO,EACP,IAAI,CAAC,GAAG,CAAC,CAAC,GAAG,EAAE,EAAE,CAAC,GAAG,CAAC,KAAK,CAAC,CAC7B,CAAC;IACF,MAAM,SAAS,GAAG,KAAK,CACrB,MAAM,EACN,IAAI,CAAC,GAAG,CAAC,CAAC,GAAG,EAAE,EAAE,CAAC,GAAG,CAAC,IAAI,CAAC,CAC5B,CAAC;IAEF,KAAK,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;IACf,KAAK,CAAC,IAAI,CACR,KAAK,MAAM,CAAC,MAAM,CAAC,SAAS,CAAC,KAAK,OAAO,CAAC,QAAQ,CAAC,UAAU,CAAC,IAAI;QAChE,GAAG,OAAO,CAAC,QAAQ,CAAC,UAAU,CAAC,KAAK,MAAM,CAAC,MAAM,CAAC,SAAS,CAAC,eAAe,CAC9E,CAAC;IACF,KAAK,MAAM,GAAG,IAAI,IAAI,EAAE,CAAC;QACvB,KAAK,CAAC,IAAI,CACR,KAAK,GAAG,CAAC,IAAI,CAAC,MAAM,CAAC,SAAS,CAAC,KAAK,GAAG,CAAC,KAAK,CAAC,QAAQ,CAAC,UAAU,CAAC,IAAI;YACpE,GAAG,GAAG,CAAC,KAAK,CAAC,QAAQ,CAAC,UAAU,CAAC,KAAK,GAAG,CAAC,IAAI,CAAC,MAAM,CAAC,SAAS,CAAC,KAAK,GAAG,CAAC,WAAW,EAAE,CACzF,CAAC;IACJ,CAAC;IAED,OAAO,GAAG,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,IAAI,CAAC;AACjC,CAAC;AAeD;;;;;;;;GAQG;AACH,MAAM,UAAU,eAAe,CAAC,EAAE,GAAG,EAAE,MAAM,EAAE,YAAY,EAAkB;IAC3E,MAAM,KAAK,GAAa,EAAE,CAAC;IAE3B,KAAK,CAAC,IAAI,CAAC,CAAC,GAAG,QAAQ,MAAM,EAAE,MAAM,EAAE,GAAG,CAAC,EAAE,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,CAAC;IAC3D,KAAK,CAAC,IAAI,CACR,iBAAiB,KAAK,CAAC,GAAG,CAAC,YAAY,CAAC,EAAE;QACxC,CAAC,GAAG,CAAC,aAAa,KAAK,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,KAAK,KAAK,CAAC,GAAG,CAAC,aAAa,EAAE,aAAa,CAAC,WAAW,CAAC;QACxF,qBAAqB,KAAK,CAAC,GAAG,CAAC,gBAAgB,CAAC,EAAE,CACrD,CAAC;IACF,KAAK,CAAC,IAAI,CACR,YAAY,KAAK,CAAC,GAAG,CAAC,OAAO,CAAC,MAAM,CAAC,OAAO,KAAK,CAAC,GAAG,CAAC,gBAAgB,CAAC,UAAU;QAC/E,CAAC,GAAG,CAAC,aAAa,KAAK,CAAC;YACtB,CAAC,CAAC,EAAE;YACJ,CAAC,CAAC,MAAM,KAAK,CAAC,GAAG,CAAC,QAAQ,CAAC,MAAM,CAAC,OAAO,KAAK,CAAC,GAAG,CAAC,aAAa,CAAC,kBAAkB,CAAC,CACzF,CAAC;IACF,KAAK,CAAC,IAAI,CACR,cAAc,KAAK,CAAC,GAAG,CAAC,WAAW,CAAC,OAAO,KAAK,CAAC,GAAG,CAAC,WAAW,CAAC,YAAY,YAAY,IAAI;QAC3F,sFAAsF,CACzF,CAAC;IAEF,IAAI,GAAG,CAAC,KAAK,KAAK,SAAS,EAAE,CAAC;QAC5B,KAAK,CAAC,IAAI,CACR,UAAU,KAAK,CAAC,GAAG,CAAC,KAAK,CAAC,IAAI,EAAE,KAAK,CAAC,KAAK,KAAK,CAAC,GAAG,CAAC,KAAK,CAAC,MAAM,EAAE,MAAM,EAAE,IAAI,CAAC,IAAI;YAClF,GAAG,KAAK,CAAC,GAAG,CAAC,KAAK,CAAC,SAAS,CAAC,eAAe,KAAK,CAAC,GAAG,CAAC,KAAK,CAAC,MAAM,CAAC,SAAS,CAC/E,CAAC;IACJ,CAAC;IACD,KAAK,MAAM,OAAO,IAAI,GAAG,CAAC,QAAQ,EAAE,CAAC;QACnC,KAAK,CAAC,IAAI,CAAC,YAAY,OAAO,CAAC,IAAI,KAAK,OAAO,CAAC,WAAW,EAAE,CAAC,CAAC;IACjE,CAAC;IAED,OAAO,GAAG,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,IAAI,CAAC;AACjC,CAAC;AAED,0FAA0F;AAC1F,SAAS,QAAQ,CAAC,IAAY,EAAE,KAAa,EAAE,GAAW;IACxD,MAAM,KAAK,GAAG,MAAM,CAAC,IAAI,CAAC,IAAI,EAAE,MAAM,CAAC,CAAC,QAAQ,CAAC,KAAK,EAAE,GAAG,CAAC,CAAC,QAAQ,CAAC,MAAM,CAAC,CAAC;IAC9E,OAAO,KAAK,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC,MAAM,CAAC;AAClC,CAAC;AAED,SAAS,KAAK,CAAC,MAAc,EAAE,MAAyB;IACtD,OAAO,MAAM,CAAC,MAAM,CAAC,CAAC,MAAM,EAAE,KAAK,EAAE,EAAE,CAAC,IAAI,CAAC,GAAG,CAAC,MAAM,EAAE,KAAK,CAAC,MAAM,CAAC,EAAE,MAAM,CAAC,MAAM,CAAC,CAAC;AACzF,CAAC;AAED,0FAA0F;AAC1F,SAAS,KAAK,CAAC,CAAS;IACtB,MAAM,MAAM,GAAG,MAAM,CAAC,IAAI,CAAC,GAAG,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;IAC/C,MAAM,OAAO,GAAG,MAAM,CAAC,OAAO,CAAC,uBAAuB,EAAE,GAAG,CAAC,CAAC;IAC7D,OAAO,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,IAAI,OAAO,EAAE,CAAC,CAAC,CAAC,OAAO,CAAC;AACzC,CAAC;AAED,SAAS,KAAK,CAAC,UAAkB,EAAE,WAAmB;IACpD,IAAI,UAAU,KAAK,CAAC;QAAE,OAAO,aAAa,CAAC;IAC3C,MAAM,OAAO,GAAG,CAAC,CAAC,WAAW,GAAG,UAAU,CAAC,GAAG,UAAU,CAAC,GAAG,GAAG,CAAC;IAChE,MAAM,IAAI,GAAG,OAAO,GAAG,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,CAAC;IACpC,OAAO,GAAG,IAAI,GAAG,OAAO,CAAC,OAAO,CAAC,CAAC,CAAC,GAAG,CAAC;AACzC,CAAC;AAED,SAAS,KAAK,CAAC,CAAS,EAAE,IAAY,EAAE,YAAY,GAAG,GAAG;IACxD,OAAO,GAAG,KAAK,CAAC,CAAC,CAAC,IAAI,IAAI,GAAG,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,YAAY,EAAE,CAAC;AAC7D,CAAC;AAED,SAAS,IAAI,CAAC,IAAY,EAAE,GAAW;IACrC,OAAO,IAAI,CAAC,MAAM,IAAI,GAAG,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,GAAG,IAAI,CAAC,KAAK,CAAC,CAAC,EAAE,GAAG,GAAG,CAAC,CAAC,GAAG,CAAC;AAClE,CAAC","sourcesContent":["import type { RepoMap } from '../repomap/map.ts';\nimport type { SmeltResult } from '../types.ts';\n\nimport { CLI_NAME } from './shell.ts';\n\nexport interface ReportInput {\n readonly result: SmeltResult;\n /** What to call the input in the header: a path, or `'<stdin>'`. */\n readonly source: string;\n /** The budget the caller asked for, so the report can say when it was missed. */\n readonly budgetBytes: number;\n /** The exact text that was smelted. Used only to count lines inside each range. */\n readonly inputText: string;\n}\n\n/** Longest explanation printed in full before it gets an ellipsis. */\nconst EXPLANATION_WIDTH = 46;\n\n/**\n * The report, for stderr.\n *\n * Every total here is read straight off the {@link SmeltResult} — `inputBytes`,\n * `outputBytes`, `elisions.length`. The CLI keeps no counters of its own, because two\n * pieces of code counting the same bytes is how a report ends up disagreeing with the\n * library it is reporting on, and the report is the thing a human believes.\n * `test/cli.test.ts` asserts the printed numbers equal the result's fields.\n */\nexport function formatReport({ result, source, budgetBytes, inputText }: ReportInput): string {\n const lines: string[] = [];\n\n lines.push([CLI_NAME, source, result.language, result.planner].join(' '));\n lines.push(\n `in ${group(result.inputBytes)} B → out ${group(result.outputBytes)} B ` +\n `(${delta(result.inputBytes, result.outputBytes)}, ${count(result.elisions.length, 'elision')})`,\n );\n\n if (result.measured !== undefined) {\n const { input, output, unit, measure } = result.measured;\n lines.push(`in ${group(input)} → out ${group(output)} ${unit} (${measure})`);\n }\n\n if (result.outputBytes > budgetBytes) {\n lines.push('');\n lines.push(\n `OVER BUDGET ${group(result.outputBytes)} B against a ${group(budgetBytes)} B budget ` +\n `— over by ${group(result.outputBytes - budgetBytes)} B.`,\n );\n lines.push(' The plan is reported as it came back. smelt did not cut the regions');\n lines.push(' you asked to keep in order to make a number look right.');\n }\n\n if (result.elisions.length === 0) {\n lines.push('');\n lines.push(' nothing elided — the input already fits, or every run was too small to');\n lines.push(' be worth a marker (a marker that costs more than the lines it replaces');\n lines.push(' makes the output bigger).');\n return `${lines.join('\\n')}\\n`;\n }\n\n const rows = result.elisions.map((elision) => ({\n rule: elision.reason.rule,\n lines: String(lineSpan(inputText, elision.range.start, elision.range.end)),\n bytes: group(elision.bytes),\n hash: elision.hash,\n explanation: clip(elision.reason.explanation, EXPLANATION_WIDTH),\n }));\n\n const ruleWidth = width(\n 'rule',\n rows.map((row) => row.rule),\n );\n const linesWidth = width(\n 'lines',\n rows.map((row) => row.lines),\n );\n const bytesWidth = width(\n 'bytes',\n rows.map((row) => row.bytes),\n );\n const hashWidth = width(\n 'hash',\n rows.map((row) => row.hash),\n );\n\n lines.push('');\n lines.push(\n ` ${'rule'.padEnd(ruleWidth)} ${'lines'.padStart(linesWidth)} ` +\n `${'bytes'.padStart(bytesWidth)} ${'hash'.padEnd(hashWidth)} explanation`,\n );\n for (const row of rows) {\n lines.push(\n ` ${row.rule.padEnd(ruleWidth)} ${row.lines.padStart(linesWidth)} ` +\n `${row.bytes.padStart(bytesWidth)} ${row.hash.padEnd(hashWidth)} ${row.explanation}`,\n );\n }\n\n return `${lines.join('\\n')}\\n`;\n}\n\n/** What `smelt map` prints to stderr. */\nexport interface MapReportInput {\n readonly map: RepoMap;\n /** The directory named on the command line, exactly as the user wrote it. */\n readonly source: string;\n /**\n * Where the budget came from — the `ResolvedMapRun.budgetSource` receipt, printed\n * beside the budget so a surprising number can be traced to the flag or the config\n * file that set it without re-deriving the precedence by hand.\n */\n readonly budgetSource: 'flag' | 'config';\n}\n\n/**\n * The map report, for stderr — same law as {@link formatReport}: every number is\n * read straight off the {@link RepoMap} the library returned. In particular the\n * \"bytes used\" figure is `map.outputBytes`, which the library measured off the\n * rendered text — the CLI counts nothing itself, because a report that keeps its\n * own tally is a report that can disagree with the map it describes.\n * `test/guards/repo-map.test.ts` asserts the printed figure equals the actual byte\n * length of what landed on stdout, and a mutation proves the assertion can go red.\n */\nexport function formatMapReport({ map, source, budgetSource }: MapReportInput): string {\n const lines: string[] = [];\n\n lines.push([`${CLI_NAME} map`, source, map.id].join(' '));\n lines.push(\n `files scanned ${group(map.filesScanned)}` +\n (map.binarySkipped === 0 ? '' : ` (${count(map.binarySkipped, 'binary file')} skipped)`) +\n ` symbols ranked ${group(map.definitionsTotal)}`,\n );\n lines.push(\n `included ${group(map.entries.length)} of ${group(map.definitionsTotal)} symbols` +\n (map.pathOnlyTotal === 0\n ? ''\n : ` + ${group(map.pathOnly.length)} of ${group(map.pathOnlyTotal)} path-only files`),\n );\n lines.push(\n `bytes used ${group(map.outputBytes)} of ${group(map.budgetBytes)} budget (${budgetSource}) ` +\n `— the map fits itself to the budget by construction, so there is no over-budget exit`,\n );\n\n if (map.cache !== undefined) {\n lines.push(\n `cache ${count(map.cache.hits, 'hit')}, ${count(map.cache.misses, 'miss', 'es')}, ` +\n `${group(map.cache.discarded)} discarded, ${group(map.cache.pruned)} pruned`,\n );\n }\n for (const warning of map.warnings) {\n lines.push(`warning ${warning.rule}: ${warning.explanation}`);\n }\n\n return `${lines.join('\\n')}\\n`;\n}\n\n/** How many lines a byte range covers in the input. Derived, never tallied separately. */\nfunction lineSpan(text: string, start: number, end: number): number {\n const slice = Buffer.from(text, 'utf8').subarray(start, end).toString('utf8');\n return slice.split('\\n').length;\n}\n\nfunction width(header: string, values: readonly string[]): number {\n return values.reduce((widest, value) => Math.max(widest, value.length), header.length);\n}\n\n/** Thousands separators without pulling in ICU, so the output is identical everywhere. */\nfunction group(n: number): string {\n const digits = String(Math.abs(Math.trunc(n)));\n const grouped = digits.replace(/\\B(?=(\\d{3})+(?!\\d))/g, ',');\n return n < 0 ? `-${grouped}` : grouped;\n}\n\nfunction delta(inputBytes: number, outputBytes: number): string {\n if (inputBytes === 0) return 'empty input';\n const percent = ((outputBytes - inputBytes) / inputBytes) * 100;\n const sign = percent > 0 ? '+' : '';\n return `${sign}${percent.toFixed(1)}%`;\n}\n\nfunction count(n: number, noun: string, pluralSuffix = 's'): string {\n return `${group(n)} ${noun}${n === 1 ? '' : pluralSuffix}`;\n}\n\nfunction clip(text: string, max: number): string {\n return text.length <= max ? text : `${text.slice(0, max - 1)}…`;\n}\n"]}