@vibe-agent-toolkit/cli 0.2.0-rc.2 → 0.2.0-rc.4

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (211) hide show
  1. package/dist/bin/vat +68 -16
  2. package/dist/bin/vat.js +68 -16
  3. package/dist/bin/vat.js.map +1 -1
  4. package/dist/bin.js +157 -37
  5. package/dist/bin.js.map +1 -1
  6. package/dist/command-loaders.d.ts +44 -0
  7. package/dist/command-loaders.d.ts.map +1 -0
  8. package/dist/command-loaders.js +58 -0
  9. package/dist/command-loaders.js.map +1 -0
  10. package/dist/commands/agent/index.js +1 -1
  11. package/dist/commands/agent/install.d.ts.map +1 -1
  12. package/dist/commands/agent/install.js +46 -5
  13. package/dist/commands/agent/install.js.map +1 -1
  14. package/dist/commands/audit/distributed-tree.d.ts +2 -2
  15. package/dist/commands/audit/distributed-tree.d.ts.map +1 -1
  16. package/dist/commands/audit/distributed-tree.js +2 -1
  17. package/dist/commands/audit/distributed-tree.js.map +1 -1
  18. package/dist/commands/audit/git-url-clone.d.ts +1 -1
  19. package/dist/commands/audit/git-url-clone.d.ts.map +1 -1
  20. package/dist/commands/audit/git-url-clone.js.map +1 -1
  21. package/dist/commands/audit/hierarchical-output.d.ts +1 -1
  22. package/dist/commands/audit/hierarchical-output.d.ts.map +1 -1
  23. package/dist/commands/audit/hierarchical-output.js +1 -1
  24. package/dist/commands/audit/hierarchical-output.js.map +1 -1
  25. package/dist/commands/audit.d.ts +22 -1
  26. package/dist/commands/audit.d.ts.map +1 -1
  27. package/dist/commands/audit.js +224 -24
  28. package/dist/commands/audit.js.map +1 -1
  29. package/dist/commands/build.d.ts +1 -1
  30. package/dist/commands/build.d.ts.map +1 -1
  31. package/dist/commands/build.js +15 -12
  32. package/dist/commands/build.js.map +1 -1
  33. package/dist/commands/cache/cache-control.d.ts +82 -0
  34. package/dist/commands/cache/cache-control.d.ts.map +1 -0
  35. package/dist/commands/cache/cache-control.js +86 -0
  36. package/dist/commands/cache/cache-control.js.map +1 -0
  37. package/dist/commands/cache/clear.d.ts +17 -3
  38. package/dist/commands/cache/clear.d.ts.map +1 -1
  39. package/dist/commands/cache/clear.js +68 -3
  40. package/dist/commands/cache/clear.js.map +1 -1
  41. package/dist/commands/cache/index.d.ts +13 -63
  42. package/dist/commands/cache/index.d.ts.map +1 -1
  43. package/dist/commands/cache/index.js +38 -79
  44. package/dist/commands/cache/index.js.map +1 -1
  45. package/dist/commands/claude/budget.d.ts +157 -0
  46. package/dist/commands/claude/budget.d.ts.map +1 -0
  47. package/dist/commands/claude/budget.js +412 -0
  48. package/dist/commands/claude/budget.js.map +1 -0
  49. package/dist/commands/claude/context.d.ts +340 -0
  50. package/dist/commands/claude/context.d.ts.map +1 -0
  51. package/dist/commands/claude/context.js +1079 -0
  52. package/dist/commands/claude/context.js.map +1 -0
  53. package/dist/commands/claude/index.d.ts +13 -0
  54. package/dist/commands/claude/index.d.ts.map +1 -1
  55. package/dist/commands/claude/index.js +24 -2
  56. package/dist/commands/claude/index.js.map +1 -1
  57. package/dist/commands/claude/marketplace/git-publish.d.ts.map +1 -1
  58. package/dist/commands/claude/marketplace/git-publish.js +18 -19
  59. package/dist/commands/claude/marketplace/git-publish.js.map +1 -1
  60. package/dist/commands/claude/marketplace/validate.d.ts +19 -1
  61. package/dist/commands/claude/marketplace/validate.d.ts.map +1 -1
  62. package/dist/commands/claude/marketplace/validate.js +41 -21
  63. package/dist/commands/claude/marketplace/validate.js.map +1 -1
  64. package/dist/commands/claude/plugin/build.d.ts +18 -2
  65. package/dist/commands/claude/plugin/build.d.ts.map +1 -1
  66. package/dist/commands/claude/plugin/build.js +55 -18
  67. package/dist/commands/claude/plugin/build.js.map +1 -1
  68. package/dist/commands/claude/plugin/helpers.d.ts.map +1 -1
  69. package/dist/commands/claude/plugin/helpers.js +2 -1
  70. package/dist/commands/claude/plugin/helpers.js.map +1 -1
  71. package/dist/commands/claude/plugin/install.d.ts.map +1 -1
  72. package/dist/commands/claude/plugin/install.js +24 -3
  73. package/dist/commands/claude/plugin/install.js.map +1 -1
  74. package/dist/commands/claude/plugin/tree-copy.d.ts.map +1 -1
  75. package/dist/commands/claude/plugin/tree-copy.js +2 -1
  76. package/dist/commands/claude/plugin/tree-copy.js.map +1 -1
  77. package/dist/commands/consistency-check.d.ts.map +1 -1
  78. package/dist/commands/consistency-check.js +4 -3
  79. package/dist/commands/consistency-check.js.map +1 -1
  80. package/dist/commands/corpus/report.d.ts +1 -1
  81. package/dist/commands/corpus/report.d.ts.map +1 -1
  82. package/dist/commands/corpus/runner.d.ts.map +1 -1
  83. package/dist/commands/corpus/runner.js +3 -2
  84. package/dist/commands/corpus/runner.js.map +1 -1
  85. package/dist/commands/corpus/scan.d.ts.map +1 -1
  86. package/dist/commands/corpus/scan.js +18 -8
  87. package/dist/commands/corpus/scan.js.map +1 -1
  88. package/dist/commands/doctor.d.ts +36 -0
  89. package/dist/commands/doctor.d.ts.map +1 -1
  90. package/dist/commands/doctor.js +99 -2
  91. package/dist/commands/doctor.js.map +1 -1
  92. package/dist/commands/inventory.d.ts +13 -1
  93. package/dist/commands/inventory.d.ts.map +1 -1
  94. package/dist/commands/inventory.js +118 -13
  95. package/dist/commands/inventory.js.map +1 -1
  96. package/dist/commands/mcp/collections.d.ts +1 -1
  97. package/dist/commands/mcp/collections.d.ts.map +1 -1
  98. package/dist/commands/phase-utils.d.ts +155 -104
  99. package/dist/commands/phase-utils.d.ts.map +1 -1
  100. package/dist/commands/phase-utils.js +109 -155
  101. package/dist/commands/phase-utils.js.map +1 -1
  102. package/dist/commands/rag/index-command.d.ts +39 -0
  103. package/dist/commands/rag/index-command.d.ts.map +1 -1
  104. package/dist/commands/rag/index-command.js +28 -2
  105. package/dist/commands/rag/index-command.js.map +1 -1
  106. package/dist/commands/rag/index.d.ts.map +1 -1
  107. package/dist/commands/rag/index.js +21 -10
  108. package/dist/commands/rag/index.js.map +1 -1
  109. package/dist/commands/resources/index.d.ts.map +1 -1
  110. package/dist/commands/resources/index.js +10 -2
  111. package/dist/commands/resources/index.js.map +1 -1
  112. package/dist/commands/resources/scan.d.ts +24 -0
  113. package/dist/commands/resources/scan.d.ts.map +1 -1
  114. package/dist/commands/resources/scan.js +19 -6
  115. package/dist/commands/resources/scan.js.map +1 -1
  116. package/dist/commands/resources/validate.d.ts +12 -1
  117. package/dist/commands/resources/validate.d.ts.map +1 -1
  118. package/dist/commands/resources/validate.js +102 -51
  119. package/dist/commands/resources/validate.js.map +1 -1
  120. package/dist/commands/skill/review-checklist.d.ts.map +1 -1
  121. package/dist/commands/skill/review-checklist.js +1 -0
  122. package/dist/commands/skill/review-checklist.js.map +1 -1
  123. package/dist/commands/skill/review.js +2 -2
  124. package/dist/commands/skill/review.js.map +1 -1
  125. package/dist/commands/skill/test/configure.d.ts +19 -0
  126. package/dist/commands/skill/test/configure.d.ts.map +1 -1
  127. package/dist/commands/skill/test/configure.js +18 -3
  128. package/dist/commands/skill/test/configure.js.map +1 -1
  129. package/dist/commands/skill/test/run.d.ts +51 -4
  130. package/dist/commands/skill/test/run.d.ts.map +1 -1
  131. package/dist/commands/skill/test/run.js +123 -12
  132. package/dist/commands/skill/test/run.js.map +1 -1
  133. package/dist/commands/skills/build.d.ts +11 -1
  134. package/dist/commands/skills/build.d.ts.map +1 -1
  135. package/dist/commands/skills/build.js +154 -61
  136. package/dist/commands/skills/build.js.map +1 -1
  137. package/dist/commands/skills/package.d.ts +1 -1
  138. package/dist/commands/skills/package.d.ts.map +1 -1
  139. package/dist/commands/skills/package.js.map +1 -1
  140. package/dist/commands/skills/skill-discovery.d.ts.map +1 -1
  141. package/dist/commands/skills/skill-discovery.js +2 -1
  142. package/dist/commands/skills/skill-discovery.js.map +1 -1
  143. package/dist/commands/skills/validate.d.ts +79 -2
  144. package/dist/commands/skills/validate.d.ts.map +1 -1
  145. package/dist/commands/skills/validate.js +101 -48
  146. package/dist/commands/skills/validate.js.map +1 -1
  147. package/dist/commands/validate.d.ts.map +1 -1
  148. package/dist/commands/validate.js +26 -16
  149. package/dist/commands/validate.js.map +1 -1
  150. package/dist/commands/verify.d.ts +11 -10
  151. package/dist/commands/verify.d.ts.map +1 -1
  152. package/dist/commands/verify.js +49 -38
  153. package/dist/commands/verify.js.map +1 -1
  154. package/dist/utils/command-error.d.ts +33 -2
  155. package/dist/utils/command-error.d.ts.map +1 -1
  156. package/dist/utils/command-error.js +34 -10
  157. package/dist/utils/command-error.js.map +1 -1
  158. package/dist/utils/config-loader.d.ts.map +1 -1
  159. package/dist/utils/config-loader.js +7 -1
  160. package/dist/utils/config-loader.js.map +1 -1
  161. package/dist/utils/context-budget-issues.d.ts +108 -0
  162. package/dist/utils/context-budget-issues.d.ts.map +1 -0
  163. package/dist/utils/context-budget-issues.js +280 -0
  164. package/dist/utils/context-budget-issues.js.map +1 -0
  165. package/dist/utils/corpus-target.d.ts +48 -0
  166. package/dist/utils/corpus-target.d.ts.map +1 -0
  167. package/dist/utils/corpus-target.js +61 -0
  168. package/dist/utils/corpus-target.js.map +1 -0
  169. package/dist/utils/issue-anchor.d.ts +2 -2
  170. package/dist/utils/issue-anchor.d.ts.map +1 -1
  171. package/dist/utils/issue-anchor.js +1 -1
  172. package/dist/utils/issue-rendering.d.ts +1 -1
  173. package/dist/utils/issue-rendering.d.ts.map +1 -1
  174. package/dist/utils/issue-rendering.js +1 -1
  175. package/dist/utils/issue-rendering.js.map +1 -1
  176. package/dist/utils/issue-severity.d.ts +1 -1
  177. package/dist/utils/issue-severity.d.ts.map +1 -1
  178. package/dist/utils/issue-severity.js +1 -1
  179. package/dist/utils/issue-severity.js.map +1 -1
  180. package/dist/utils/optional-backend.d.ts +77 -0
  181. package/dist/utils/optional-backend.d.ts.map +1 -0
  182. package/dist/utils/optional-backend.js +115 -0
  183. package/dist/utils/optional-backend.js.map +1 -0
  184. package/dist/utils/output.d.ts +17 -0
  185. package/dist/utils/output.d.ts.map +1 -1
  186. package/dist/utils/output.js +19 -0
  187. package/dist/utils/output.js.map +1 -1
  188. package/dist/utils/population-wiring.d.ts +100 -0
  189. package/dist/utils/population-wiring.d.ts.map +1 -0
  190. package/dist/utils/population-wiring.js +98 -0
  191. package/dist/utils/population-wiring.js.map +1 -0
  192. package/dist/utils/projection-store.d.ts +188 -0
  193. package/dist/utils/projection-store.d.ts.map +1 -0
  194. package/dist/utils/projection-store.js +257 -0
  195. package/dist/utils/projection-store.js.map +1 -0
  196. package/dist/utils/resource-loader.d.ts +128 -2
  197. package/dist/utils/resource-loader.d.ts.map +1 -1
  198. package/dist/utils/resource-loader.js +234 -7
  199. package/dist/utils/resource-loader.js.map +1 -1
  200. package/dist/utils/verdict-helpers.d.ts +1 -1
  201. package/dist/utils/verdict-helpers.d.ts.map +1 -1
  202. package/dist/utils/verdict-helpers.js +1 -1
  203. package/dist/utils/verdict-helpers.js.map +1 -1
  204. package/docs/agent.md +2 -2
  205. package/docs/mcp.md +2 -2
  206. package/docs/resources.md +8 -1
  207. package/package.json +15 -12
  208. package/dist/commands/resources/command-helpers.d.ts +0 -5
  209. package/dist/commands/resources/command-helpers.d.ts.map +0 -1
  210. package/dist/commands/resources/command-helpers.js +0 -6
  211. package/dist/commands/resources/command-helpers.js.map +0 -1
