@smeltjs/core 0.2.0 → 0.4.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.
- package/README.md +3 -3
- package/dist/agents/guide.d.ts +68 -0
- package/dist/agents/guide.d.ts.map +1 -0
- package/dist/agents/guide.js +72 -0
- package/dist/agents/guide.js.map +1 -0
- package/dist/agents/instructions.d.ts +133 -0
- package/dist/agents/instructions.d.ts.map +1 -0
- package/dist/agents/instructions.js +212 -0
- package/dist/agents/instructions.js.map +1 -0
- package/dist/agents/lint.d.ts +154 -0
- package/dist/agents/lint.d.ts.map +1 -0
- package/dist/agents/lint.js +761 -0
- package/dist/agents/lint.js.map +1 -0
- package/dist/agents/split.d.ts +113 -0
- package/dist/agents/split.d.ts.map +1 -0
- package/dist/agents/split.js +234 -0
- package/dist/agents/split.js.map +1 -0
- package/dist/apply.d.ts.map +1 -1
- package/dist/apply.js.map +1 -1
- package/dist/cache/prefix.d.ts.map +1 -1
- package/dist/cache/prefix.js.map +1 -1
- package/dist/cli/agents.d.ts +39 -0
- package/dist/cli/agents.d.ts.map +1 -0
- package/dist/cli/agents.js +121 -0
- package/dist/cli/agents.js.map +1 -0
- package/dist/cli/args.d.ts +17 -70
- package/dist/cli/args.d.ts.map +1 -1
- package/dist/cli/args.js +18 -338
- package/dist/cli/args.js.map +1 -1
- package/dist/cli/bin.d.ts.map +1 -1
- package/dist/cli/bin.js.map +1 -1
- package/dist/cli/config.d.ts +60 -0
- package/dist/cli/config.d.ts.map +1 -1
- package/dist/cli/config.js +89 -2
- package/dist/cli/config.js.map +1 -1
- package/dist/cli/hooks.d.ts +55 -51
- package/dist/cli/hooks.d.ts.map +1 -1
- package/dist/cli/hooks.js +206 -658
- package/dist/cli/hooks.js.map +1 -1
- package/dist/cli/init.d.ts +30 -15
- package/dist/cli/init.d.ts.map +1 -1
- package/dist/cli/init.js +167 -38
- package/dist/cli/init.js.map +1 -1
- package/dist/cli/report.d.ts +23 -0
- package/dist/cli/report.d.ts.map +1 -1
- package/dist/cli/report.js +142 -4
- package/dist/cli/report.js.map +1 -1
- package/dist/cli/run.d.ts +29 -90
- package/dist/cli/run.d.ts.map +1 -1
- package/dist/cli/run.js +34 -342
- package/dist/cli/run.js.map +1 -1
- package/dist/cli/shell.d.ts +106 -0
- package/dist/cli/shell.d.ts.map +1 -0
- package/dist/cli/shell.js +100 -0
- package/dist/cli/shell.js.map +1 -0
- package/dist/cli/subcommands/agents.d.ts +72 -0
- package/dist/cli/subcommands/agents.d.ts.map +1 -0
- package/dist/cli/subcommands/agents.js +162 -0
- package/dist/cli/subcommands/agents.js.map +1 -0
- package/dist/cli/subcommands/flags.d.ts +144 -0
- package/dist/cli/subcommands/flags.d.ts.map +1 -0
- package/dist/cli/subcommands/flags.js +220 -0
- package/dist/cli/subcommands/flags.js.map +1 -0
- package/dist/cli/subcommands/hooks.d.ts +18 -0
- package/dist/cli/subcommands/hooks.d.ts.map +1 -0
- package/dist/cli/subcommands/hooks.js +80 -0
- package/dist/cli/subcommands/hooks.js.map +1 -0
- package/dist/cli/subcommands/init.d.ts +19 -0
- package/dist/cli/subcommands/init.d.ts.map +1 -0
- package/dist/cli/subcommands/init.js +44 -0
- package/dist/cli/subcommands/init.js.map +1 -0
- package/dist/cli/subcommands/map.d.ts +75 -0
- package/dist/cli/subcommands/map.d.ts.map +1 -0
- package/dist/cli/subcommands/map.js +132 -0
- package/dist/cli/subcommands/map.js.map +1 -0
- package/dist/cli/subcommands/registry.d.ts +81 -0
- package/dist/cli/subcommands/registry.d.ts.map +1 -0
- package/dist/cli/subcommands/registry.js +141 -0
- package/dist/cli/subcommands/registry.js.map +1 -0
- package/dist/cli/subcommands/retrieve.d.ts +74 -0
- package/dist/cli/subcommands/retrieve.d.ts.map +1 -0
- package/dist/cli/subcommands/retrieve.js +84 -0
- package/dist/cli/subcommands/retrieve.js.map +1 -0
- package/dist/cli/subcommands/smelt.d.ts +107 -0
- package/dist/cli/subcommands/smelt.d.ts.map +1 -0
- package/dist/cli/subcommands/smelt.js +304 -0
- package/dist/cli/subcommands/smelt.js.map +1 -0
- package/dist/cli/subcommands/stats.d.ts +43 -0
- package/dist/cli/subcommands/stats.d.ts.map +1 -0
- package/dist/cli/subcommands/stats.js +62 -0
- package/dist/cli/subcommands/stats.js.map +1 -0
- package/dist/cli/subcommands/subcommand.d.ts +113 -0
- package/dist/cli/subcommands/subcommand.d.ts.map +1 -0
- package/dist/cli/subcommands/subcommand.js +3 -0
- package/dist/cli/subcommands/subcommand.js.map +1 -0
- package/dist/cli/usage.d.ts +3 -0
- package/dist/cli/usage.d.ts.map +1 -0
- package/dist/cli/usage.js +95 -0
- package/dist/cli/usage.js.map +1 -0
- package/dist/detect.d.ts.map +1 -1
- package/dist/detect.js.map +1 -1
- package/dist/errors.d.ts +21 -1
- package/dist/errors.d.ts.map +1 -1
- package/dist/errors.js +33 -1
- package/dist/errors.js.map +1 -1
- package/dist/harness/aider.d.ts +10 -0
- package/dist/harness/aider.d.ts.map +1 -0
- package/dist/harness/aider.js +21 -0
- package/dist/harness/aider.js.map +1 -0
- package/dist/harness/claude-code.d.ts +3 -0
- package/dist/harness/claude-code.d.ts.map +1 -0
- package/dist/harness/claude-code.js +68 -0
- package/dist/harness/claude-code.js.map +1 -0
- package/dist/harness/cline.d.ts +3 -0
- package/dist/harness/cline.d.ts.map +1 -0
- package/dist/harness/cline.js +54 -0
- package/dist/harness/cline.js.map +1 -0
- package/dist/harness/codex.d.ts +3 -0
- package/dist/harness/codex.d.ts.map +1 -0
- package/dist/harness/codex.js +92 -0
- package/dist/harness/codex.js.map +1 -0
- package/dist/harness/cursor.d.ts +3 -0
- package/dist/harness/cursor.d.ts.map +1 -0
- package/dist/harness/cursor.js +54 -0
- package/dist/harness/cursor.js.map +1 -0
- package/dist/harness/gemini.d.ts +3 -0
- package/dist/harness/gemini.d.ts.map +1 -0
- package/dist/harness/gemini.js +60 -0
- package/dist/harness/gemini.js.map +1 -0
- package/dist/harness/grok.d.ts +3 -0
- package/dist/harness/grok.d.ts.map +1 -0
- package/dist/harness/grok.js +47 -0
- package/dist/harness/grok.js.map +1 -0
- package/dist/harness/hermes.d.ts +3 -0
- package/dist/harness/hermes.d.ts.map +1 -0
- package/dist/harness/hermes.js +72 -0
- package/dist/harness/hermes.js.map +1 -0
- package/dist/harness/kilocode.d.ts +3 -0
- package/dist/harness/kilocode.d.ts.map +1 -0
- package/dist/harness/kilocode.js +35 -0
- package/dist/harness/kilocode.js.map +1 -0
- package/dist/harness/opencode.d.ts +3 -0
- package/dist/harness/opencode.d.ts.map +1 -0
- package/dist/harness/opencode.js +97 -0
- package/dist/harness/opencode.js.map +1 -0
- package/dist/harness/paths.d.ts +17 -0
- package/dist/harness/paths.d.ts.map +1 -0
- package/dist/harness/paths.js +45 -0
- package/dist/harness/paths.js.map +1 -0
- package/dist/harness/profile.d.ts +209 -0
- package/dist/harness/profile.d.ts.map +1 -0
- package/dist/harness/profile.js +41 -0
- package/dist/harness/profile.js.map +1 -0
- package/dist/harness/registry.d.ts +100 -0
- package/dist/harness/registry.d.ts.map +1 -0
- package/dist/harness/registry.js +144 -0
- package/dist/harness/registry.js.map +1 -0
- package/dist/harness/snippet.d.ts +19 -0
- package/dist/harness/snippet.d.ts.map +1 -0
- package/dist/harness/snippet.js +41 -0
- package/dist/harness/snippet.js.map +1 -0
- package/dist/hash.d.ts.map +1 -1
- package/dist/hash.js.map +1 -1
- package/dist/hooks/guard-core.d.ts +14 -14
- package/dist/hooks/guard-core.d.ts.map +1 -1
- package/dist/hooks/guard-core.js +15 -37
- package/dist/hooks/guard-core.js.map +1 -1
- package/dist/hooks/shim.d.ts +95 -4
- package/dist/hooks/shim.d.ts.map +1 -1
- package/dist/hooks/shim.js +87 -2
- package/dist/hooks/shim.js.map +1 -1
- package/dist/hooks/shims/claude-code.d.ts +5 -18
- package/dist/hooks/shims/claude-code.d.ts.map +1 -1
- package/dist/hooks/shims/claude-code.js +9 -56
- package/dist/hooks/shims/claude-code.js.map +1 -1
- package/dist/hooks/shims/cline.d.ts +5 -12
- package/dist/hooks/shims/cline.d.ts.map +1 -1
- package/dist/hooks/shims/cline.js +9 -34
- package/dist/hooks/shims/cline.js.map +1 -1
- package/dist/hooks/shims/codex.d.ts +5 -18
- package/dist/hooks/shims/codex.d.ts.map +1 -1
- package/dist/hooks/shims/codex.js +9 -51
- package/dist/hooks/shims/codex.js.map +1 -1
- package/dist/hooks/shims/cursor.d.ts +5 -14
- package/dist/hooks/shims/cursor.d.ts.map +1 -1
- package/dist/hooks/shims/cursor.js +9 -42
- package/dist/hooks/shims/cursor.js.map +1 -1
- package/dist/hooks/shims/gemini.d.ts +5 -18
- package/dist/hooks/shims/gemini.d.ts.map +1 -1
- package/dist/hooks/shims/gemini.js +9 -48
- package/dist/hooks/shims/gemini.js.map +1 -1
- package/dist/hooks/shims/grok.d.ts +5 -13
- package/dist/hooks/shims/grok.d.ts.map +1 -1
- package/dist/hooks/shims/grok.js +9 -32
- package/dist/hooks/shims/grok.js.map +1 -1
- package/dist/hooks/shims/hermes.d.ts +5 -17
- package/dist/hooks/shims/hermes.d.ts.map +1 -1
- package/dist/hooks/shims/hermes.js +9 -45
- package/dist/hooks/shims/hermes.js.map +1 -1
- package/dist/index.d.ts +43 -76
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +21 -67
- package/dist/index.js.map +1 -1
- package/dist/lang/bash.d.ts.map +1 -1
- package/dist/lang/bash.js.map +1 -1
- package/dist/lang/c.d.ts.map +1 -1
- package/dist/lang/c.js.map +1 -1
- package/dist/lang/c_sharp.d.ts.map +1 -1
- package/dist/lang/c_sharp.js.map +1 -1
- package/dist/lang/cpp.d.ts.map +1 -1
- package/dist/lang/cpp.js.map +1 -1
- package/dist/lang/go.d.ts.map +1 -1
- package/dist/lang/go.js.map +1 -1
- package/dist/lang/java.d.ts.map +1 -1
- package/dist/lang/java.js.map +1 -1
- package/dist/lang/javascript.d.ts.map +1 -1
- package/dist/lang/javascript.js.map +1 -1
- package/dist/lang/kotlin.d.ts.map +1 -1
- package/dist/lang/kotlin.js.map +1 -1
- package/dist/lang/php.d.ts.map +1 -1
- package/dist/lang/php.js.map +1 -1
- package/dist/lang/profile.d.ts.map +1 -1
- package/dist/lang/profile.js.map +1 -1
- package/dist/lang/python.d.ts.map +1 -1
- package/dist/lang/python.js.map +1 -1
- package/dist/lang/registry.d.ts.map +1 -1
- package/dist/lang/registry.js.map +1 -1
- package/dist/lang/ruby.d.ts.map +1 -1
- package/dist/lang/ruby.js.map +1 -1
- package/dist/lang/rust.d.ts.map +1 -1
- package/dist/lang/rust.js.map +1 -1
- package/dist/lang/swift.d.ts.map +1 -1
- package/dist/lang/swift.js.map +1 -1
- package/dist/lang/tsx.d.ts.map +1 -1
- package/dist/lang/tsx.js.map +1 -1
- package/dist/lang/typescript.d.ts.map +1 -1
- package/dist/lang/typescript.js.map +1 -1
- package/dist/net/policy.d.ts +18 -1
- package/dist/net/policy.d.ts.map +1 -1
- package/dist/net/policy.js +6 -4
- package/dist/net/policy.js.map +1 -1
- package/dist/ops/index.d.ts +39 -0
- package/dist/ops/index.d.ts.map +1 -0
- package/dist/ops/index.js +37 -0
- package/dist/ops/index.js.map +1 -0
- package/dist/ops/inputs.d.ts +170 -0
- package/dist/ops/inputs.d.ts.map +1 -0
- package/dist/ops/inputs.js +142 -0
- package/dist/ops/inputs.js.map +1 -0
- package/dist/ops/verbs.d.ts +136 -0
- package/dist/ops/verbs.d.ts.map +1 -0
- package/dist/ops/verbs.js +76 -0
- package/dist/ops/verbs.js.map +1 -0
- package/dist/plan/auto.d.ts +69 -0
- package/dist/plan/auto.d.ts.map +1 -0
- package/dist/plan/auto.js +70 -0
- package/dist/plan/auto.js.map +1 -0
- package/dist/plan/budget.d.ts +21 -0
- package/dist/plan/budget.d.ts.map +1 -0
- package/dist/plan/budget.js +26 -0
- package/dist/plan/budget.js.map +1 -0
- package/dist/plan/grammar.d.ts +14 -0
- package/dist/plan/grammar.d.ts.map +1 -1
- package/dist/plan/grammar.js +47 -6
- package/dist/plan/grammar.js.map +1 -1
- package/dist/plan/lexical.d.ts.map +1 -1
- package/dist/plan/lexical.js +1 -7
- package/dist/plan/lexical.js.map +1 -1
- package/dist/plan/planners.d.ts +35 -2
- package/dist/plan/planners.d.ts.map +1 -1
- package/dist/plan/planners.js +35 -2
- package/dist/plan/planners.js.map +1 -1
- package/dist/plan/structural.d.ts +19 -5
- package/dist/plan/structural.d.ts.map +1 -1
- package/dist/plan/structural.js +180 -33
- package/dist/plan/structural.js.map +1 -1
- package/dist/repomap/cache.d.ts +48 -0
- package/dist/repomap/cache.d.ts.map +1 -1
- package/dist/repomap/cache.js +112 -13
- package/dist/repomap/cache.js.map +1 -1
- package/dist/repomap/io.d.ts +24 -0
- package/dist/repomap/io.d.ts.map +1 -0
- package/dist/repomap/io.js +34 -0
- package/dist/repomap/io.js.map +1 -0
- package/dist/repomap/map.d.ts +69 -6
- package/dist/repomap/map.d.ts.map +1 -1
- package/dist/repomap/map.js +104 -22
- package/dist/repomap/map.js.map +1 -1
- package/dist/repomap/rank.d.ts +26 -2
- package/dist/repomap/rank.d.ts.map +1 -1
- package/dist/repomap/rank.js +20 -0
- package/dist/repomap/rank.js.map +1 -1
- package/dist/repomap/reader.d.ts +73 -0
- package/dist/repomap/reader.d.ts.map +1 -0
- package/dist/repomap/reader.js +30 -0
- package/dist/repomap/reader.js.map +1 -0
- package/dist/repomap/tags.d.ts.map +1 -1
- package/dist/repomap/tags.js.map +1 -1
- package/dist/retrieve.d.ts +8 -0
- package/dist/retrieve.d.ts.map +1 -1
- package/dist/retrieve.js +12 -1
- package/dist/retrieve.js.map +1 -1
- package/dist/smelter.d.ts +79 -0
- package/dist/smelter.d.ts.map +1 -0
- package/dist/smelter.js +65 -0
- package/dist/smelter.js.map +1 -0
- package/dist/stages.d.ts.map +1 -1
- package/dist/stages.js +2 -2
- package/dist/stages.js.map +1 -1
- package/dist/stats.d.ts +2 -1
- package/dist/stats.d.ts.map +1 -1
- package/dist/stats.js +2 -1
- package/dist/stats.js.map +1 -1
- package/dist/store-dir.d.ts +43 -4
- package/dist/store-dir.d.ts.map +1 -1
- package/dist/store-dir.js +48 -5
- package/dist/store-dir.js.map +1 -1
- package/dist/store.d.ts +6 -0
- package/dist/store.d.ts.map +1 -1
- package/dist/store.js +6 -0
- package/dist/store.js.map +1 -1
- package/dist/text/json-edit.d.ts +71 -0
- package/dist/text/json-edit.d.ts.map +1 -0
- package/dist/text/json-edit.js +219 -0
- package/dist/text/json-edit.js.map +1 -0
- package/dist/types.d.ts +35 -14
- package/dist/types.d.ts.map +1 -1
- package/dist/types.js.map +1 -1
- package/grammars/tree-sitter-bash.wasm +0 -0
- package/grammars/tree-sitter-c.wasm +0 -0
- package/grammars/tree-sitter-c_sharp.wasm +0 -0
- package/grammars/tree-sitter-cpp.wasm +0 -0
- package/grammars/tree-sitter-go.wasm +0 -0
- package/grammars/tree-sitter-java.wasm +0 -0
- package/grammars/tree-sitter-javascript.wasm +0 -0
- package/grammars/tree-sitter-kotlin.wasm +0 -0
- package/grammars/tree-sitter-php.wasm +0 -0
- package/grammars/tree-sitter-python.wasm +0 -0
- package/grammars/tree-sitter-ruby.wasm +0 -0
- package/grammars/tree-sitter-rust.wasm +0 -0
- package/grammars/tree-sitter-swift.wasm +0 -0
- package/grammars/tree-sitter-tsx.wasm +0 -0
- package/grammars/tree-sitter-typescript.wasm +0 -0
- package/package.json +11 -11
- package/dist/cli/resolve.d.ts +0 -103
- package/dist/cli/resolve.d.ts.map +0 -1
- package/dist/cli/resolve.js +0 -106
- 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 './
|
|
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
|
-
|
|
41
|
-
|
|
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
|
|
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.
|
|
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
|
-
|
|
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:
|
|
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,
|
|
92
|
-
if (outcome
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
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
|
-
|
|
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,
|
|
134
|
+
const verdict = await confirmAndWrite(io, ask, choices, dir);
|
|
103
135
|
if (verdict !== 'back')
|
|
104
|
-
return
|
|
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 ??
|
|
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
|
-
`
|
|
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
|
|
213
|
-
const answer = await ask(`strategy (
|
|
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
|
-
|
|
218
|
-
|
|
341
|
+
const index = picks.indexOf(pick);
|
|
342
|
+
if (index >= 0) {
|
|
343
|
+
choices.strategy = STRATEGIES[index];
|
|
219
344
|
return 'ok';
|
|
220
345
|
}
|
|
221
|
-
io.output(
|
|
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
|
-
/**
|
|
338
|
-
|
|
339
|
-
|
|
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
|
package/dist/cli/init.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"init.js","sourceRoot":"","sources":["../../src/cli/init.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,YAAY,EAAE,aAAa,EAAE,MAAM,SAAS,CAAC;AAClE,OAAO,EAAE,OAAO,EAAE,IAAI,EAAE,MAAM,WAAW,CAAC;AAC1C,OAAO,EAAE,eAAe,EAAE,MAAM,wBAAwB,CAAC;AAEzD,OAAO,EAAE,aAAa,EAAE,MAAM,cAAc,CAAC;AAC7C,OAAO,EAAE,oBAAoB,EAAE,MAAM,uBAAuB,CAAC;AAE7D,OAAO,EAAE,QAAQ,EAAE,MAAM,WAAW,CAAC;AACrC,OAAO,EAAE,gBAAgB,EAAE,cAAc,EAAE,cAAc,EAAE,WAAW,EAAE,MAAM,aAAa,CAAC;AAG5F;;;;;;;;;;;;;;;;;;;GAmBG;AAEH,mDAAmD;AACnD,MAAM,CAAC,MAAM,iBAAiB,GAAG,kBAAkB,CAAC;AAEpD,+CAA+C;AAC/C,MAAM,CAAC,MAAM,gBAAgB,GAAG,iBAAiB,CAAC;AA2ClD;;;;;;GAMG;AACH,MAAM,CAAC,KAAK,UAAU,OAAO,CAAC,EAAU;IACtC,MAAM,EAAE,GAAG,eAAe,CAAC,EAAE,KAAK,EAAE,EAAE,CAAC,KAAK,EAAE,CAAC,CAAC;IAChD,MAAM,KAAK,GAAG,EAAE,CAAC,MAAM,CAAC,aAAa,CAAC,EAAE,CAAC;IACzC,MAAM,GAAG,GAAG,KAAK,EAAE,MAAc,EAAmB,EAAE;QACpD,EAAE,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC;QAClB,MAAM,IAAI,GAAG,MAAM,KAAK,CAAC,IAAI,EAAE,CAAC;QAChC,IAAI,IAAI,CAAC,IAAI,KAAK,IAAI,EAAE,CAAC;YACvB,MAAM,IAAI,aAAa,CACrB,GAAG,QAAQ,iDAAiD;gBAC1D,wEAAwE,CAC3E,CAAC;QACJ,CAAC;QACD,OAAO,IAAI,CAAC,KAAK,CAAC,IAAI,EAAE,CAAC;IAC3B,CAAC,CAAC;IAEF,IAAI,CAAC;QACH,MAAM,QAAQ,GAAG,YAAY,CAAC,EAAE,CAAC,GAAG,CAAC,CAAC;QACtC,OAAO,QAAQ,KAAK,SAAS;YAC3B,CAAC,CAAC,MAAM,QAAQ,CAAC,EAAE,EAAE,GAAG,CAAC;YACzB,CAAC,CAAC,MAAM,OAAO,CAAC,EAAE,EAAE,GAAG,EAAE,QAAQ,CAAC,IAAI,EAAE,QAAQ,CAAC,MAAM,CAAC,CAAC;IAC7D,CAAC;YAAS,CAAC;QACT,EAAE,CAAC,KAAK,EAAE,CAAC;IACb,CAAC;AACH,CAAC;AAED,SAAS,YAAY,CAAC,GAAW;IAC/B,MAAM,IAAI,GAAG,cAAc,CAAC,GAAG,CAAC,CAAC;IACjC,IAAI,IAAI,KAAK,SAAS;QAAE,OAAO,SAAS,CAAC;IACzC,kFAAkF;IAClF,gFAAgF;IAChF,OAAO,EAAE,IAAI,EAAE,MAAM,EAAE,WAAW,CAAC,YAAY,CAAC,IAAI,EAAE,MAAM,CAAC,EAAE,IAAI,CAAC,EAAE,CAAC;AACzE,CAAC;AAaD,MAAM,KAAK,GAAoB;IAC7B,EAAE,EAAE,EAAE,QAAQ,EAAE,GAAG,EAAE,UAAU,EAAE;IACjC,EAAE,EAAE,EAAE,OAAO,EAAE,GAAG,EAAE,SAAS,EAAE;IAC/B,EAAE,EAAE,EAAE,UAAU,EAAE,GAAG,EAAE,YAAY,EAAE;IACrC,EAAE,EAAE,EAAE,SAAS,EAAE,GAAG,EAAE,WAAW,EAAE;IACnC,EAAE,EAAE,EAAE,QAAQ,EAAE,GAAG,EAAE,UAAU,EAAE;CAClC,CAAC;AAEF,KAAK,UAAU,QAAQ,CAAC,EAAU,EAAE,GAAU;IAC5C,EAAE,CAAC,MAAM,CACP,GAAG,QAAQ,mBAAmB,gBAAgB,OAAO,EAAE,CAAC,GAAG,KAAK;QAC9D,6DAA6D;QAC7D,sDAAsD,CACzD,CAAC;IACF,MAAM,OAAO,GAAkB;QAC7B,WAAW,EAAE,SAAS;QACtB,KAAK,EAAE,EAAE,IAAI,EAAE,QAAQ,EAAE;QACzB,QAAQ,EAAE,SAAS;QACnB,WAAW,EAAE,KAAK;QAClB,UAAU,EAAE,KAAK;QACjB,KAAK,EAAE,SAAS;KACjB,CAAC;IAEF,IAAI,KAAK,GAAG,CAAC,CAAC;IACd,SAAS,CAAC;QACR,OAAO,KAAK,GAAG,KAAK,CAAC,MAAM,EAAE,CAAC;YAC5B,MAAM,OAAO,GAAG,MAAM,KAAK,CAAC,KAAK,CAAE,CAAC,GAAG,CAAC,EAAE,EAAE,GAAG,EAAE,OAAO,EAAE,EAAE,CAAC,GAAG,CAAC,CAAC;YAClE,IAAI,OAAO,KAAK,MAAM,EAAE,CAAC;gBACvB,IAAI,KAAK,KAAK,CAAC;oBAAE,EAAE,CAAC,MAAM,CAAC,wDAAwD,CAAC,CAAC;;oBAChF,KAAK,IAAI,CAAC,CAAC;YAClB,CAAC;iBAAM,CAAC;gBACN,KAAK,IAAI,CAAC,CAAC;YACb,CAAC;QACH,CAAC;QACD,MAAM,OAAO,GAAG,MAAM,eAAe,CAAC,EAAE,EAAE,GAAG,EAAE,OAAO,EAAE,EAAE,CAAC,GAAG,CAAC,CAAC;QAChE,IAAI,OAAO,KAAK,MAAM;YAAE,OAAO,CAAC,CAAC;QACjC,KAAK,GAAG,KAAK,CAAC,MAAM,GAAG,CAAC,CAAC;IAC3B,CAAC;AACH,CAAC;AAED,KAAK,UAAU,OAAO,CACpB,EAAU,EACV,GAAU,EACV,UAAkB,EAClB,MAAmB;IAEnB,MAAM,GAAG,GAAG,OAAO,CAAC,UAAU,CAAC,CAAC;IAChC,MAAM,OAAO,GAAkB;QAC7B,WAAW,EAAE,MAAM,CAAC,kBAAkB;QACtC,KAAK,EAAE,MAAM,CAAC,KAAK,IAAI,EAAE,IAAI,EAAE,QAAQ,EAAE;QACzC,QAAQ,EAAE,MAAM,CAAC,QAAQ,IAAI,SAAS;QACtC,WAAW,EAAE,KAAK;QAClB,UAAU,EAAE,KAAK;QACjB,KAAK,EAAE,MAAM,CAAC,KAAK;KACpB,CAAC;IAEF,EAAE,CAAC,MAAM,CACP,GAAG,QAAQ,WAAW,gBAAgB,sBAAsB,UAAU,KAAK;QACzE,uEAAuE,CAC1E,CAAC;IAEF,SAAS,CAAC;QACR,EAAE,CAAC,MAAM,CAAC,sBAAsB,OAAO,CAAC,OAAO,EAAE,GAAG,CAAC,IAAI,CAAC,CAAC;QAC3D,MAAM,MAAM,GAAG,MAAM,GAAG,CACtB,uEAAuE;YACrE,wEAAwE,CAC3E,CAAC;QACF,IAAI,MAAM,KAAK,MAAM,EAAE,CAAC;YACtB,EAAE,CAAC,MAAM,CAAC,6CAA6C,CAAC,CAAC;YACzD,OAAO,CAAC,CAAC;QACX,CAAC;QACD,IAAI,MAAM,KAAK,MAAM,EAAE,CAAC;YACtB,MAAM,OAAO,GAAG,MAAM,eAAe,CAAC,EAAE,EAAE,GAAG,EAAE,OAAO,EAAE,GAAG,CAAC,CAAC;YAC7D,IAAI,OAAO,KAAK,MAAM;gBAAE,OAAO,CAAC,CAAC;YACjC,SAAS,CAAC,yCAAyC;QACrD,CAAC;QACD,MAAM,IAAI,GAAG,KAAK,CAAC,IAAI,CAAC,CAAC,SAAS,EAAE,EAAE,CAAC,SAAS,CAAC,EAAE,KAAK,MAAM,CAAC,CAAC;QAChE,IAAI,IAAI,KAAK,SAAS,EAAE,CAAC;YACvB,EAAE,CAAC,MAAM,CAAC,mBAAmB,MAAM,wDAAwD,CAAC,CAAC;YAC7F,SAAS;QACX,CAAC;QACD,MAAM,IAAI,CAAC,GAAG,CAAC,EAAE,EAAE,GAAG,EAAE,OAAO,EAAE,GAAG,CAAC,CAAC,CAAC,8BAA8B;IACvE,CAAC;AACH,CAAC;AAED,SAAS,OAAO,CAAC,OAAsB,EAAE,GAAW;IAClD,MAAM,QAAQ,GAAG,CAAC,IAAY,EAAE,QAAiB,EAAU,EAAE;QAC3D,IAAI,QAAQ;YAAE,OAAO,YAAY,IAAI,EAAE,CAAC;QACxC,OAAO,UAAU,CAAC,IAAI,CAAC,GAAG,EAAE,IAAI,CAAC,CAAC,CAAC,CAAC,CAAC,GAAG,IAAI,sBAAsB,CAAC,CAAC,CAAC,MAAM,CAAC;IAC9E,CAAC,CAAC;IACF,OAAO;QACL,gBAAgB,OAAO,CAAC,WAAW,KAAK,SAAS,CAAC,CAAC,CAAC,WAAW,CAAC,CAAC,CAAC,GAAG,MAAM,CAAC,OAAO,CAAC,WAAW,CAAC,QAAQ,EAAE;QAC1G,gBAAgB,OAAO,CAAC,KAAK,CAAC,IAAI,KAAK,QAAQ,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,CAAC,cAAc,OAAO,CAAC,KAAK,CAAC,IAAI,GAAG,EAAE;QAClG,gBAAgB,OAAO,CAAC,QAAQ,EAAE;QAClC,gBAAgB,QAAQ,CAAC,iBAAiB,EAAE,OAAO,CAAC,WAAW,CAAC,EAAE;QAClE,gBAAgB,QAAQ,CAAC,gBAAgB,EAAE,OAAO,CAAC,UAAU,CAAC,EAAE;KACjE,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;AACf,CAAC;AAED,8EAA8E;AAC9E,sCAAsC;AACtC,8EAA8E;AAE9E,KAAK,UAAU,UAAU,CAAC,EAAU,EAAE,GAAU,EAAE,OAAsB;IACtE,EAAE,CAAC,MAAM,CACP,yCAAyC,QAAQ,0BAA0B;QACzE,2EAA2E;QAC3E,8EAA8E;QAC9E,sDAAsD,CACzD,CAAC;IACF,SAAS,CAAC;QACR,MAAM,OAAO,GAAG,OAAO,CAAC,WAAW,KAAK,SAAS,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,KAAK,MAAM,CAAC,OAAO,CAAC,WAAW,CAAC,GAAG,CAAC;QAC7F,MAAM,MAAM,GAAG,MAAM,GAAG,CAAC,kBAAkB,OAAO,cAAc,CAAC,CAAC;QAClE,IAAI,MAAM,KAAK,MAAM;YAAE,OAAO,MAAM,CAAC;QACrC,IAAI,MAAM,KAAK,EAAE,IAAI,OAAO,CAAC,WAAW,KAAK,SAAS;YAAE,OAAO,IAAI,CAAC;QACpE,IAAI,OAAO,CAAC,IAAI,CAAC,MAAM,CAAC,IAAI,MAAM,CAAC,MAAM,CAAC,GAAG,CAAC,EAAE,CAAC;YAC/C,OAAO,CAAC,WAAW,GAAG,MAAM,CAAC,MAAM,CAAC,CAAC;YACrC,OAAO,IAAI,CAAC;QACd,CAAC;QACD,EAAE,CAAC,MAAM,CAAC,yDAAyD,CAAC,CAAC;IACvE,CAAC;AACH,CAAC;AAED,KAAK,UAAU,SAAS,CAAC,EAAU,EAAE,GAAU,EAAE,OAAsB;IACrE,EAAE,CAAC,MAAM,CACP,kFAAkF;QAChF,sBAAsB;QACtB,wEAAwE;QACxE,+EAA+E;QAC/E,oBAAoB,CACvB,CAAC;IACF,SAAS,CAAC;QACR,MAAM,OAAO,GAAG,OAAO,CAAC,KAAK,CAAC,IAAI,KAAK,QAAQ,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,GAAG,CAAC;QAC5D,MAAM,MAAM,GAAG,MAAM,GAAG,CAAC,gBAAgB,OAAO,eAAe,CAAC,CAAC;QACjE,IAAI,MAAM,KAAK,MAAM;YAAE,OAAO,MAAM,CAAC;QACrC,MAAM,IAAI,GAAG,MAAM,KAAK,EAAE,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC;QAC9C,IAAI,IAAI,KAAK,GAAG,EAAE,CAAC;YACjB,OAAO,CAAC,KAAK,GAAG,EAAE,IAAI,EAAE,QAAQ,EAAE,CAAC;YACnC,OAAO,IAAI,CAAC;QACd,CAAC;QACD,IAAI,IAAI,KAAK,GAAG,EAAE,CAAC;YACjB,MAAM,QAAQ,GAAG,OAAO,CAAC,KAAK,CAAC,IAAI,KAAK,WAAW,CAAC,CAAC,CAAC,OAAO,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC,CAAC,cAAc,CAAC;YAC1F,MAAM,IAAI,GAAG,MAAM,GAAG,CAAC,gCAAgC,gBAAgB,KAAK,QAAQ,KAAK,CAAC,CAAC;YAC3F,IAAI,IAAI,KAAK,MAAM;gBAAE,SAAS,CAAC,gDAAgD;YAC/E,OAAO,CAAC,KAAK,GAAG,EAAE,IAAI,EAAE,WAAW,EAAE,IAAI,EAAE,IAAI,KAAK,EAAE,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,CAAC,IAAI,EAAE,CAAC;YAC3E,OAAO,IAAI,CAAC;QACd,CAAC;QACD,EAAE,CAAC,MAAM,CAAC,2CAA2C,CAAC,CAAC;IACzD,CAAC;AACH,CAAC;AAED,KAAK,UAAU,YAAY,CAAC,EAAU,EAAE,GAAU,EAAE,OAAsB;IACxE,EAAE,CAAC,MAAM,CACP,kEAAkE;QAChE,8EAA8E;QAC9E,6BAA6B,MAAM,CAAC,oBAAoB,CAAC,MAAM,CAAC,kBAAkB;QAClF,qBAAqB,oBAAoB,CAAC,IAAI,CAAC,IAAI,CAAC,QAAQ;QAC5D,iFAAiF,CACpF,CAAC;IACF,SAAS,CAAC;QACR,MAAM,OAAO,GAAG,OAAO,CAAC,QAAQ,KAAK,SAAS,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,GAAG,CAAC;QAC3D,MAAM,MAAM,GAAG,MAAM,GAAG,CAAC,mBAAmB,OAAO,eAAe,CAAC,CAAC;QACpE,IAAI,MAAM,KAAK,MAAM;YAAE,OAAO,MAAM,CAAC;QACrC,MAAM,IAAI,GAAG,MAAM,KAAK,EAAE,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC;QAC9C,IAAI,IAAI,KAAK,GAAG,IAAI,IAAI,KAAK,GAAG,EAAE,CAAC;YACjC,OAAO,CAAC,QAAQ,GAAG,IAAI,KAAK,GAAG,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,YAAY,CAAC;YAC3D,OAAO,IAAI,CAAC;QACd,CAAC;QACD,EAAE,CAAC,MAAM,CAAC,6CAA6C,CAAC,CAAC;IAC3D,CAAC;AACH,CAAC;AAED,KAAK,UAAU,WAAW,CACxB,EAAU,EACV,GAAU,EACV,OAAsB,EACtB,GAAW;IAEX,MAAM,MAAM,GAAG,UAAU,CAAC,IAAI,CAAC,GAAG,EAAE,iBAAiB,CAAC,CAAC,CAAC;IACxD,EAAE,CAAC,MAAM,CACP,+EAA+E;QAC7E,6EAA6E;QAC7E,2DAA2D;QAC3D,aAAa;QACb,iBAAiB,iBAAiB,8BAA8B;QAChE,CAAC,MAAM,CAAC,CAAC,CAAC,IAAI,iBAAiB,oDAAoD,CAAC,CAAC,CAAC,EAAE,CAAC,CAC5F,CAAC;IACF,SAAS,CAAC;QACR,MAAM,MAAM,GAAG,MAAM,GAAG,CAAC,kBAAkB,OAAO,CAAC,WAAW,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,GAAG,eAAe,CAAC,CAAC;QAC3F,IAAI,MAAM,KAAK,MAAM;YAAE,OAAO,MAAM,CAAC;QACrC,MAAM,IAAI,GAAG,MAAM,KAAK,EAAE,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC,WAAW,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC;QACxE,IAAI,IAAI,KAAK,GAAG,IAAI,IAAI,KAAK,GAAG,EAAE,CAAC;YACjC,OAAO,CAAC,WAAW,GAAG,IAAI,KAAK,GAAG,CAAC;YACnC,OAAO,IAAI,CAAC;QACd,CAAC;QACD,EAAE,CAAC,MAAM,CAAC,gDAAgD,CAAC,CAAC;IAC9D,CAAC;AACH,CAAC;AAED,KAAK,UAAU,UAAU,CACvB,EAAU,EACV,GAAU,EACV,OAAsB,EACtB,GAAW;IAEX,MAAM,MAAM,GAAG,UAAU,CAAC,IAAI,CAAC,GAAG,EAAE,gBAAgB,CAAC,CAAC,CAAC;IACvD,EAAE,CAAC,MAAM,CACP,kFAAkF;QAChF,+EAA+E;QAC/E,mBAAmB;QACnB,aAAa;QACb,iBAAiB,gBAAgB,wDAAwD;QACzF,CAAC,MAAM,CAAC,CAAC,CAAC,IAAI,gBAAgB,oDAAoD,CAAC,CAAC,CAAC,EAAE,CAAC,CAC3F,CAAC;IACF,SAAS,CAAC;QACR,MAAM,MAAM,GAAG,MAAM,GAAG,CAAC,iBAAiB,OAAO,CAAC,UAAU,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,GAAG,eAAe,CAAC,CAAC;QACzF,IAAI,MAAM,KAAK,MAAM;YAAE,OAAO,MAAM,CAAC;QACrC,MAAM,IAAI,GAAG,MAAM,KAAK,EAAE,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC,UAAU,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC;QACvE,IAAI,IAAI,KAAK,GAAG,IAAI,IAAI,KAAK,GAAG,EAAE,CAAC;YACjC,OAAO,CAAC,UAAU,GAAG,IAAI,KAAK,GAAG,CAAC;YAClC,OAAO,IAAI,CAAC;QACd,CAAC;QACD,EAAE,CAAC,MAAM,CAAC,gDAAgD,CAAC,CAAC;IAC9D,CAAC;AACH,CAAC;AAED,8EAA8E;AAC9E,uDAAuD;AACvD,8EAA8E;AAE9E,MAAM,UAAU,GAAG,CAAC,KAAmB,EAAU,EAAE;IACjD,IAAI,KAAK,CAAC,SAAS;QAAE,OAAO,8BAA8B,CAAC;IAC3D,OAAO,KAAK,CAAC,MAAM,CAAC,CAAC,CAAC,sCAAsC,CAAC,CAAC,CAAC,KAAK,CAAC;AACvE,CAAC,CAAC;AAEF,KAAK,UAAU,eAAe,CAC5B,EAAU,EACV,GAAU,EACV,OAAsB,EACtB,GAAW;IAEX,IAAI,OAAO,CAAC,WAAW,KAAK,SAAS,EAAE,CAAC;QACtC,kFAAkF;QAClF,kFAAkF;QAClF,8EAA8E;QAC9E,iFAAiF;QACjF,gFAAgF;QAChF,EAAE,CAAC,MAAM,CAAC,qDAAqD,CAAC,CAAC;QACjE,IAAI,CAAC,MAAM,UAAU,CAAC,EAAE,EAAE,GAAG,EAAE,OAAO,CAAC,CAAC,KAAK,MAAM;YAAE,OAAO,MAAM,CAAC;IACrE,CAAC;IAED,MAAM,MAAM,GAAG,aAAa,CAAC,OAAO,EAAE,GAAG,CAAC,CAAC;IAC3C,EAAE,CAAC,MAAM,CACP,0BAA0B,GAAG,KAAK;QAChC,MAAM,CAAC,GAAG,CAAC,CAAC,KAAK,EAAE,EAAE,CAAC,KAAK,KAAK,CAAC,IAAI,CAAC,MAAM,CAAC,EAAE,CAAC,KAAK,UAAU,CAAC,KAAK,CAAC,KAAK,CAAC,CAAC,IAAI,CAAC,EAAE,CAAC;QACrF,iCAAiC,CACpC,CAAC;IAEF,SAAS,CAAC;QACR,MAAM,MAAM,GAAG,MAAM,GAAG,CAAC,6BAA6B,CAAC,CAAC;QACxD,IAAI,MAAM,KAAK,MAAM;YAAE,OAAO,MAAM,CAAC;QACrC,IAAI,MAAM,KAAK,IAAI,EAAE,CAAC;YACpB,EAAE,CAAC,MAAM,CAAC,wBAAwB,CAAC,CAAC;YACpC,OAAO,MAAM,CAAC;QAChB,CAAC;QACD,IAAI,MAAM,KAAK,KAAK;YAAE,MAAM;QAC5B,EAAE,CAAC,MAAM,CAAC,6EAA6E,CAAC,CAAC;IAC3F,CAAC;IAED,KAAK,MAAM,KAAK,IAAI,MAAM,EAAE,CAAC;QAC3B,IAAI,KAAK,CAAC,SAAS,EAAE,CAAC;YACpB,EAAE,CAAC,MAAM,CAAC,KAAK,KAAK,CAAC,IAAI,+BAA+B,CAAC,CAAC;YAC1D,SAAS;QACX,CAAC;QACD,IAAI,KAAK,CAAC,MAAM,EAAE,CAAC;YACjB,+EAA+E;YAC/E,4DAA4D;YAC5D,yEAAyE;YACzE,MAAM,MAAM,GAAG,MAAM,GAAG,CAAC,KAAK,KAAK,CAAC,IAAI,oCAAoC,CAAC,CAAC;YAC9E,IAAI,MAAM,KAAK,KAAK,EAAE,CAAC;gBACrB,EAAE,CAAC,MAAM,CAAC,aAAa,KAAK,CAAC,IAAI,wCAAwC,CAAC,CAAC;gBAC3E,SAAS;YACX,CAAC;QACH,CAAC;QACD,aAAa,CAAC,KAAK,CAAC,IAAI,EAAE,KAAK,CAAC,OAAO,CAAC,CAAC;QACzC,EAAE,CAAC,MAAM,CAAC,WAAW,KAAK,CAAC,IAAI,IAAI,CAAC,CAAC;IACvC,CAAC;IACD,EAAE,CAAC,MAAM,CAAC,SAAS,CAAC,CAAC;IACrB,EAAE,CAAC,MAAM,CACP,WAAW,QAAQ,4DAA4D;QAC7E,iFAAiF;QACjF,4BAA4B,CAC/B,CAAC;IACF,OAAO,MAAM,CAAC;AAChB,CAAC;AAED,SAAS,aAAa,CAAC,OAAsB,EAAE,GAAW;IACxD,MAAM,IAAI,GAAG,CAAC,IAAY,EAAE,OAAe,EAAgB,EAAE;QAC3D,MAAM,IAAI,GAAG,IAAI,CAAC,GAAG,EAAE,IAAI,CAAC,CAAC;QAC7B,MAAM,MAAM,GAAG,UAAU,CAAC,IAAI,CAAC,CAAC;QAChC,MAAM,SAAS,GAAG,MAAM,IAAI,YAAY,CAAC,IAAI,EAAE,MAAM,CAAC,KAAK,OAAO,CAAC;QACnE,OAAO,EAAE,IAAI,EAAE,IAAI,EAAE,OAAO,EAAE,MAAM,EAAE,SAAS,EAAE,CAAC;IACpD,CAAC,CAAC;IACF,MAAM,MAAM,GAAG,CAAC,IAAI,CAAC,gBAAgB,EAAE,YAAY,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC;IAC/D,IAAI,OAAO,CAAC,WAAW;QAAE,MAAM,CAAC,IAAI,CAAC,IAAI,CAAC,iBAAiB,EAAE,iBAAiB,EAAE,CAAC,CAAC,CAAC;IACnF,IAAI,OAAO,CAAC,UAAU;QAAE,MAAM,CAAC,IAAI,CAAC,IAAI,CAAC,gBAAgB,EAAE,gBAAgB,EAAE,CAAC,CAAC,CAAC;IAChF,OAAO,MAAM,CAAC;AAChB,CAAC;AAED,mFAAmF;AACnF,MAAM,UAAU,YAAY,CAAC,OAM5B;IACC,MAAM,MAAM,GAAgB;QAC1B,WAAW,EAAE,cAAc;QAC3B,GAAG,CAAC,OAAO,CAAC,WAAW,KAAK,SAAS,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,EAAE,kBAAkB,EAAE,OAAO,CAAC,WAAW,EAAE,CAAC;QACzF,QAAQ,EAAE,OAAO,CAAC,QAAQ;QAC1B,KAAK,EAAE,OAAO,CAAC,KAAK;QACpB,GAAG,CAAC,OAAO,CAAC,KAAK,KAAK,SAAS,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,EAAE,KAAK,EAAE,OAAO,CAAC,KAAK,EAAE,CAAC;KACjE,CAAC;IACF,OAAO,GAAG,IAAI,CAAC,SAAS,CAAC,MAAM,EAAE,IAAI,EAAE,CAAC,CAAC,IAAI,CAAC;AAChD,CAAC;AAED,8EAA8E;AAC9E,qFAAqF;AACrF,mFAAmF;AACnF,oFAAoF;AACpF,EAAE;AACF,sFAAsF;AACtF,mFAAmF;AACnF,sFAAsF;AACtF,sFAAsF;AACtF,gCAAgC;AAChC,8EAA8E;AAE9E,kFAAkF;AAClF,MAAM,UAAU,iBAAiB;IAC/B,OAAO;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CA6BR,CAAC;AACF,CAAC;AAED,iFAAiF;AACjF,MAAM,UAAU,gBAAgB;IAC9B,OAAO;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CA2DR,CAAC;AACF,CAAC"}
|
|
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"]}
|
package/dist/cli/report.d.ts
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import type { AgentsLintReport } from '../agents/lint.ts';
|
|
1
2
|
import type { RepoMap } from '../repomap/map.ts';
|
|
2
3
|
import type { SmeltResult } from '../types.ts';
|
|
3
4
|
export interface ReportInput {
|
|
@@ -41,4 +42,26 @@ export interface MapReportInput {
|
|
|
41
42
|
* length of what landed on stdout, and a mutation proves the assertion can go red.
|
|
42
43
|
*/
|
|
43
44
|
export declare function formatMapReport({ map, source, budgetSource }: MapReportInput): string;
|
|
45
|
+
/** What `smelt agents lint` prints. */
|
|
46
|
+
export interface AgentsReportInput {
|
|
47
|
+
/** The directory named on the command line, exactly as the user wrote it. */
|
|
48
|
+
readonly source: string;
|
|
49
|
+
/** Whether `--strict` was given — it changes what the closing line promises. */
|
|
50
|
+
readonly strict: boolean;
|
|
51
|
+
}
|
|
52
|
+
/**
|
|
53
|
+
* The lint report — and unlike the other two, it goes to **stdout**, because here the
|
|
54
|
+
* report *is* the output. `smelt` and `smelt map` put a payload on stdout and their
|
|
55
|
+
* report on stderr so the two can be piped apart; a lint has no payload to separate
|
|
56
|
+
* from, and sending its only output to stderr would make `smelt agents lint > audit.txt`
|
|
57
|
+
* write an empty file.
|
|
58
|
+
*
|
|
59
|
+
* Same law as the other two, though: every number is read off the
|
|
60
|
+
* {@link AgentsLintReport} the library returned. The renderer counts nothing, so it
|
|
61
|
+
* cannot disagree with what was measured — and in particular both totals are the ones
|
|
62
|
+
* the lint computed over the levels, not a second tally over the printed rows. The
|
|
63
|
+
* guide's cited figure is likewise read from `agents/guide.ts` rather than retyped
|
|
64
|
+
* under the guide's name.
|
|
65
|
+
*/
|
|
66
|
+
export declare function formatAgentsReport(report: AgentsLintReport, { source, strict }: AgentsReportInput): string;
|
|
44
67
|
//# sourceMappingURL=report.d.ts.map
|
package/dist/cli/report.d.ts.map
CHANGED
|
@@ -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":"AAEA,OAAO,KAAK,EAAE,gBAAgB,EAAsB,MAAM,mBAAmB,CAAC;AAC9E,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,mBAAmB,CAAC;AACjD,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,aAAa,CAAC;AAK/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;AAED,uCAAuC;AACvC,MAAM,WAAW,iBAAiB;IAChC,6EAA6E;IAC7E,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;IACxB,gFAAgF;IAChF,QAAQ,CAAC,MAAM,EAAE,OAAO,CAAC;CAC1B;AAED;;;;;;;;;;;;;GAaG;AACH,wBAAgB,kBAAkB,CAChC,MAAM,EAAE,gBAAgB,EACxB,EAAE,MAAM,EAAE,MAAM,EAAE,EAAE,iBAAiB,GACpC,MAAM,CA8GR","sourcesContent":["import { GUIDE, GUIDE_TITLE } from '../agents/guide.ts';\nimport { overBudgetBytes } from '../agents/lint.ts';\nimport type { AgentsLintReport, AgentsMirrorReport } from '../agents/lint.ts';\nimport type { RepoMap } from '../repomap/map.ts';\nimport type { SmeltResult } from '../types.ts';\n\nimport { CONFIG_FILE_NAME } from './config.ts';\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/** What `smelt agents lint` prints. */\nexport interface AgentsReportInput {\n /** The directory named on the command line, exactly as the user wrote it. */\n readonly source: string;\n /** Whether `--strict` was given — it changes what the closing line promises. */\n readonly strict: boolean;\n}\n\n/**\n * The lint report — and unlike the other two, it goes to **stdout**, because here the\n * report *is* the output. `smelt` and `smelt map` put a payload on stdout and their\n * report on stderr so the two can be piped apart; a lint has no payload to separate\n * from, and sending its only output to stderr would make `smelt agents lint > audit.txt`\n * write an empty file.\n *\n * Same law as the other two, though: every number is read off the\n * {@link AgentsLintReport} the library returned. The renderer counts nothing, so it\n * cannot disagree with what was measured — and in particular both totals are the ones\n * the lint computed over the levels, not a second tally over the printed rows. The\n * guide's cited figure is likewise read from `agents/guide.ts` rather than retyped\n * under the guide's name.\n */\nexport function formatAgentsReport(\n report: AgentsLintReport,\n { source, strict }: AgentsReportInput,\n): string {\n const lines: string[] = [`${CLI_NAME} agents lint ${source}`];\n\n if (report.levels.length === 0) {\n lines.push('');\n lines.push(` no AGENTS.md, CLAUDE.md or GEMINI.md under ${source} — nothing is loaded on`);\n lines.push(' every request, so there is nothing to measure. That is a fine state, not a');\n lines.push(` failure; \\`${CLI_NAME} agents lint\\` has no opinion about whether you want one.`);\n return `${lines.join('\\n')}\\n`;\n }\n\n lines.push('');\n lines.push(' the instruction files in this tree');\n const labelWidth = report.levels.reduce(\n (widest, level) =>\n Math.max(widest, level.path.length, ...level.mirrors.map((m) => m.path.length)),\n Math.max(IMPERATIVES_LABEL.length, PER_REQUEST_LABEL.length, WHOLE_TREE_LABEL.length),\n );\n for (const level of report.levels) {\n lines.push(` ${level.path.padEnd(labelWidth)} ${group(level.bytes).padStart(9)} B`);\n for (const mirror of level.mirrors) {\n lines.push(\n ` ${mirror.path.padEnd(labelWidth)} ${' '.repeat(11)}${mirrorNote(mirror.standing)}`,\n );\n }\n }\n lines.push(\n ` ${PER_REQUEST_LABEL.padEnd(labelWidth)} ${group(report.perRequestBytes).padStart(9)} B`,\n );\n // Printed only when it is a different number — which is exactly when a reader could\n // otherwise mistake the sum for a per-request cost. In a single-chain repository the\n // two are equal and a second row would be noise claiming to be information.\n if (report.totalBytes !== report.perRequestBytes) {\n lines.push(\n ` ${WHOLE_TREE_LABEL.padEnd(labelWidth)} ${group(report.totalBytes).padStart(9)} B`,\n );\n lines.push(' a nested file merges with its ancestors, never with its siblings, so no');\n lines.push(' one request loads the whole tree. Per request is the heaviest chain.');\n }\n lines.push(\n ` ${IMPERATIVES_LABEL.padEnd(labelWidth)} ` +\n `${group(report.imperatives.length).padStart(9)}`,\n );\n // The figure is the guide's, so it is read from where the guide is quoted rather\n // than retyped here: an explanation that paraphrases its source drifts from it\n // silently, and this one is printed under the guide's own name.\n for (const wrapped of wrap(`${GUIDE_TITLE} cites: \"${GUIDE.instructionCeiling}\".`, 68)) {\n lines.push(` ${wrapped}`);\n }\n lines.push(' Printed as a citation, compared to nothing: the only ceiling here is');\n lines.push(' the one you set.');\n\n const over = overBudgetBytes(report);\n lines.push('');\n if (report.budgetBytes === undefined) {\n lines.push(` no budget set — add {\"agents\":{\"budgetBytes\":N}} to ${CONFIG_FILE_NAME} and`);\n lines.push(` exceeding it exits 1. ${CLI_NAME} will never invent that number for you.`);\n } else if (over === undefined) {\n lines.push(\n ` within budget ${group(report.totalBytes)} B of ${group(report.budgetBytes)} B ` +\n `(${CONFIG_FILE_NAME}: agents.budgetBytes, against the whole tree).`,\n );\n } else {\n lines.push(\n ` OVER BUDGET ${group(report.totalBytes)} B against your ${group(report.budgetBytes)} B ` +\n `budget — over by ${group(over)} B.`,\n );\n lines.push(` The budget is yours, from ${CONFIG_FILE_NAME}, and it caps the`);\n lines.push(' whole tree rather than one request — the stricter of the two, so');\n lines.push(' it cannot be met by moving bytes into another package. Exit 1 is');\n lines.push(' the same over-budget code every other smelt run uses.');\n }\n\n if (report.findings.length === 0) {\n lines.push('');\n lines.push(' no findings. Eight advisory rules ran and none matched — either the file is');\n lines.push(' in good shape, or a rule is asleep. `pnpm mutate` is how this repo tells the');\n lines.push(' difference about its own guards; a fixture per rule is how it tells it here.');\n return `${lines.join('\\n')}\\n`;\n }\n\n const rows = report.findings.map((finding) => ({\n place: `${finding.file}:${String(finding.line)}`,\n rule: finding.reason.rule,\n explanation: finding.reason.explanation,\n }));\n const ruleWidth = width(\n '',\n rows.map((row) => row.rule),\n );\n\n lines.push('');\n for (const row of rows) {\n lines.push(` ${row.rule.padEnd(ruleWidth)} ${row.place}`);\n // The explanation gets its own wrapped lines rather than a fourth column. It is\n // the *reason*, which is the part a reader actually has to read — clipped to a\n // terminal column it becomes an ellipsis, and Law 2 promises an explanation, not\n // the first 46 characters of one.\n for (const wrapped of wrap(row.explanation, EXPLANATION_WRAP)) lines.push(` ${wrapped}`);\n }\n\n lines.push('');\n lines.push(\n ` ${count(report.findings.length, 'finding')}. ` +\n (strict\n ? 'Exit 1: --strict was given.'\n : `Advisory — exit 0. Pass --strict to fail a CI run on any of them.`),\n );\n\n return `${lines.join('\\n')}\\n`;\n}\n\n/** The label the imperative count is reported under. Never \"instructions\": R6. */\nconst IMPERATIVES_LABEL = 'imperatives (heuristic)';\n\n/** The heaviest ancestor chain — the honest answer to \"what does a request cost\". */\nconst PER_REQUEST_LABEL = 'per request (worst case)';\n\n/** Every level summed. The repository's instruction surface, and not a request's cost. */\nconst WHOLE_TREE_LABEL = 'whole tree';\n\n/** Where a finding's explanation wraps, once its six-column indent is removed. */\nconst EXPLANATION_WRAP = 84;\n\n/** Greedy word wrap. No ICU, no dependency — the output is identical everywhere. */\nfunction wrap(text: string, columns: number): readonly string[] {\n const out: string[] = [];\n let line = '';\n for (const word of text.split(' ')) {\n const candidate = line === '' ? word : `${line} ${word}`;\n if (line !== '' && candidate.length > columns) {\n out.push(line);\n line = word;\n } else {\n line = candidate;\n }\n }\n if (line !== '') out.push(line);\n return out;\n}\n\n/** How a mirror stands beside its AGENTS.md, in one clause. */\nfunction mirrorNote(standing: AgentsMirrorReport['standing']): string {\n switch (standing) {\n case 'symlink':\n return 'symlink — cannot drift, and costs no extra bytes';\n case 'copy':\n return 'copy, byte-identical today — a symlink could not drift';\n case 'drift':\n return 'DIVERGED — see mirror-drift below';\n }\n}\n\n/** How many lines a byte range covers in the input. Derived, never tallied separately. */ function lineSpan(\n text: string,\n start: number,\n end: number,\n): 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"]}
|