@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/report.js
CHANGED
|
@@ -1,4 +1,7 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { GUIDE, GUIDE_TITLE } from '../agents/guide.js';
|
|
2
|
+
import { overBudgetBytes } from '../agents/lint.js';
|
|
3
|
+
import { CONFIG_FILE_NAME } from './config.js';
|
|
4
|
+
import { CLI_NAME } from './shell.js';
|
|
2
5
|
/** Longest explanation printed in full before it gets an ellipsis. */
|
|
3
6
|
const EXPLANATION_WIDTH = 46;
|
|
4
7
|
/**
|
|
@@ -76,15 +79,150 @@ export function formatMapReport({ map, source, budgetSource }) {
|
|
|
76
79
|
`— the map fits itself to the budget by construction, so there is no over-budget exit`);
|
|
77
80
|
if (map.cache !== undefined) {
|
|
78
81
|
lines.push(`cache ${count(map.cache.hits, 'hit')}, ${count(map.cache.misses, 'miss', 'es')}, ` +
|
|
79
|
-
`${group(map.cache.discarded)} discarded`);
|
|
82
|
+
`${group(map.cache.discarded)} discarded, ${group(map.cache.pruned)} pruned`);
|
|
80
83
|
}
|
|
81
84
|
for (const warning of map.warnings) {
|
|
82
85
|
lines.push(`warning ${warning.rule}: ${warning.explanation}`);
|
|
83
86
|
}
|
|
84
87
|
return `${lines.join('\n')}\n`;
|
|
85
88
|
}
|
|
86
|
-
/**
|
|
87
|
-
|
|
89
|
+
/**
|
|
90
|
+
* The lint report — and unlike the other two, it goes to **stdout**, because here the
|
|
91
|
+
* report *is* the output. `smelt` and `smelt map` put a payload on stdout and their
|
|
92
|
+
* report on stderr so the two can be piped apart; a lint has no payload to separate
|
|
93
|
+
* from, and sending its only output to stderr would make `smelt agents lint > audit.txt`
|
|
94
|
+
* write an empty file.
|
|
95
|
+
*
|
|
96
|
+
* Same law as the other two, though: every number is read off the
|
|
97
|
+
* {@link AgentsLintReport} the library returned. The renderer counts nothing, so it
|
|
98
|
+
* cannot disagree with what was measured — and in particular both totals are the ones
|
|
99
|
+
* the lint computed over the levels, not a second tally over the printed rows. The
|
|
100
|
+
* guide's cited figure is likewise read from `agents/guide.ts` rather than retyped
|
|
101
|
+
* under the guide's name.
|
|
102
|
+
*/
|
|
103
|
+
export function formatAgentsReport(report, { source, strict }) {
|
|
104
|
+
const lines = [`${CLI_NAME} agents lint ${source}`];
|
|
105
|
+
if (report.levels.length === 0) {
|
|
106
|
+
lines.push('');
|
|
107
|
+
lines.push(` no AGENTS.md, CLAUDE.md or GEMINI.md under ${source} — nothing is loaded on`);
|
|
108
|
+
lines.push(' every request, so there is nothing to measure. That is a fine state, not a');
|
|
109
|
+
lines.push(` failure; \`${CLI_NAME} agents lint\` has no opinion about whether you want one.`);
|
|
110
|
+
return `${lines.join('\n')}\n`;
|
|
111
|
+
}
|
|
112
|
+
lines.push('');
|
|
113
|
+
lines.push(' the instruction files in this tree');
|
|
114
|
+
const labelWidth = report.levels.reduce((widest, level) => Math.max(widest, level.path.length, ...level.mirrors.map((m) => m.path.length)), Math.max(IMPERATIVES_LABEL.length, PER_REQUEST_LABEL.length, WHOLE_TREE_LABEL.length));
|
|
115
|
+
for (const level of report.levels) {
|
|
116
|
+
lines.push(` ${level.path.padEnd(labelWidth)} ${group(level.bytes).padStart(9)} B`);
|
|
117
|
+
for (const mirror of level.mirrors) {
|
|
118
|
+
lines.push(` ${mirror.path.padEnd(labelWidth)} ${' '.repeat(11)}${mirrorNote(mirror.standing)}`);
|
|
119
|
+
}
|
|
120
|
+
}
|
|
121
|
+
lines.push(` ${PER_REQUEST_LABEL.padEnd(labelWidth)} ${group(report.perRequestBytes).padStart(9)} B`);
|
|
122
|
+
// Printed only when it is a different number — which is exactly when a reader could
|
|
123
|
+
// otherwise mistake the sum for a per-request cost. In a single-chain repository the
|
|
124
|
+
// two are equal and a second row would be noise claiming to be information.
|
|
125
|
+
if (report.totalBytes !== report.perRequestBytes) {
|
|
126
|
+
lines.push(` ${WHOLE_TREE_LABEL.padEnd(labelWidth)} ${group(report.totalBytes).padStart(9)} B`);
|
|
127
|
+
lines.push(' a nested file merges with its ancestors, never with its siblings, so no');
|
|
128
|
+
lines.push(' one request loads the whole tree. Per request is the heaviest chain.');
|
|
129
|
+
}
|
|
130
|
+
lines.push(` ${IMPERATIVES_LABEL.padEnd(labelWidth)} ` +
|
|
131
|
+
`${group(report.imperatives.length).padStart(9)}`);
|
|
132
|
+
// The figure is the guide's, so it is read from where the guide is quoted rather
|
|
133
|
+
// than retyped here: an explanation that paraphrases its source drifts from it
|
|
134
|
+
// silently, and this one is printed under the guide's own name.
|
|
135
|
+
for (const wrapped of wrap(`${GUIDE_TITLE} cites: "${GUIDE.instructionCeiling}".`, 68)) {
|
|
136
|
+
lines.push(` ${wrapped}`);
|
|
137
|
+
}
|
|
138
|
+
lines.push(' Printed as a citation, compared to nothing: the only ceiling here is');
|
|
139
|
+
lines.push(' the one you set.');
|
|
140
|
+
const over = overBudgetBytes(report);
|
|
141
|
+
lines.push('');
|
|
142
|
+
if (report.budgetBytes === undefined) {
|
|
143
|
+
lines.push(` no budget set — add {"agents":{"budgetBytes":N}} to ${CONFIG_FILE_NAME} and`);
|
|
144
|
+
lines.push(` exceeding it exits 1. ${CLI_NAME} will never invent that number for you.`);
|
|
145
|
+
}
|
|
146
|
+
else if (over === undefined) {
|
|
147
|
+
lines.push(` within budget ${group(report.totalBytes)} B of ${group(report.budgetBytes)} B ` +
|
|
148
|
+
`(${CONFIG_FILE_NAME}: agents.budgetBytes, against the whole tree).`);
|
|
149
|
+
}
|
|
150
|
+
else {
|
|
151
|
+
lines.push(` OVER BUDGET ${group(report.totalBytes)} B against your ${group(report.budgetBytes)} B ` +
|
|
152
|
+
`budget — over by ${group(over)} B.`);
|
|
153
|
+
lines.push(` The budget is yours, from ${CONFIG_FILE_NAME}, and it caps the`);
|
|
154
|
+
lines.push(' whole tree rather than one request — the stricter of the two, so');
|
|
155
|
+
lines.push(' it cannot be met by moving bytes into another package. Exit 1 is');
|
|
156
|
+
lines.push(' the same over-budget code every other smelt run uses.');
|
|
157
|
+
}
|
|
158
|
+
if (report.findings.length === 0) {
|
|
159
|
+
lines.push('');
|
|
160
|
+
lines.push(' no findings. Eight advisory rules ran and none matched — either the file is');
|
|
161
|
+
lines.push(' in good shape, or a rule is asleep. `pnpm mutate` is how this repo tells the');
|
|
162
|
+
lines.push(' difference about its own guards; a fixture per rule is how it tells it here.');
|
|
163
|
+
return `${lines.join('\n')}\n`;
|
|
164
|
+
}
|
|
165
|
+
const rows = report.findings.map((finding) => ({
|
|
166
|
+
place: `${finding.file}:${String(finding.line)}`,
|
|
167
|
+
rule: finding.reason.rule,
|
|
168
|
+
explanation: finding.reason.explanation,
|
|
169
|
+
}));
|
|
170
|
+
const ruleWidth = width('', rows.map((row) => row.rule));
|
|
171
|
+
lines.push('');
|
|
172
|
+
for (const row of rows) {
|
|
173
|
+
lines.push(` ${row.rule.padEnd(ruleWidth)} ${row.place}`);
|
|
174
|
+
// The explanation gets its own wrapped lines rather than a fourth column. It is
|
|
175
|
+
// the *reason*, which is the part a reader actually has to read — clipped to a
|
|
176
|
+
// terminal column it becomes an ellipsis, and Law 2 promises an explanation, not
|
|
177
|
+
// the first 46 characters of one.
|
|
178
|
+
for (const wrapped of wrap(row.explanation, EXPLANATION_WRAP))
|
|
179
|
+
lines.push(` ${wrapped}`);
|
|
180
|
+
}
|
|
181
|
+
lines.push('');
|
|
182
|
+
lines.push(` ${count(report.findings.length, 'finding')}. ` +
|
|
183
|
+
(strict
|
|
184
|
+
? 'Exit 1: --strict was given.'
|
|
185
|
+
: `Advisory — exit 0. Pass --strict to fail a CI run on any of them.`));
|
|
186
|
+
return `${lines.join('\n')}\n`;
|
|
187
|
+
}
|
|
188
|
+
/** The label the imperative count is reported under. Never "instructions": R6. */
|
|
189
|
+
const IMPERATIVES_LABEL = 'imperatives (heuristic)';
|
|
190
|
+
/** The heaviest ancestor chain — the honest answer to "what does a request cost". */
|
|
191
|
+
const PER_REQUEST_LABEL = 'per request (worst case)';
|
|
192
|
+
/** Every level summed. The repository's instruction surface, and not a request's cost. */
|
|
193
|
+
const WHOLE_TREE_LABEL = 'whole tree';
|
|
194
|
+
/** Where a finding's explanation wraps, once its six-column indent is removed. */
|
|
195
|
+
const EXPLANATION_WRAP = 84;
|
|
196
|
+
/** Greedy word wrap. No ICU, no dependency — the output is identical everywhere. */
|
|
197
|
+
function wrap(text, columns) {
|
|
198
|
+
const out = [];
|
|
199
|
+
let line = '';
|
|
200
|
+
for (const word of text.split(' ')) {
|
|
201
|
+
const candidate = line === '' ? word : `${line} ${word}`;
|
|
202
|
+
if (line !== '' && candidate.length > columns) {
|
|
203
|
+
out.push(line);
|
|
204
|
+
line = word;
|
|
205
|
+
}
|
|
206
|
+
else {
|
|
207
|
+
line = candidate;
|
|
208
|
+
}
|
|
209
|
+
}
|
|
210
|
+
if (line !== '')
|
|
211
|
+
out.push(line);
|
|
212
|
+
return out;
|
|
213
|
+
}
|
|
214
|
+
/** How a mirror stands beside its AGENTS.md, in one clause. */
|
|
215
|
+
function mirrorNote(standing) {
|
|
216
|
+
switch (standing) {
|
|
217
|
+
case 'symlink':
|
|
218
|
+
return 'symlink — cannot drift, and costs no extra bytes';
|
|
219
|
+
case 'copy':
|
|
220
|
+
return 'copy, byte-identical today — a symlink could not drift';
|
|
221
|
+
case 'drift':
|
|
222
|
+
return 'DIVERGED — see mirror-drift below';
|
|
223
|
+
}
|
|
224
|
+
}
|
|
225
|
+
/** How many lines a byte range covers in the input. Derived, never tallied separately. */ function lineSpan(text, start, end) {
|
|
88
226
|
const slice = Buffer.from(text, 'utf8').subarray(start, end).toString('utf8');
|
|
89
227
|
return slice.split('\n').length;
|
|
90
228
|
}
|
package/dist/cli/report.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"report.js","sourceRoot":"","sources":["../../src/cli/report.ts"],"names":[],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"report.js","sourceRoot":"","sources":["../../src/cli/report.ts"],"names":[],"mappings":"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","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"]}
|
package/dist/cli/run.d.ts
CHANGED
|
@@ -1,99 +1,38 @@
|
|
|
1
|
-
import type {
|
|
2
|
-
|
|
3
|
-
export {
|
|
4
|
-
export
|
|
5
|
-
export {
|
|
6
|
-
export type {
|
|
7
|
-
export {
|
|
8
|
-
export type {
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
export declare const EXIT: {
|
|
20
|
-
readonly ok: 0;
|
|
21
|
-
readonly overBudget: 1;
|
|
22
|
-
readonly usage: 2;
|
|
23
|
-
readonly refused: 3;
|
|
24
|
-
readonly unexpected: 4;
|
|
25
|
-
};
|
|
26
|
-
/**
|
|
27
|
-
* The `--json` envelope format, versioned like the marker for the same reason: this is
|
|
28
|
-
* a surface other programs parse, so a change to it has to be identifiable rather than
|
|
29
|
-
* silent.
|
|
30
|
-
*/
|
|
31
|
-
export declare const CLI_JSON_FORMAT = "smelt-cli/v1";
|
|
32
|
-
/**
|
|
33
|
-
* The `smelt map --json` envelope format. Its own version line, because the two
|
|
34
|
-
* envelopes carry different structures and must be able to move independently —
|
|
35
|
-
* a map envelope has no elided bytes to carry, since a map elides nothing.
|
|
36
|
-
*/
|
|
37
|
-
export declare const CLI_MAP_JSON_FORMAT = "smelt-map-cli/v1";
|
|
38
|
-
/**
|
|
39
|
-
* The `smelt stats --json` envelope format. Its own version line for the same reason
|
|
40
|
-
* `smelt map` has one: the two envelopes carry different structures and must move
|
|
41
|
-
* independently.
|
|
42
|
-
*/
|
|
43
|
-
export declare const CLI_STATS_JSON_FORMAT = "smelt-stats-cli/v1";
|
|
44
|
-
/** What `smelt stats --json` prints: the {@link RetrieveStats} verbatim, versioned. */
|
|
45
|
-
export interface CliStatsJsonEnvelope {
|
|
46
|
-
readonly format: string;
|
|
47
|
-
/** The {@link RetrieveStats} exactly as the store's `stats()` returned them. */
|
|
48
|
-
readonly stats: RetrieveStats;
|
|
49
|
-
}
|
|
50
|
-
/** What `smelt map --json` prints: the {@link RepoMap} verbatim, versioned. */
|
|
51
|
-
export interface CliMapJsonEnvelope {
|
|
52
|
-
readonly format: string;
|
|
53
|
-
/** The {@link RepoMap} exactly as `buildRepoMap` returned it. */
|
|
54
|
-
readonly map: RepoMap;
|
|
55
|
-
}
|
|
56
|
-
/**
|
|
57
|
-
* What `--json` prints, and what `--reconstruct` reads back.
|
|
58
|
-
*
|
|
59
|
-
* `result` is the {@link SmeltResult} **verbatim** — nothing renamed, nothing dropped —
|
|
60
|
-
* so it can be diffed in a test. `elided` is the other half, and it is here because a
|
|
61
|
-
* result on its own is *not* reconstructible: Law 3 is a property of the result plus
|
|
62
|
-
* the store that holds its bytes, and a file claiming to prove the round trip while
|
|
63
|
-
* carrying only half of it would prove nothing.
|
|
64
|
-
*/
|
|
65
|
-
export interface CliJsonEnvelope {
|
|
66
|
-
readonly format: string;
|
|
67
|
-
readonly result: SmeltResult;
|
|
68
|
-
/** hash → the exact elided bytes. Keys match `result.elisions[].hash`. */
|
|
69
|
-
readonly elided: Readonly<Record<string, string>>;
|
|
70
|
-
}
|
|
71
|
-
/** Where the CLI's bytes come from and go. Injected so `runCli` is testable in-process. */
|
|
72
|
-
export interface CliIo {
|
|
73
|
-
readonly stdout: (text: string) => void;
|
|
74
|
-
readonly stderr: (text: string) => void;
|
|
75
|
-
/** All of stdin, as UTF-8. @throws {CliUsageError} when nothing is piped. */
|
|
76
|
-
readonly stdin: () => string;
|
|
77
|
-
/** The package version, for `--version`. */
|
|
78
|
-
readonly version: string;
|
|
79
|
-
/**
|
|
80
|
-
* Where `smelt.config.json` discovery starts, and where `init` writes. Defaults to
|
|
81
|
-
* the process working directory; tests pass a temp directory to stay hermetic.
|
|
82
|
-
*/
|
|
83
|
-
readonly cwd?: string;
|
|
84
|
-
/**
|
|
85
|
-
* Interactive input for `smelt init` — the wizard reads answers line by line, which
|
|
86
|
-
* the one-shot `stdin()` above cannot provide. `bin.ts` passes the real stdin
|
|
87
|
-
* stream; tests pass a scripted one. Absent means `init` is a usage error.
|
|
88
|
-
*/
|
|
89
|
-
readonly initInput?: NodeJS.ReadableStream;
|
|
90
|
-
}
|
|
1
|
+
import type { CliIo } from './shell.ts';
|
|
2
|
+
export { CLI_NAME, EXIT } from './shell.ts';
|
|
3
|
+
export type { AnswerStream, CliIo } from './shell.ts';
|
|
4
|
+
export { cliUsage } from './usage.ts';
|
|
5
|
+
export { parseSmeltArgs } from './args.ts';
|
|
6
|
+
export type { AgentsInvocation, CliInvocation, HooksInvocation, InitInvocation, MapInvocation, RetrieveInvocation, SmeltInvocation, StatsInvocation, } from './args.ts';
|
|
7
|
+
export { formatAgentsReport, formatMapReport, formatReport } from './report.ts';
|
|
8
|
+
export type { AgentsReportInput, MapReportInput, ReportInput } from './report.ts';
|
|
9
|
+
export { CLI_JSON_FORMAT, resolveRun } from './subcommands/smelt.ts';
|
|
10
|
+
export type { CliJsonEnvelope, ResolvedRun } from './subcommands/smelt.ts';
|
|
11
|
+
export { CLI_MAP_JSON_FORMAT, resolveMapRun } from './subcommands/map.ts';
|
|
12
|
+
export type { CliMapJsonEnvelope, ResolvedMapRun } from './subcommands/map.ts';
|
|
13
|
+
export { resolveStoreRun } from './subcommands/retrieve.ts';
|
|
14
|
+
export type { ResolvedStoreRun } from './subcommands/retrieve.ts';
|
|
15
|
+
export { CLI_STATS_JSON_FORMAT } from './subcommands/stats.ts';
|
|
16
|
+
export type { CliStatsJsonEnvelope } from './subcommands/stats.ts';
|
|
17
|
+
export { CLI_AGENTS_JSON_FORMAT, resolveAgentsRun } from './subcommands/agents.ts';
|
|
18
|
+
export type { CliAgentsJsonEnvelope, ResolvedAgentsRun } from './subcommands/agents.ts';
|
|
91
19
|
/**
|
|
92
20
|
* The whole CLI, as a function that returns an exit code instead of calling `exit`.
|
|
93
21
|
*
|
|
94
22
|
* Smelted text goes to stdout and the report goes to stderr, so `smelt big.log
|
|
95
23
|
* --budget 4000 > small.log` leaves the human-readable part on the terminal and the
|
|
96
24
|
* payload in the file.
|
|
25
|
+
*
|
|
26
|
+
* It is a lookup and a dispatch, and nothing else: this function used to hold a
|
|
27
|
+
* `switch` over seven modes and seven `run*` functions beneath it, so adding a verb
|
|
28
|
+
* meant editing it. Now the verb that parsed an invocation is the verb that resolves
|
|
29
|
+
* and runs it — `SUBCOMMANDS` in `subcommands/registry.ts` — and the only decisions
|
|
30
|
+
* left here are the two global flags and the mapping from a thrown error to an exit
|
|
31
|
+
* code.
|
|
32
|
+
*
|
|
33
|
+
* The config is passed as a thunk, not a value: `init` and `hooks` read
|
|
34
|
+
* `smelt.config.json` themselves with their own tolerance, and loading it eagerly here
|
|
35
|
+
* would make a wizard you run to *fix* a malformed config refuse to start.
|
|
97
36
|
*/
|
|
98
37
|
export declare function runCli(argv: readonly string[], io: CliIo): Promise<number>;
|
|
99
38
|
//# sourceMappingURL=run.d.ts.map
|
package/dist/cli/run.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"run.d.ts","sourceRoot":"","sources":["../../src/cli/run.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"run.d.ts","sourceRoot":"","sources":["../../src/cli/run.ts"],"names":[],"mappings":"AAMA,OAAO,KAAK,EAAE,KAAK,EAAE,MAAM,YAAY,CAAC;AAMxC,OAAO,EAAE,QAAQ,EAAE,IAAI,EAAE,MAAM,YAAY,CAAC;AAC5C,YAAY,EAAE,YAAY,EAAE,KAAK,EAAE,MAAM,YAAY,CAAC;AACtD,OAAO,EAAE,QAAQ,EAAE,MAAM,YAAY,CAAC;AACtC,OAAO,EAAE,cAAc,EAAE,MAAM,WAAW,CAAC;AAC3C,YAAY,EACV,gBAAgB,EAChB,aAAa,EACb,eAAe,EACf,cAAc,EACd,aAAa,EACb,kBAAkB,EAClB,eAAe,EACf,eAAe,GAChB,MAAM,WAAW,CAAC;AACnB,OAAO,EAAE,kBAAkB,EAAE,eAAe,EAAE,YAAY,EAAE,MAAM,aAAa,CAAC;AAChF,YAAY,EAAE,iBAAiB,EAAE,cAAc,EAAE,WAAW,EAAE,MAAM,aAAa,CAAC;AAClF,OAAO,EAAE,eAAe,EAAE,UAAU,EAAE,MAAM,wBAAwB,CAAC;AACrE,YAAY,EAAE,eAAe,EAAE,WAAW,EAAE,MAAM,wBAAwB,CAAC;AAC3E,OAAO,EAAE,mBAAmB,EAAE,aAAa,EAAE,MAAM,sBAAsB,CAAC;AAC1E,YAAY,EAAE,kBAAkB,EAAE,cAAc,EAAE,MAAM,sBAAsB,CAAC;AAC/E,OAAO,EAAE,eAAe,EAAE,MAAM,2BAA2B,CAAC;AAC5D,YAAY,EAAE,gBAAgB,EAAE,MAAM,2BAA2B,CAAC;AAClE,OAAO,EAAE,qBAAqB,EAAE,MAAM,wBAAwB,CAAC;AAC/D,YAAY,EAAE,oBAAoB,EAAE,MAAM,wBAAwB,CAAC;AACnE,OAAO,EAAE,sBAAsB,EAAE,gBAAgB,EAAE,MAAM,yBAAyB,CAAC;AACnF,YAAY,EAAE,qBAAqB,EAAE,iBAAiB,EAAE,MAAM,yBAAyB,CAAC;AAExF;;;;;;;;;;;;;;;;;GAiBG;AACH,wBAAsB,MAAM,CAAC,IAAI,EAAE,SAAS,MAAM,EAAE,EAAE,EAAE,EAAE,KAAK,GAAG,OAAO,CAAC,MAAM,CAAC,CA2BhF","sourcesContent":["import process from 'node:process';\n\nimport { CliUsageError, SmeltError } from '../errors.ts';\n\nimport { loadNearestConfig } from './config.ts';\nimport { EXIT } from './shell.ts';\nimport type { CliIo } from './shell.ts';\nimport { commandFor } from './subcommands/registry.ts';\nimport { cliUsage } from './usage.ts';\n\nimport { parseSmeltArgs } from './args.ts';\n\nexport { CLI_NAME, EXIT } from './shell.ts';\nexport type { AnswerStream, CliIo } from './shell.ts';\nexport { cliUsage } from './usage.ts';\nexport { parseSmeltArgs } from './args.ts';\nexport type {\n AgentsInvocation,\n CliInvocation,\n HooksInvocation,\n InitInvocation,\n MapInvocation,\n RetrieveInvocation,\n SmeltInvocation,\n StatsInvocation,\n} from './args.ts';\nexport { formatAgentsReport, formatMapReport, formatReport } from './report.ts';\nexport type { AgentsReportInput, MapReportInput, ReportInput } from './report.ts';\nexport { CLI_JSON_FORMAT, resolveRun } from './subcommands/smelt.ts';\nexport type { CliJsonEnvelope, ResolvedRun } from './subcommands/smelt.ts';\nexport { CLI_MAP_JSON_FORMAT, resolveMapRun } from './subcommands/map.ts';\nexport type { CliMapJsonEnvelope, ResolvedMapRun } from './subcommands/map.ts';\nexport { resolveStoreRun } from './subcommands/retrieve.ts';\nexport type { ResolvedStoreRun } from './subcommands/retrieve.ts';\nexport { CLI_STATS_JSON_FORMAT } from './subcommands/stats.ts';\nexport type { CliStatsJsonEnvelope } from './subcommands/stats.ts';\nexport { CLI_AGENTS_JSON_FORMAT, resolveAgentsRun } from './subcommands/agents.ts';\nexport type { CliAgentsJsonEnvelope, ResolvedAgentsRun } from './subcommands/agents.ts';\n\n/**\n * The whole CLI, as a function that returns an exit code instead of calling `exit`.\n *\n * Smelted text goes to stdout and the report goes to stderr, so `smelt big.log\n * --budget 4000 > small.log` leaves the human-readable part on the terminal and the\n * payload in the file.\n *\n * It is a lookup and a dispatch, and nothing else: this function used to hold a\n * `switch` over seven modes and seven `run*` functions beneath it, so adding a verb\n * meant editing it. Now the verb that parsed an invocation is the verb that resolves\n * and runs it — `SUBCOMMANDS` in `subcommands/registry.ts` — and the only decisions\n * left here are the two global flags and the mapping from a thrown error to an exit\n * code.\n *\n * The config is passed as a thunk, not a value: `init` and `hooks` read\n * `smelt.config.json` themselves with their own tolerance, and loading it eagerly here\n * would make a wizard you run to *fix* a malformed config refuse to start.\n */\nexport async function runCli(argv: readonly string[], io: CliIo): Promise<number> {\n try {\n const invocation = parseSmeltArgs(argv);\n\n if (invocation.mode === 'help') {\n io.stdout(cliUsage());\n return EXIT.ok;\n }\n if (invocation.mode === 'version') {\n io.stdout(`${io.version}\\n`);\n return EXIT.ok;\n }\n\n const command = commandFor(invocation.mode);\n const config = () => loadNearestConfig(io.cwd ?? process.cwd());\n return await command.run(command.resolve(invocation, config), io);\n } catch (error) {\n if (error instanceof CliUsageError) {\n io.stderr(`${error.message}\\n`);\n return EXIT.usage;\n }\n if (error instanceof SmeltError) {\n io.stderr(`${error.name}: ${error.message}\\n`);\n return EXIT.refused;\n }\n throw error;\n }\n}\n"]}
|