@@ -0,0 +1,412 @@
1
+ /**
2
+ * `vat claude budget [paths...]` — is the always-loaded context at a working
3
+ * location over its budget?
4
+ *
5
+ * ## Why this is a command and not a check inside `vat resources validate`
6
+ *
7
+ * It used to be one: default-on, with a `--no-context-budget` opt-out. That is
8
+ * gone, in both directions — `vat resources validate` has no knowledge of the
9
+ * budget at all any more, not a flag, not a default. The ruling behind the move
10
+ * is short: *a validation run must not emit findings nobody asked for.* An
11
+ * `info` finding attached to a lane people run for link and anchor errors is a
12
+ * finding they scroll past, and a check people scroll past is a check they
13
+ * eventually silence.
14
+ *
15
+ * ## The sibling split: `context` QUERIES, `budget` CHECKS
16
+ *
17
+ * `vat claude context` answers a question and
18
+ * never gates — totals, admissions, the declared limits, no verdict, always
19
+ * exit 0. This command is the other half of that pair: it applies a THRESHOLD,
20
+ * produces findings with severities an adopter can configure, and lets an
21
+ * adopter who promotes the code to `error` fail their build with it. Two verbs
22
+ * because they are two acts, and folding a verdict into the query would make
23
+ * the query's number a number people learn to stop reading.
24
+ *
25
+ * ## Everything below is orchestration — deliberately
26
+ *
27
+ * Which directories exist, what each pays, and whether that is over budget are
28
+ * all decided in `@vibe-agent-toolkit/resources` (`buildClaudeContextPopulation`
29
+ * and `sweepAlwaysLoadedBudgets`); the wording and grouping of the findings in
30
+ * `utils/context-budget-issues.ts`; severity resolution in the two shared
31
+ * filters every other lane runs. This module populates one tree, calls them in
32
+ * order, and renders. It decides nothing about context loading of its own,
33
+ * which is the CLI-stays-dumb rule applied to the lane where the temptation is
34
+ * strongest.
35
+ *
36
+ * ⛔ The threshold is never re-spelled here. It is a MEASURED quantity that
37
+ * lives beside the detector (`DEFAULT_ALWAYS_LOADED_CONTEXT_TOKENS`), and a
38
+ * literal in this package would be a second source of truth that nothing
39
+ * compares.
40
+ *
41
+ * ## The stated bounds ride ONCE on the REPORT, in every format
42
+ *
43
+ * The sibling query publishes 23 stated limits; this command applies a threshold
44
+ * to the same measurement, so it publishes {@link ALWAYS_LOADED_BUDGET_LIMITS}
45
+ * and {@link CLAUDE_CONTEXT_BOUNDS_STATEMENT} beside its verdict — the half that
46
+ * GATES is the half whose bounds a reader most needs. Both are imported, never
47
+ * restated: the sentence is domain content owned beside the list it frames.
48
+ *
49
+ * ⛔ They belong to the REPORT, never to a finding. A per-finding copy is the
50
+ * defect this lane already shipped once on the query side, and it is invisible to
51
+ * any assertion that checks presence rather than counting occurrences.
52
+ */
53
+ import { ALWAYS_LOADED_BUDGET_LIMITS, buildClaudeContextPopulation, CLAUDE_CONTEXT_BOUNDS_STATEMENT, DEFAULT_ALWAYS_LOADED_CONTEXT_TOKENS, sweepAlwaysLoadedBudgets, } from '@vibe-agent-toolkit/resources';
54
+ import { applyAllowFilter, calculateValidationStatus, countBySeverity, } from '@vibe-agent-toolkit/schema';
55
+ import { findProjectRoot } from '@vibe-agent-toolkit/utils';
56
+ import { Command, Option } from 'commander';
57
+ import { handleCommandError } from '../../utils/command-error.js';
58
+ import { loadConfig } from '../../utils/config-loader.js';
59
+ import { contextBudgetIssues, scopeSweepToPaths } from '../../utils/context-budget-issues.js';
60
+ import { targetPathWithin } from '../../utils/corpus-target.js';
61
+ import { resolveIssueSeverity } from '../../utils/issue-severity.js';
62
+ import { createLogger } from '../../utils/logger.js';
63
+ import { writeJsonOutput, writeStdoutSync, writeYamlOutput } from '../../utils/output.js';
64
+ import { populationWiring } from '../../utils/population-wiring.js';
65
+ import { withPopulationCache } from '../../utils/projection-store.js';
66
+ import { gitTrackerForProjectRoot } from '../audit/distributed-tree.js';
67
+ /** How this command names itself in a refusal. */
68
+ const COMMAND_NAME = 'vat claude budget';
69
+ /** Soft wrap width for the printed limit statements. */
70
+ const WRAP_COLUMNS = 96;
71
+ /**
72
+ * Create the `vat claude budget [paths...]` command.
73
+ *
74
+ * @returns The configured Commander command
75
+ */
76
+ export function createBudgetCommand() {
77
+ const command = new Command('budget');
78
+ command
79
+ .description('Check whether the always-loaded context at a working location exceeds its budget')
80
+ .argument('[paths...]', 'Directories to check, with everything beneath them (default: the whole tree)')
81
+ .addOption(new Option('--format <format>', 'Output format: text (default), yaml, or json').choices([
82
+ 'text',
83
+ 'yaml',
84
+ 'json',
85
+ ]).default('text'))
86
+ .option('--debug', 'Verbose logging to stderr')
87
+ .action(claudeBudgetCommand)
88
+ .addHelpText('after', `
89
+ Description:
90
+ Reports ALWAYS_LOADED_CONTEXT_BUDGET for each instruction chain whose
91
+ always-loaded context exceeds the budget. The measured chain is the
92
+ repo-root CLAUDE.md, every CLAUDE.md on the path down to the working
93
+ location, one level of @ imports from each, and any unscoped rules file in
94
+ the root .claude/rules/. An AGENTS.md is measured only where a CLAUDE.md
95
+ imports it (@AGENTS.md) — Claude Code does not load it by name, so a repo
96
+ standardised on AGENTS.md alone has nothing here to measure. Path-scoped
97
+ rules (a paths: list) are excluded: they load when the agent touches a
98
+ matching file, not at launch.
99
+
100
+ ONE finding per chain, not per directory: directories loading the same files
101
+ share a finding, which names how many working locations pay it. Naming paths
102
+ narrows WHICH chains are reported; the payer count stays the whole tree's,
103
+ because that is the number that was measured.
104
+
105
+ This is the CHECK. 'vat claude context' is the QUERY — same lane, no
106
+ threshold and no verdict.
107
+
108
+ Configuration (vibe-agent-toolkit.config.yaml):
109
+ resources.validation.thresholds.alwaysLoadedContextTokens moves the budget
110
+ (default ${String(DEFAULT_ALWAYS_LOADED_CONTEXT_TOKENS)}). resources.validation.severity.ALWAYS_LOADED_CONTEXT_BUDGET
111
+ silences it (ignore) or promotes it to warning/error. A project with no
112
+ config file is checked at the same default budget.
113
+
114
+ Output:
115
+ - threshold: the budget every chain was measured against
116
+ - scope/unmatchedScope: what was asked about, and what matched nothing
117
+ - status/issueCounts: the worst actionable severity, plus every severity
118
+ - workingLocations, distinctChains, skippedUnknownLocations: whole-tree
119
+ facts, so an empty findings list is legible
120
+ - findings: one per over-budget chain, ascending by directory
121
+ - limits/boundsStatement: what this verdict does not settle, signed
122
+ over-report or under-report. On the REPORT, never on a
123
+ finding — they bound the method, not any one chain, so
124
+ they are stated exactly once however many chains flag
125
+
126
+ Text to stdout by default; --format yaml|json for a program. Diagnostics
127
+ and blob-stage refusals go to stderr.
128
+
129
+ Exit Codes:
130
+ 0 - Reported (findings at the default info severity do not gate)
131
+ 1 - A finding resolved to error severity via config
132
+ 2 - System error (a path outside the corpus root, unreadable tree)
133
+
134
+ Example:
135
+ $ vat claude budget packages/cli # is it over budget where I work?
136
+ `);
137
+ return command;
138
+ }
139
+ /**
140
+ * Action handler for `vat claude budget [paths...]`.
141
+ *
142
+ * @param pathArgs - Directories to check; empty means the whole tree
143
+ * @param options - The command's flags
144
+ */
145
+ export async function claudeBudgetCommand(pathArgs, options) {
146
+ const logger = createLogger(options.debug === true ? { debug: true } : {});
147
+ const startTime = Date.now();
148
+ try {
149
+ const root = findProjectRoot(process.cwd()) ?? process.cwd();
150
+ // 🔑 Every argument is resolved BEFORE the population. A path outside the
151
+ // corpus is a usage error, and finding it afterwards would charge the caller
152
+ // a full population — minutes on a cold cache — to be told they mistyped.
153
+ const scope = scopeWithin(root, pathArgs);
154
+ const config = loadConfig(root);
155
+ const validation = config?.resources?.validation;
156
+ const threshold = validation?.thresholds?.alwaysLoadedContextTokens
157
+ ?? DEFAULT_ALWAYS_LOADED_CONTEXT_TOKENS;
158
+ const sweep = await sweepBudgets(root, threshold, logger);
159
+ const scoped = scopeSweepToPaths(sweep, scope);
160
+ // The same two shared mechanisms every other lane uses, in the same order:
161
+ // `validation.allow` suppresses by path glob, then `validation.severity`
162
+ // resolves — BOTH directions, so an adopter promoting this code to `error`
163
+ // gets an error, which is the case that gets forgotten.
164
+ const findings = resolveIssueSeverity(applyAllowFilter(contextBudgetIssues(scoped.sweep), validation ?? {}).emitted, validation);
165
+ warnUnmatched(scoped.unmatchedScope, logger);
166
+ const report = buildReport({ root, threshold, scope, sweep, scoped, findings });
167
+ emit(report, options.format ?? 'text');
168
+ // Only `error` gates. At the code's `info` default this is always 0, so the
169
+ // budget cannot fail a build unless an adopter asked it to.
170
+ process.exit(report.issueCounts.errors > 0 ? 1 : 0);
171
+ }
172
+ catch (error) {
173
+ handleCommandError(error, logger, startTime, 'claude budget');
174
+ }
175
+ }
176
+ /**
177
+ * Assemble the report from the run's parts.
178
+ *
179
+ * ⛔ The counters come from the UNSCOPED sweep. They answer "what was measured",
180
+ * and a scope changes only what is reported — sourcing them from the narrowed
181
+ * view would let `vat claude budget docs` claim the tree has one chain.
182
+ *
183
+ * ⛔ This is the ONE place the stated bounds enter the machine-readable output,
184
+ * and keeping it a single assignment is what makes "stated once" structural
185
+ * rather than a habit: there is no per-finding site left where a copy could be
186
+ * reintroduced. They are attached unconditionally — a run that flagged nothing
187
+ * used the same method, and a reader acting on "within budget" needs them most.
188
+ *
189
+ * ⛔ Exported so it can be TESTED. What has to be pinned is a COUNT — that the
190
+ * block appears exactly once across a MULTI-finding report — and a presence
191
+ * check passes identically with a copy per finding.
192
+ *
193
+ * @param input - The run's parts
194
+ * @returns The report, ready to serialize
195
+ */
196
+ export function buildReport(input) {
197
+ const { root, threshold, scope, sweep, scoped, findings } = input;
198
+ return {
199
+ root,
200
+ threshold,
201
+ scope,
202
+ unmatchedScope: scoped.unmatchedScope,
203
+ status: calculateValidationStatus(findings),
204
+ issueCounts: countBySeverity(findings),
205
+ workingLocations: sweep.evaluatedDirectories,
206
+ distinctChains: sweep.queriedDirectories,
207
+ skippedUnknownLocations: sweep.skippedUnknownLocations,
208
+ findings,
209
+ boundsStatement: CLAUDE_CONTEXT_BOUNDS_STATEMENT,
210
+ limits: ALWAYS_LOADED_BUDGET_LIMITS,
211
+ };
212
+ }
213
+ /**
214
+ * Resolve the requested scope, defaulting to the whole tree.
215
+ *
216
+ * ⚠️ No arguments means the WHOLE TREE, not the current directory — the
217
+ * opposite of `vat claude context`'s default, and deliberately so. This is a
218
+ * check: the useful bare invocation is "tell me about everything", the way a
219
+ * linter run from a subdirectory still lints the project. Naming a directory is
220
+ * how a caller asks the narrower question.
221
+ *
222
+ * @param root - The discovered project root
223
+ * @param pathArgs - The path arguments, possibly empty
224
+ * @returns Root-relative directories; `['']` for the whole tree
225
+ */
226
+ function scopeWithin(root, pathArgs) {
227
+ if (pathArgs.length === 0)
228
+ return [''];
229
+ return pathArgs.map((pathArg) => targetPathWithin(root, pathArg, COMMAND_NAME));
230
+ }
231
+ /**
232
+ * Say so, loudly, when a requested path named no working location.
233
+ *
234
+ * ⛔ `warn` (stderr), never `debug`. Such a scope produces zero findings, which
235
+ * is byte-identical to a clean bill of health — and a default run that stayed
236
+ * silent about it would publish that confusion rather than the fact behind it.
237
+ *
238
+ * @param unmatched - The requested paths that matched nothing
239
+ * @param logger - Where the warning goes
240
+ */
241
+ function warnUnmatched(unmatched, logger) {
242
+ if (unmatched.length === 0)
243
+ return;
244
+ logger.warn(`Warning: no working location matched ${unmatched.join(', ')} — nothing was checked there.`
245
+ + ' This is NOT a report that those paths are within budget.');
246
+ }
247
+ /**
248
+ * Populate the Claude-context lane for one tree and sweep every location.
249
+ *
250
+ * ⚠️ Roots at the discovered project root and NOWHERE else, whatever paths were
251
+ * named. A budget is a property of a position in the directory tree, and rooting
252
+ * a population at a subdirectory would compute one against a corpus whose
253
+ * ancestors are missing — a confidently wrong number.
254
+ *
255
+ * @param root - The absolute corpus root; the ONLY tree populated
256
+ * @param threshold - The always-loaded token budget
257
+ * @param logger - Where blob-stage refusals go. **stderr**, never stdout: this
258
+ * command's stdout is the document a caller parses
259
+ * @returns Every working location's budget
260
+ */
261
+ async function sweepBudgets(root, threshold, logger) {
262
+ const projection = await withPopulationCache({ root }, async (cache) => {
263
+ const gitTracker = await gitTrackerForProjectRoot(root);
264
+ return buildClaudeContextPopulation({ root, ...populationWiring(logger, gitTracker, cache, root) });
265
+ });
266
+ return sweepAlwaysLoadedBudgets(projection, threshold);
267
+ }
268
+ /**
269
+ * Write the report in the requested format.
270
+ *
271
+ * @param report - The report
272
+ * @param format - The selected format
273
+ */
274
+ function emit(report, format) {
275
+ if (format === 'json') {
276
+ writeJsonOutput(report);
277
+ return;
278
+ }
279
+ if (format === 'yaml') {
280
+ writeYamlOutput(report);
281
+ return;
282
+ }
283
+ writeStdoutSync(renderReportText(report));
284
+ }
285
+ /**
286
+ * Render the report for a person.
287
+ *
288
+ * ⛔ Exported so the "stated once" property can be pinned in TEXT as well as in
289
+ * json. The two renderings are separate code paths and this lane has already
290
+ * shipped a defect where they disagreed while each looked right alone.
291
+ *
292
+ * @param report - The report
293
+ * @returns The text rendering, newline-terminated
294
+ */
295
+ export function renderReportText(report) {
296
+ const lines = [
297
+ `Always-loaded context budget at ${report.root}`,
298
+ ` budget ${count(report.threshold)} tokens`
299
+ + ` · ${count(report.workingLocations)} working locations`
300
+ + ` · ${count(report.distinctChains)} distinct chains`
301
+ + ` · ${count(report.skippedUnknownLocations)} unrealized`,
302
+ '',
303
+ ...findingLines(report.findings),
304
+ ...unmatchedLines(report.unmatchedScope),
305
+ ...limitLines(report),
306
+ ];
307
+ return `${lines.join('\n')}\n`;
308
+ }
309
+ /**
310
+ * The stated bounds, printed once at the foot of the report.
311
+ *
312
+ * ⛔ Never omitted, and never per finding. A clean report is subject to exactly
313
+ * the same signed bounds as a flagged one — more so, since "within budget" is the
314
+ * verdict a reader is most likely to act on without reading further.
315
+ *
316
+ * The sibling `vat claude context` prints a section of the same shape from its
317
+ * own list. They are deliberately NOT sharing a renderer: two commands, two
318
+ * report types, and the query additionally prints the modelled-behaviour
319
+ * citations that no bound of this verdict rests on.
320
+ *
321
+ * @param report - The report carrying the bounds
322
+ * @returns The section's lines
323
+ */
324
+ function limitLines(report) {
325
+ const lines = ['What this verdict does not settle', ...wrapped(report.boundsStatement, ' '), ''];
326
+ for (const limit of report.limits) {
327
+ lines.push(` ${limit.direction}: ${limit.id}`);
328
+ lines.push(...wrapped(limit.statement, ' '));
329
+ }
330
+ return lines;
331
+ }
332
+ /**
333
+ * Soft-wrap a statement under a fixed indent.
334
+ *
335
+ * The statements run to several sentences and are the part of this output a
336
+ * reader has to actually read; unwrapped they arrive as one 500-column line that
337
+ * a terminal breaks mid-word. A word longer than the width overflows its own line
338
+ * rather than being split — no character of a statement is ever dropped.
339
+ *
340
+ * @param text - The statement
341
+ * @param indent - Leading whitespace for every produced line
342
+ * @returns One or more indented lines
343
+ */
344
+ function wrapped(text, indent) {
345
+ const width = Math.max(WRAP_COLUMNS - indent.length, 24);
346
+ const lines = [];
347
+ let pending = '';
348
+ for (const word of text.split(' ')) {
349
+ const candidate = pending === '' ? word : `${pending} ${word}`;
350
+ if (pending !== '' && candidate.length > width) {
351
+ lines.push(indent + pending);
352
+ pending = word;
353
+ }
354
+ else {
355
+ pending = candidate;
356
+ }
357
+ }
358
+ if (pending !== '')
359
+ lines.push(indent + pending);
360
+ return lines;
361
+ }
362
+ /**
363
+ * The findings, or the sentence that says there were none.
364
+ *
365
+ * ⛔ The empty case is a SENTENCE, not blank output. A command that prints
366
+ * nothing is indistinguishable from one that failed to run.
367
+ *
368
+ * @param findings - The reported findings
369
+ * @returns The lines, blank-terminated
370
+ */
371
+ function findingLines(findings) {
372
+ if (findings.length === 0)
373
+ return ['Every instruction chain checked is within budget.', ''];
374
+ const lines = [];
375
+ for (const finding of findings) {
376
+ lines.push(`${finding.severity} ${finding.code} at ${finding.location ?? '<corpus root>'}`);
377
+ lines.push(` ${finding.message}`);
378
+ if (finding.fix !== undefined)
379
+ lines.push(` Fix: ${finding.fix}`);
380
+ lines.push('');
381
+ }
382
+ return lines;
383
+ }
384
+ /**
385
+ * The unmatched-scope notice, printed in the document as well as on stderr.
386
+ *
387
+ * @param unmatched - The requested paths that matched nothing
388
+ * @returns The lines, or none
389
+ */
390
+ function unmatchedLines(unmatched) {
391
+ if (unmatched.length === 0)
392
+ return [];
393
+ return [
394
+ `Matched no working location: ${unmatched.join(', ')}`,
395
+ ' Nothing was checked there — this is not a report that they are within budget.',
396
+ '',
397
+ ];
398
+ }
399
+ /**
400
+ * A count as a reader reads it.
401
+ *
402
+ * Pinned to `en-US` rather than left to the host locale, so the same run renders
403
+ * byte-identically on two developers' machines — the same rule the findings
404
+ * themselves follow in `utils/context-budget-issues.ts`.
405
+ *
406
+ * @param value - The number
407
+ * @returns Its thousands-separated form
408
+ */
409
+ function count(value) {
410
+ return value.toLocaleString('en-US');
411
+ }
412
+ //# sourceMappingURL=budget.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"budget.js","sourceRoot":"","sources":["../../../src/commands/claude/budget.ts"],"names":[],"mappings":"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"}