@vibe-agent-toolkit/cli 0.1.41-rc.7 → 0.1.41

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 (185) hide show
  1. package/dist/bin/vat +24 -1
  2. package/dist/bin/vat.js +24 -1
  3. package/dist/bin/vat.js.map +1 -1
  4. package/dist/bin.js +23 -2
  5. package/dist/bin.js.map +1 -1
  6. package/dist/commands/agent/list.d.ts +11 -0
  7. package/dist/commands/agent/list.d.ts.map +1 -1
  8. package/dist/commands/agent/list.js +30 -11
  9. package/dist/commands/agent/list.js.map +1 -1
  10. package/dist/commands/audit/distributed-tree.d.ts +172 -0
  11. package/dist/commands/audit/distributed-tree.d.ts.map +1 -0
  12. package/dist/commands/audit/distributed-tree.js +319 -0
  13. package/dist/commands/audit/distributed-tree.js.map +1 -0
  14. package/dist/commands/audit.d.ts +69 -1
  15. package/dist/commands/audit.d.ts.map +1 -1
  16. package/dist/commands/audit.js +525 -174
  17. package/dist/commands/audit.js.map +1 -1
  18. package/dist/commands/build.d.ts +14 -0
  19. package/dist/commands/build.d.ts.map +1 -1
  20. package/dist/commands/build.js +103 -26
  21. package/dist/commands/build.js.map +1 -1
  22. package/dist/commands/claude/marketplace/git-publish.d.ts.map +1 -1
  23. package/dist/commands/claude/marketplace/git-publish.js +21 -3
  24. package/dist/commands/claude/marketplace/git-publish.js.map +1 -1
  25. package/dist/commands/claude/marketplace/validate.d.ts +125 -0
  26. package/dist/commands/claude/marketplace/validate.d.ts.map +1 -1
  27. package/dist/commands/claude/marketplace/validate.js +251 -44
  28. package/dist/commands/claude/marketplace/validate.js.map +1 -1
  29. package/dist/commands/claude/org/stubs.d.ts +9 -1
  30. package/dist/commands/claude/org/stubs.d.ts.map +1 -1
  31. package/dist/commands/claude/org/stubs.js +11 -3
  32. package/dist/commands/claude/org/stubs.js.map +1 -1
  33. package/dist/commands/claude/plugin/build.d.ts +34 -4
  34. package/dist/commands/claude/plugin/build.d.ts.map +1 -1
  35. package/dist/commands/claude/plugin/build.js +187 -16
  36. package/dist/commands/claude/plugin/build.js.map +1 -1
  37. package/dist/commands/claude/plugin/plugin-files.d.ts.map +1 -1
  38. package/dist/commands/claude/plugin/plugin-files.js +6 -2
  39. package/dist/commands/claude/plugin/plugin-files.js.map +1 -1
  40. package/dist/commands/claude/plugin/plugin-json-merge.d.ts.map +1 -1
  41. package/dist/commands/claude/plugin/plugin-json-merge.js +15 -0
  42. package/dist/commands/claude/plugin/plugin-json-merge.js.map +1 -1
  43. package/dist/commands/claude/plugin/tree-copy.d.ts +40 -0
  44. package/dist/commands/claude/plugin/tree-copy.d.ts.map +1 -1
  45. package/dist/commands/claude/plugin/tree-copy.js +100 -4
  46. package/dist/commands/claude/plugin/tree-copy.js.map +1 -1
  47. package/dist/commands/corpus/report.d.ts +22 -4
  48. package/dist/commands/corpus/report.d.ts.map +1 -1
  49. package/dist/commands/corpus/report.js +1 -0
  50. package/dist/commands/corpus/report.js.map +1 -1
  51. package/dist/commands/corpus/runner.d.ts +16 -1
  52. package/dist/commands/corpus/runner.d.ts.map +1 -1
  53. package/dist/commands/corpus/runner.js +40 -22
  54. package/dist/commands/corpus/runner.js.map +1 -1
  55. package/dist/commands/doctor.js +1 -1
  56. package/dist/commands/doctor.js.map +1 -1
  57. package/dist/commands/inventory.d.ts +2 -0
  58. package/dist/commands/inventory.d.ts.map +1 -1
  59. package/dist/commands/inventory.js +45 -4
  60. package/dist/commands/inventory.js.map +1 -1
  61. package/dist/commands/phase-utils.d.ts +183 -14
  62. package/dist/commands/phase-utils.d.ts.map +1 -1
  63. package/dist/commands/phase-utils.js +294 -29
  64. package/dist/commands/phase-utils.js.map +1 -1
  65. package/dist/commands/positional-args.d.ts +36 -0
  66. package/dist/commands/positional-args.d.ts.map +1 -0
  67. package/dist/commands/positional-args.js +52 -0
  68. package/dist/commands/positional-args.js.map +1 -0
  69. package/dist/commands/rag/query-command.d.ts +40 -0
  70. package/dist/commands/rag/query-command.d.ts.map +1 -1
  71. package/dist/commands/rag/query-command.js +47 -20
  72. package/dist/commands/rag/query-command.js.map +1 -1
  73. package/dist/commands/resources/index.d.ts.map +1 -1
  74. package/dist/commands/resources/index.js +27 -9
  75. package/dist/commands/resources/index.js.map +1 -1
  76. package/dist/commands/resources/scan.d.ts +37 -0
  77. package/dist/commands/resources/scan.d.ts.map +1 -1
  78. package/dist/commands/resources/scan.js +47 -32
  79. package/dist/commands/resources/scan.js.map +1 -1
  80. package/dist/commands/resources/validate.d.ts +136 -1
  81. package/dist/commands/resources/validate.d.ts.map +1 -1
  82. package/dist/commands/resources/validate.js +105 -66
  83. package/dist/commands/resources/validate.js.map +1 -1
  84. package/dist/commands/skill/review-checklist.d.ts.map +1 -1
  85. package/dist/commands/skill/review-checklist.js +5 -0
  86. package/dist/commands/skill/review-checklist.js.map +1 -1
  87. package/dist/commands/skill/review.d.ts.map +1 -1
  88. package/dist/commands/skill/review.js +7 -3
  89. package/dist/commands/skill/review.js.map +1 -1
  90. package/dist/commands/skill/test/run.d.ts +1 -1
  91. package/dist/commands/skill/test/run.d.ts.map +1 -1
  92. package/dist/commands/skill/test/run.js +8 -6
  93. package/dist/commands/skill/test/run.js.map +1 -1
  94. package/dist/commands/skills/build.d.ts +349 -11
  95. package/dist/commands/skills/build.d.ts.map +1 -1
  96. package/dist/commands/skills/build.js +901 -97
  97. package/dist/commands/skills/build.js.map +1 -1
  98. package/dist/commands/skills/command-helpers.d.ts +6 -10
  99. package/dist/commands/skills/command-helpers.d.ts.map +1 -1
  100. package/dist/commands/skills/command-helpers.js +6 -22
  101. package/dist/commands/skills/command-helpers.js.map +1 -1
  102. package/dist/commands/skills/list.d.ts +18 -0
  103. package/dist/commands/skills/list.d.ts.map +1 -1
  104. package/dist/commands/skills/list.js +41 -15
  105. package/dist/commands/skills/list.js.map +1 -1
  106. package/dist/commands/skills/package.d.ts +15 -0
  107. package/dist/commands/skills/package.d.ts.map +1 -1
  108. package/dist/commands/skills/package.js +30 -20
  109. package/dist/commands/skills/package.js.map +1 -1
  110. package/dist/commands/skills/scope-guard.d.ts +64 -0
  111. package/dist/commands/skills/scope-guard.d.ts.map +1 -0
  112. package/dist/commands/skills/scope-guard.js +86 -0
  113. package/dist/commands/skills/scope-guard.js.map +1 -0
  114. package/dist/commands/skills/validate-command.d.ts.map +1 -1
  115. package/dist/commands/skills/validate-command.js +41 -7
  116. package/dist/commands/skills/validate-command.js.map +1 -1
  117. package/dist/commands/skills/validate.d.ts +44 -3
  118. package/dist/commands/skills/validate.d.ts.map +1 -1
  119. package/dist/commands/skills/validate.js +217 -53
  120. package/dist/commands/skills/validate.js.map +1 -1
  121. package/dist/commands/validate.d.ts +18 -0
  122. package/dist/commands/validate.d.ts.map +1 -1
  123. package/dist/commands/validate.js +89 -68
  124. package/dist/commands/validate.js.map +1 -1
  125. package/dist/commands/verify.d.ts +113 -6
  126. package/dist/commands/verify.d.ts.map +1 -1
  127. package/dist/commands/verify.js +440 -123
  128. package/dist/commands/verify.js.map +1 -1
  129. package/dist/index.d.ts +1 -1
  130. package/dist/index.d.ts.map +1 -1
  131. package/dist/index.js +7 -1
  132. package/dist/index.js.map +1 -1
  133. package/dist/skill-resolution/index.d.ts +1 -1
  134. package/dist/skill-resolution/index.d.ts.map +1 -1
  135. package/dist/skill-resolution/index.js +1 -1
  136. package/dist/skill-resolution/index.js.map +1 -1
  137. package/dist/skill-resolution/packaging-config.d.ts +15 -2
  138. package/dist/skill-resolution/packaging-config.d.ts.map +1 -1
  139. package/dist/skill-resolution/packaging-config.js +39 -2
  140. package/dist/skill-resolution/packaging-config.js.map +1 -1
  141. package/dist/utils/command-error.d.ts +34 -1
  142. package/dist/utils/command-error.d.ts.map +1 -1
  143. package/dist/utils/command-error.js +32 -1
  144. package/dist/utils/command-error.js.map +1 -1
  145. package/dist/utils/help-loader.d.ts +6 -2
  146. package/dist/utils/help-loader.d.ts.map +1 -1
  147. package/dist/utils/help-loader.js +9 -16
  148. package/dist/utils/help-loader.js.map +1 -1
  149. package/dist/utils/issue-rendering.d.ts +130 -0
  150. package/dist/utils/issue-rendering.d.ts.map +1 -1
  151. package/dist/utils/issue-rendering.js +147 -0
  152. package/dist/utils/issue-rendering.js.map +1 -1
  153. package/dist/utils/issue-severity.d.ts +51 -0
  154. package/dist/utils/issue-severity.d.ts.map +1 -0
  155. package/dist/utils/issue-severity.js +63 -0
  156. package/dist/utils/issue-severity.js.map +1 -0
  157. package/dist/utils/output.d.ts +54 -5
  158. package/dist/utils/output.d.ts.map +1 -1
  159. package/dist/utils/output.js +111 -17
  160. package/dist/utils/output.js.map +1 -1
  161. package/dist/utils/relativize-paths.d.ts +45 -0
  162. package/dist/utils/relativize-paths.d.ts.map +1 -0
  163. package/dist/utils/relativize-paths.js +67 -0
  164. package/dist/utils/relativize-paths.js.map +1 -0
  165. package/dist/utils/resource-loader.d.ts +21 -2
  166. package/dist/utils/resource-loader.d.ts.map +1 -1
  167. package/dist/utils/resource-loader.js +85 -11
  168. package/dist/utils/resource-loader.js.map +1 -1
  169. package/dist/utils/skill-packaging-config.d.ts +22 -1
  170. package/dist/utils/skill-packaging-config.d.ts.map +1 -1
  171. package/dist/utils/skill-packaging-config.js +26 -0
  172. package/dist/utils/skill-packaging-config.js.map +1 -1
  173. package/dist/utils/verdict-helpers.d.ts +4 -3
  174. package/dist/utils/verdict-helpers.d.ts.map +1 -1
  175. package/dist/utils/verdict-helpers.js +6 -13
  176. package/dist/utils/verdict-helpers.js.map +1 -1
  177. package/dist/version.d.ts +22 -2
  178. package/dist/version.d.ts.map +1 -1
  179. package/dist/version.js +31 -2
  180. package/dist/version.js.map +1 -1
  181. package/docs/index.md +12 -0
  182. package/docs/rag.md +9 -4
  183. package/docs/resources.md +30 -14
  184. package/docs/skills.md +25 -7
  185. package/package.json +12 -12
@@ -3,9 +3,58 @@
3
3
  */
4
4
  import { spawnSync } from 'node:child_process';
5
5
  import { safePath } from '@vibe-agent-toolkit/utils';
6
+ import { Option } from 'commander';
7
+ import * as YAML from 'yaml';
6
8
  import { createLogger } from '../utils/logger.js';
9
+ import { writeYamlOutput } from '../utils/output.js';
10
+ /**
11
+ * Declare `--only` on a command that has RETIRED it, solely so the command can
12
+ * explain itself instead of emitting Commander's bare `error: unknown option
13
+ * '--only'`.
14
+ *
15
+ * This is **not** a backward-compatibility shim — the pre-1.0 policy forbids
16
+ * those and this obeys it. The flag does not work: {@link rejectRetiredOnly}
17
+ * fails the run before any phase is selected, so no caller can keep depending
18
+ * on the old behaviour. What it buys is a diagnosis. An unknown-option error
19
+ * names the flag and nothing else; the reader cannot tell a typo from a removal
20
+ * and has no way to learn what replaced it, so the next move is a bug report or
21
+ * a version pin. Naming the removal, the measurement behind it, and the command
22
+ * where `--only` still exists turns a dead end into a one-line fix.
23
+ *
24
+ * Hidden from `--help` on purpose: a retired flag is not a feature to discover,
25
+ * and listing it would suggest it still selects something.
26
+ */
27
+ export function addRetiredOnlyOption(command) {
28
+ return command.addOption(new Option('--only <phase>', 'Retired — a run is now a whole run.').hideHelp());
29
+ }
30
+ /**
31
+ * Fail the run when a caller passed the retired `--only`, naming what changed.
32
+ *
33
+ * Exit 1, matching both Commander's usage-error convention and the exit code an
34
+ * unroutable `--only` already produced on these commands, so a CI gate that was
35
+ * failing on a bad `--only` keeps failing rather than flipping to green.
36
+ *
37
+ * @param only - The parsed `--only` value; `undefined` when it was not passed.
38
+ * @param command - Command name for the message, e.g. `vat validate`.
39
+ * @param seconds - The measured full-run duration that made the flag not worth
40
+ * its coverage risk. Cited so the removal reads as a decision with evidence
41
+ * rather than a preference.
42
+ */
43
+ export function rejectRetiredOnly(only, command, seconds) {
44
+ if (only === undefined)
45
+ return;
46
+ process.stderr.write(`error: '--only' was removed from '${command}'.\n` +
47
+ `\n` +
48
+ ` A full run measures ~${seconds}s on a 90-skill project, so the flag saved\n` +
49
+ ` little while letting a CI gate silently lose coverage: renaming a config\n` +
50
+ ` key left '--only <that key>' selecting nothing, and the gate stayed green.\n` +
51
+ `\n` +
52
+ ` Fix: drop the flag — '${command}' runs every configured surface.\n` +
53
+ ` Still selective: 'vat build --only <phase>', where a phase is minutes, not seconds.\n`);
54
+ process.exit(1);
55
+ }
7
56
  /** The phase outcome for "we did not learn what this phase would have said". */
8
- const SYSTEM_ERROR = 'system-error';
57
+ export const SYSTEM_ERROR = 'system-error';
9
58
  /**
10
59
  * Resolve the absolute path to the vat binary.
11
60
  * This file lives in commands/, one level above bin/.
@@ -17,26 +66,168 @@ export function resolveBinPath() {
17
66
  return safePath.resolve(safePath.join(import.meta.dirname, '../bin.js'));
18
67
  }
19
68
  /**
20
- * Create the shared phase command context: logger, startTime, and validated bin path.
21
- * Throws if the phases list is empty (indicating an unknown --only value).
22
- *
23
- * @param debugFlag - Whether debug logging is enabled
24
- * @param phases - Pre-built list of phases to validate
25
- * @param onlyValue - The --only flag value (for the error message)
26
- * @param validPhaseNames - Human-readable list of valid phase names (for error message)
27
- * @returns Initialized phase context
28
- * @throws Error if phases list is empty
69
+ * Create the shared phase command context: logger, startTime, and bin path.
70
+ *
71
+ * It used to THROW when the phase list came out empty — and it was called
72
+ * before the command's try block, so an unroutable `--only` reached the user as
73
+ * a raw Node stack trace with zero bytes of stdout and an exit 1 that looked
74
+ * like "validation errors". `--only` routing is decided by
75
+ * {@link decidePhaseSelection} and reported by {@link applyPhaseSelection} now,
76
+ * which emit the command's normal structured document.
29
77
  */
30
- export function createPhaseContext(debugFlag, phases, onlyValue, validPhaseNames) {
31
- if (phases.length === 0) {
32
- throw new Error(`Unknown phase: ${onlyValue ?? ''}. Valid phases: ${validPhaseNames}`);
33
- }
78
+ export function createPhaseContext(debugFlag) {
34
79
  return {
35
80
  logger: createLogger(debugFlag ? { debug: true } : {}),
36
81
  startTime: Date.now(),
37
82
  binPath: resolveBinPath(),
38
83
  };
39
84
  }
85
+ /**
86
+ * Decide what an orchestrator should do with its `--only` value and the phase
87
+ * list its config produced.
88
+ *
89
+ * Shared by all three orchestrators because they used to disagree: `vat verify`
90
+ * built its phase list without consulting the config at all, so `vat verify
91
+ * --only skills` in a project with no `skills:` block exited 0 while `vat
92
+ * validate --only skills` on the same project exited 1 — opposite verdicts on
93
+ * the same question. (`vat verify` has since retired `--only` entirely and now
94
+ * always passes `only: undefined`; `vat validate` and `vat build` still route
95
+ * their own `--only` through here.)
96
+ *
97
+ * There used to be a third option, `emptyIsValid`, which existed solely so
98
+ * `vat verify --only consistency` could run with an empty SUBPROCESS list
99
+ * (consistency runs in-process). It was checked BEFORE `unreadableConfig`, so
100
+ * `vat verify --only consistency` against an unparseable config answered the
101
+ * confidently-wrong "no skills: block" instead of reporting the config error.
102
+ * `--only` is gone from verify, `emptyIsValid` went with it, and that ordering
103
+ * hazard cannot recur: nothing short-circuits ahead of the config-error arm.
104
+ *
105
+ * @param unreadableConfig - The config-load error, when the config exists but
106
+ * could not be parsed. A broken config is NOT "the phase is unconfigured":
107
+ * we do not know what it declares, so we must not answer with a confident
108
+ * "not configured". Only `vat verify` passes it, and only defensively — its
109
+ * phase builder pushes every subprocess phase when the config is unreadable
110
+ * (so the CHILD reports the real error), which makes the list non-empty and
111
+ * this arm unreachable by construction today. It is kept because the arm that
112
+ * would otherwise catch an empty list is the "not configured" lie.
113
+ */
114
+ export function decidePhaseSelection(only, phases, vocab, options = {}) {
115
+ const lower = vocab.noun.toLowerCase();
116
+ if (only !== undefined && !vocab.validNames.includes(only)) {
117
+ return {
118
+ kind: 'fail',
119
+ message: `Unknown ${lower}: ${only}. Valid ${lower}s: ${vocab.validNames.join(', ')}`,
120
+ };
121
+ }
122
+ if (phases.length > 0) {
123
+ return { kind: 'run', phases };
124
+ }
125
+ if (options.unreadableConfig !== undefined) {
126
+ return { kind: 'fail', message: options.unreadableConfig };
127
+ }
128
+ if (only !== undefined) {
129
+ return {
130
+ kind: 'fail',
131
+ message: `${vocab.noun} '${only}' is not configured in vibe-agent-toolkit.config.yaml — nothing to ${vocab.verb}.`,
132
+ };
133
+ }
134
+ return vocab.noop === undefined
135
+ ? { kind: 'fail', message: `No ${lower} to ${vocab.verb}.` }
136
+ : { kind: 'noop', ...vocab.noop };
137
+ }
138
+ /**
139
+ * Act on a {@link PhaseSelection}: return the phases to run, or emit the
140
+ * command's normal structured document and exit.
141
+ *
142
+ * Both terminal arms go through `writeYamlOutput` deliberately. A `--only`
143
+ * failure used to be an uncaught throw, so the one output a scripted caller
144
+ * parses — the YAML document on stdout — was never written at all.
145
+ */
146
+ export function applyPhaseSelection(selection, logger, startTime) {
147
+ if (selection.kind === 'run') {
148
+ return selection.phases;
149
+ }
150
+ if (selection.kind === 'fail') {
151
+ logger.error(selection.message);
152
+ writeYamlOutput({
153
+ status: 'error',
154
+ phases: [],
155
+ error: selection.message,
156
+ duration: `${Date.now() - startTime}ms`,
157
+ });
158
+ return process.exit(1);
159
+ }
160
+ logger.warn(selection.warning);
161
+ writeYamlOutput({
162
+ status: 'success',
163
+ phases: [],
164
+ note: selection.note,
165
+ duration: `${Date.now() - startTime}ms`,
166
+ });
167
+ return process.exit(0);
168
+ }
169
+ /** Rank used by {@link worseOf}: later wins. */
170
+ const PHASE_STATUS_ORDER = ['success', 'warning', 'error', 'system-error'];
171
+ /** The worse of two phase statuses, per {@link PHASE_STATUS_ORDER}. */
172
+ export function worseOf(a, b) {
173
+ return PHASE_STATUS_ORDER.indexOf(b) > PHASE_STATUS_ORDER.indexOf(a) ? b : a;
174
+ }
175
+ /** Every value a child may legitimately report as its own `status`. */
176
+ const REPORTABLE_STATUSES = new Set(PHASE_STATUS_ORDER);
177
+ /**
178
+ * Parse the child's captured stdout into its reported document.
179
+ *
180
+ * Takes the LAST non-empty document in the stream: every orchestrated child
181
+ * writes its summary last, and a child that happens to emit more than one
182
+ * document must not make the summary unreadable.
183
+ *
184
+ * Empty stdout is NOT a failure — `vat skills validate` legitimately exits 0
185
+ * printing nothing when there is no `skills:` block. Stdout that exists but
186
+ * cannot be parsed IS a failure: the child crashed mid-answer, and the phase
187
+ * must degrade to `system-error` rather than throw an unhandled exception out
188
+ * of the orchestrator.
189
+ */
190
+ function parseChildReport(name, stdout) {
191
+ if (stdout === undefined || stdout === null || stdout.trim() === '') {
192
+ return {};
193
+ }
194
+ let documents;
195
+ try {
196
+ documents = YAML.parseAllDocuments(stdout);
197
+ }
198
+ catch (error) {
199
+ return { parseError: unparseableMessage(name, error) };
200
+ }
201
+ const last = documents.findLast((doc) => doc.contents !== null);
202
+ if (last === undefined) {
203
+ return {};
204
+ }
205
+ if (last.errors.length > 0) {
206
+ return { parseError: unparseableMessage(name, last.errors[0]) };
207
+ }
208
+ return { report: last.toJS() };
209
+ }
210
+ function unparseableMessage(name, cause) {
211
+ const detail = cause instanceof Error ? cause.message : String(cause);
212
+ return `Phase '${name}' wrote unparseable output on stdout: ${detail}`;
213
+ }
214
+ /** The status an exit code alone implies, before the child's report is read. */
215
+ function statusFromExitCode(status) {
216
+ if (status === 0)
217
+ return 'success';
218
+ if (status === 1)
219
+ return 'error';
220
+ return SYSTEM_ERROR;
221
+ }
222
+ /** The status the child claimed for itself, when it claimed a recognized one. */
223
+ function statusFromReport(report) {
224
+ if (typeof report !== 'object' || report === null)
225
+ return undefined;
226
+ const claimed = report.status;
227
+ return typeof claimed === 'string' && REPORTABLE_STATUSES.has(claimed)
228
+ ? claimed
229
+ : undefined;
230
+ }
40
231
  /**
41
232
  * Map a spawn outcome to a phase outcome. The pure core of {@link runPhase}.
42
233
  *
@@ -48,9 +239,16 @@ export function createPhaseContext(debugFlag, phases, onlyValue, validPhaseNames
48
239
  * | `error` set | `system-error` | the child never ran |
49
240
  * | killed by a signal | `system-error` | the child was cut off mid-answer |
50
241
  * | no exit code, no signal | `system-error` | there is no answer to read |
242
+ * | stdout not parseable | `system-error` | the child's answer cannot be read |
51
243
  * | exit 0 | `success` | ran, found nothing actionable |
52
244
  * | exit 1 | `error` | ran, found validation errors |
53
245
  * | exit 2 (or any other) | `system-error` | the child itself reported a system error |
246
+ *
247
+ * The exit code is then reconciled with the child's OWN reported `status`,
248
+ * worst-wins. An exit code has three values and cannot express `warning`, so
249
+ * `vat skills validate` — which exits 0 while reporting `status: warning` —
250
+ * was being recorded as `success` by every orchestrator, including the one
251
+ * VAT's CI dogfoods on VAT itself.
54
252
  */
55
253
  export function phaseResultFromSpawn(name, outcome) {
56
254
  if (outcome.error !== undefined) {
@@ -67,30 +265,53 @@ export function phaseResultFromSpawn(name, outcome) {
67
265
  if (outcome.status === null) {
68
266
  return { name, status: SYSTEM_ERROR, error: `Phase '${name}' exited without a status code` };
69
267
  }
70
- if (outcome.status === 0) {
71
- return { name, status: 'success', exitCode: 0 };
72
- }
73
- if (outcome.status === 1) {
74
- return { name, status: 'error', exitCode: 1 };
268
+ const exitCode = outcome.status;
269
+ const { report, parseError } = parseChildReport(name, outcome.stdout);
270
+ if (parseError !== undefined) {
271
+ return { name, status: SYSTEM_ERROR, exitCode, error: parseError };
75
272
  }
273
+ const exitStatus = statusFromExitCode(exitCode);
274
+ const reported = statusFromReport(report);
275
+ const status = reported === undefined ? exitStatus : worseOf(exitStatus, reported);
76
276
  return {
77
277
  name,
78
- status: SYSTEM_ERROR,
79
- exitCode: outcome.status,
80
- error: `Phase '${name}' exited with system-error code ${outcome.status}`,
278
+ status,
279
+ exitCode,
280
+ ...(exitStatus === SYSTEM_ERROR
281
+ ? { error: `Phase '${name}' exited with system-error code ${exitCode}` }
282
+ : {}),
283
+ ...(report === undefined ? {} : { report }),
81
284
  };
82
285
  }
286
+ /**
287
+ * Cap on a captured child document, well above the ~2.3 MB a large real project
288
+ * produces. spawnSync's 1 MB default would set ENOBUFS and hand back a
289
+ * TRUNCATED (and therefore unparseable) document; exceeding this cap surfaces
290
+ * as a loud `system-error`, never as a silently shortened report.
291
+ */
292
+ const MAX_PHASE_STDOUT_BYTES = 256 * 1024 * 1024;
83
293
  /**
84
294
  * Run a single phase by spawning the vat binary with the phase args.
295
+ *
296
+ * stdout is CAPTURED, not inherited: the child's YAML document belongs in this
297
+ * phase's `report`, and letting it stream onto the parent's stdout is what made
298
+ * `vat validate`'s output a run of documents with no `---` between them.
299
+ * stderr stays inherited — progress output is on stderr by design and must keep
300
+ * streaming live rather than arriving in one lump at the end.
85
301
  */
86
302
  export function runPhase(binPath, phase) {
87
303
  const result = spawnSync(process.execPath, [binPath, ...phase.args], {
88
- stdio: ['inherit', 'inherit', 'inherit'],
304
+ stdio: ['inherit', 'pipe', 'inherit'],
305
+ encoding: 'utf8',
306
+ maxBuffer: MAX_PHASE_STDOUT_BYTES,
307
+ });
308
+ return phaseResultFromSpawn(phase.name, {
309
+ status: result.status,
310
+ signal: result.signal,
311
+ error: result.error,
312
+ stdout: result.stdout,
89
313
  });
90
- return phaseResultFromSpawn(phase.name, result);
91
314
  }
92
- /** Rank used by {@link aggregatePhaseStatus}: later wins. */
93
- const PHASE_STATUS_ORDER = ['success', 'warning', 'error', 'system-error'];
94
315
  /**
95
316
  * Worst-wins aggregate across phases. `system-error` outranks `error`: "we could
96
317
  * not determine the answer" must never be filed under "we determined it is bad".
@@ -98,12 +319,56 @@ const PHASE_STATUS_ORDER = ['success', 'warning', 'error', 'system-error'];
98
319
  export function aggregatePhaseStatus(results) {
99
320
  let worst = 'success';
100
321
  for (const { status } of results) {
101
- if (PHASE_STATUS_ORDER.indexOf(status) > PHASE_STATUS_ORDER.indexOf(worst)) {
102
- worst = status;
103
- }
322
+ worst = worseOf(worst, status);
104
323
  }
105
324
  return worst;
106
325
  }
326
+ /**
327
+ * One phase's per-severity distribution, wherever that phase keeps it.
328
+ *
329
+ * An in-process phase holds its own findings and publishes {@link
330
+ * PhaseResult.issueCounts}. A subprocess phase deliberately does not — the child
331
+ * owns its findings, and its document rides verbatim in {@link
332
+ * PhaseResult.report}. Reading only the former is why an orchestrator's header
333
+ * could report `{0, 0, 0}` over children that had just reported 12 warnings.
334
+ *
335
+ * Absent or malformed counts read as zero rather than throwing: a phase that
336
+ * published no distribution contributes nothing to the total, which is the same
337
+ * answer as before this function existed — just no longer the answer for phases
338
+ * that DID publish one.
339
+ */
340
+ export function phaseIssueCounts(result) {
341
+ if (result.issueCounts)
342
+ return result.issueCounts;
343
+ const counts = result.report?.issueCounts;
344
+ if (typeof counts !== 'object' || counts === null)
345
+ return { errors: 0, warnings: 0, info: 0 };
346
+ const { errors, warnings, info } = counts;
347
+ return {
348
+ errors: typeof errors === 'number' ? errors : 0,
349
+ warnings: typeof warnings === 'number' ? warnings : 0,
350
+ info: typeof info === 'number' ? info : 0,
351
+ };
352
+ }
353
+ /**
354
+ * Sum every phase's distribution, so an orchestrator's header total reconciles
355
+ * against the phases printed beneath it.
356
+ *
357
+ * The companion to {@link aggregatePhaseStatus}: status has always been
358
+ * worst-wins ACROSS phases, and a header whose `status` can see the children
359
+ * while its `issueCounts` cannot is the same contradiction in one document —
360
+ * `status: warning` beside `warnings: 0`.
361
+ */
362
+ export function aggregatePhaseIssueCounts(results) {
363
+ const total = { errors: 0, warnings: 0, info: 0 };
364
+ for (const result of results) {
365
+ const { errors, warnings, info } = phaseIssueCounts(result);
366
+ total.errors += errors;
367
+ total.warnings += warnings;
368
+ total.info += info;
369
+ }
370
+ return total;
371
+ }
107
372
  /**
108
373
  * The process exit code for a set of phase outcomes, per the exit-code contract
109
374
  * every orchestrator's help text documents: 0 pass, 1 validation failure,
@@ -1 +1 @@
1
- {"version":3,"file":"phase-utils.js","sourceRoot":"","sources":["../../src/commands/phase-utils.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"phase-utils.js","sourceRoot":"","sources":["../../src/commands/phase-utils.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,36 @@
1
+ /**
2
+ * Rejection of positional arguments on commands that take none.
3
+ *
4
+ * Shared by the config-driven top-level orchestrators (`vat verify`,
5
+ * `vat validate`), which operate on the whole project as the config describes
6
+ * it and have no path-shaped subject at all.
7
+ */
8
+ /**
9
+ * Fail the run when a caller passed a positional argument to a command that
10
+ * takes none, naming the argument and where to take it instead.
11
+ *
12
+ * **Why this is not `.allowExcessArguments(false)`.** That is the Commander
13
+ * mechanism for the same rejection and it would work, but its message is
14
+ * `error: too many arguments for 'verify'. Expected 0 arguments but got 1.` —
15
+ * which tells the reader the argument was wrong without telling them what the
16
+ * command DOES operate on or where a path is accepted, so the next move is a
17
+ * guess. The whole point of this fix is diagnosability, so the message is
18
+ * written by hand and this rejection runs first in the action instead.
19
+ *
20
+ * **Why exit 2, not Commander's usage-error 1.** On both of these commands exit
21
+ * 1 is documented as "validation errors found". A usage error reported as 1
22
+ * tells a CI gate the project's artifacts are broken when in fact nothing was
23
+ * inspected — a different wrong answer to the same question, not a fix. Exit 2
24
+ * is this repo's "the run could not tell you anything about your artifacts",
25
+ * which is exactly true here. (It therefore diverges from `rejectRetiredOnly`,
26
+ * which chose 1 to keep a pre-existing failing CI gate failing; there is no
27
+ * such continuity to preserve for an argument that used to be *accepted*.)
28
+ *
29
+ * @param operands - The command's parsed positional operands (`command.args`).
30
+ * @param command - Command name for the message, e.g. `vat verify`.
31
+ * @param operatesOn - One clause completing "<command> …", saying what the
32
+ * command actually runs against, so the reader learns why a path is
33
+ * meaningless rather than merely that it was refused.
34
+ */
35
+ export declare function rejectPositionalArguments(operands: readonly string[], command: string, operatesOn: string): void;
36
+ //# sourceMappingURL=positional-args.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"positional-args.d.ts","sourceRoot":"","sources":["../../src/commands/positional-args.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAEH;;;;;;;;;;;;;;;;;;;;;;;;;;GA0BG;AACH,wBAAgB,yBAAyB,CACvC,QAAQ,EAAE,SAAS,MAAM,EAAE,EAC3B,OAAO,EAAE,MAAM,EACf,UAAU,EAAE,MAAM,GACjB,IAAI,CAmBN"}
@@ -0,0 +1,52 @@
1
+ /**
2
+ * Rejection of positional arguments on commands that take none.
3
+ *
4
+ * Shared by the config-driven top-level orchestrators (`vat verify`,
5
+ * `vat validate`), which operate on the whole project as the config describes
6
+ * it and have no path-shaped subject at all.
7
+ */
8
+ /**
9
+ * Fail the run when a caller passed a positional argument to a command that
10
+ * takes none, naming the argument and where to take it instead.
11
+ *
12
+ * **Why this is not `.allowExcessArguments(false)`.** That is the Commander
13
+ * mechanism for the same rejection and it would work, but its message is
14
+ * `error: too many arguments for 'verify'. Expected 0 arguments but got 1.` —
15
+ * which tells the reader the argument was wrong without telling them what the
16
+ * command DOES operate on or where a path is accepted, so the next move is a
17
+ * guess. The whole point of this fix is diagnosability, so the message is
18
+ * written by hand and this rejection runs first in the action instead.
19
+ *
20
+ * **Why exit 2, not Commander's usage-error 1.** On both of these commands exit
21
+ * 1 is documented as "validation errors found". A usage error reported as 1
22
+ * tells a CI gate the project's artifacts are broken when in fact nothing was
23
+ * inspected — a different wrong answer to the same question, not a fix. Exit 2
24
+ * is this repo's "the run could not tell you anything about your artifacts",
25
+ * which is exactly true here. (It therefore diverges from `rejectRetiredOnly`,
26
+ * which chose 1 to keep a pre-existing failing CI gate failing; there is no
27
+ * such continuity to preserve for an argument that used to be *accepted*.)
28
+ *
29
+ * @param operands - The command's parsed positional operands (`command.args`).
30
+ * @param command - Command name for the message, e.g. `vat verify`.
31
+ * @param operatesOn - One clause completing "<command> …", saying what the
32
+ * command actually runs against, so the reader learns why a path is
33
+ * meaningless rather than merely that it was refused.
34
+ */
35
+ export function rejectPositionalArguments(operands, command, operatesOn) {
36
+ if (operands.length === 0)
37
+ return;
38
+ const listed = operands.map((operand) => `'${operand}'`).join(', ');
39
+ process.stderr.write(`error: '${command}' does not take a path argument (got: ${listed}).\n` +
40
+ `\n` +
41
+ ` '${command}' ${operatesOn}, so there is nothing for a path to scope.\n` +
42
+ ` The argument used to be accepted and silently DISCARDED: the run went\n` +
43
+ ` wide over the whole project and still reported success, so an operator\n` +
44
+ ` who believed they had scoped the scan got a green tick for a scan that\n` +
45
+ ` never happened.\n` +
46
+ `\n` +
47
+ ` Fix: run '${command}' with no arguments, and scope it in\n` +
48
+ ` vibe-agent-toolkit.config.yaml.\n` +
49
+ ` To inspect ONE skill or bundle by path, use: vat audit <path>\n`);
50
+ process.exit(2);
51
+ }
52
+ //# sourceMappingURL=positional-args.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"positional-args.js","sourceRoot":"","sources":["../../src/commands/positional-args.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAEH;;;;;;;;;;;;;;;;;;;;;;;;;;GA0BG;AACH,MAAM,UAAU,yBAAyB,CACvC,QAA2B,EAC3B,OAAe,EACf,UAAkB;IAElB,IAAI,QAAQ,CAAC,MAAM,KAAK,CAAC;QAAE,OAAO;IAElC,MAAM,MAAM,GAAG,QAAQ,CAAC,GAAG,CAAC,CAAC,OAAO,EAAE,EAAE,CAAC,IAAI,OAAO,GAAG,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;IAEpE,OAAO,CAAC,MAAM,CAAC,KAAK,CAClB,WAAW,OAAO,yCAAyC,MAAM,MAAM;QACrE,IAAI;QACJ,MAAM,OAAO,KAAK,UAAU,8CAA8C;QAC1E,2EAA2E;QAC3E,4EAA4E;QAC5E,4EAA4E;QAC5E,qBAAqB;QACrB,IAAI;QACJ,eAAe,OAAO,wCAAwC;QAC9D,qCAAqC;QACrC,mEAAmE,CACtE,CAAC;IACF,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;AAClB,CAAC"}
@@ -6,6 +6,46 @@ interface QueryOptions {
6
6
  limit?: number;
7
7
  debug?: boolean;
8
8
  }
9
+ /** The chunk fields this payload republishes. Structural, so tests can pass a literal. */
10
+ interface QueriedChunk {
11
+ chunkId: string;
12
+ resourceId: string;
13
+ filePath: string;
14
+ headingPath?: string | undefined;
15
+ headingLevel?: number | undefined;
16
+ startLine?: number | undefined;
17
+ endLine?: number | undefined;
18
+ title?: string | undefined;
19
+ type?: string | undefined;
20
+ tags?: string[] | undefined;
21
+ contentHash: string;
22
+ tokenCount: number;
23
+ embeddingModel: string;
24
+ embeddedAt: Date;
25
+ previousChunkId?: string | undefined;
26
+ nextChunkId?: string | undefined;
27
+ content: string;
28
+ }
29
+ export interface QueryPayloadInput {
30
+ queryText: string;
31
+ chunks: readonly QueriedChunk[];
32
+ stats: unknown;
33
+ durationMs: number;
34
+ /** The stated root: the ONE base every reported path is relative to. */
35
+ root: string;
36
+ }
37
+ /**
38
+ * Build the query payload.
39
+ *
40
+ * `resourceId` is already relative — the registry derives it from the indexing
41
+ * base — so an absolute `filePath` one line above it put a single record in two
42
+ * coordinate systems, and leaked `$HOME` into every result. Re-basing happens
43
+ * once, here, so both identifiers read the same way.
44
+ *
45
+ * Fields are ordered deliberately: short ones first, `content` last, so a long
46
+ * result stays scannable.
47
+ */
48
+ export declare function buildQueryOutputData(input: QueryPayloadInput): Record<string, unknown>;
9
49
  export declare function queryCommand(queryText: string, options: QueryOptions): Promise<void>;
10
50
  export {};
11
51
  //# sourceMappingURL=query-command.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"query-command.d.ts","sourceRoot":"","sources":["../../../src/commands/rag/query-command.ts"],"names":[],"mappings":"AAAA;;GAEG;AAMH,UAAU,YAAY;IACpB,EAAE,CAAC,EAAE,MAAM,CAAC;IACZ,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,KAAK,CAAC,EAAE,OAAO,CAAC;CACjB;AAED,wBAAsB,YAAY,CAChC,SAAS,EAAE,MAAM,EACjB,OAAO,EAAE,YAAY,GACpB,OAAO,CAAC,IAAI,CAAC,CA+Df"}
1
+ {"version":3,"file":"query-command.d.ts","sourceRoot":"","sources":["../../../src/commands/rag/query-command.ts"],"names":[],"mappings":"AAAA;;GAEG;AAUH,UAAU,YAAY;IACpB,EAAE,CAAC,EAAE,MAAM,CAAC;IACZ,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,KAAK,CAAC,EAAE,OAAO,CAAC;CACjB;AAED,0FAA0F;AAC1F,UAAU,YAAY;IACpB,OAAO,EAAE,MAAM,CAAC;IAChB,UAAU,EAAE,MAAM,CAAC;IACnB,QAAQ,EAAE,MAAM,CAAC;IACjB,WAAW,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;IACjC,YAAY,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;IAClC,SAAS,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;IAC/B,OAAO,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;IAC7B,KAAK,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;IAC3B,IAAI,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;IAC1B,IAAI,CAAC,EAAE,MAAM,EAAE,GAAG,SAAS,CAAC;IAC5B,WAAW,EAAE,MAAM,CAAC;IACpB,UAAU,EAAE,MAAM,CAAC;IACnB,cAAc,EAAE,MAAM,CAAC;IACvB,UAAU,EAAE,IAAI,CAAC;IACjB,eAAe,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;IACrC,WAAW,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;IACjC,OAAO,EAAE,MAAM,CAAC;CACjB;AAED,MAAM,WAAW,iBAAiB;IAChC,SAAS,EAAE,MAAM,CAAC;IAClB,MAAM,EAAE,SAAS,YAAY,EAAE,CAAC;IAChC,KAAK,EAAE,OAAO,CAAC;IACf,UAAU,EAAE,MAAM,CAAC;IACnB,wEAAwE;IACxE,IAAI,EAAE,MAAM,CAAC;CACd;AAED;;;;;;;;;;GAUG;AACH,wBAAgB,oBAAoB,CAAC,KAAK,EAAE,iBAAiB,GAAG,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CA2CtF;AAED,wBAAsB,YAAY,CAChC,SAAS,EAAE,MAAM,EACjB,OAAO,EAAE,YAAY,GACpB,OAAO,CAAC,IAAI,CAAC,CAmCf"}
@@ -1,27 +1,30 @@
1
1
  /**
2
2
  * RAG query command - search the vector database
3
3
  */
4
+ import { safePath } from '@vibe-agent-toolkit/utils';
4
5
  import { writeYamlOutput } from '../../utils/output.js';
6
+ import { projectRootOrNull } from '../../utils/project-root-policy.js';
7
+ import { relativizePath } from '../../utils/relativize-paths.js';
5
8
  import { executeRagOperation, formatDuration } from './command-helpers.js';
6
- export async function queryCommand(queryText, options) {
7
- const startTime = Date.now();
8
- const result = await executeRagOperation(options, async (ragProvider, logger) => {
9
- logger.debug(`Querying for: "${queryText}"`);
10
- // Execute query
11
- const queryResult = await ragProvider.query({
12
- text: queryText,
13
- limit: options.limit ?? 10,
14
- });
15
- return queryResult;
16
- }, 'Query');
17
- const duration = Date.now() - startTime;
18
- // Format chunks with explicit field order: short fields first, content last
19
- const formattedChunks = result.chunks.map((chunk) => ({
9
+ /**
10
+ * Build the query payload.
11
+ *
12
+ * `resourceId` is already relative — the registry derives it from the indexing
13
+ * base — so an absolute `filePath` one line above it put a single record in two
14
+ * coordinate systems, and leaked `$HOME` into every result. Re-basing happens
15
+ * once, here, so both identifiers read the same way.
16
+ *
17
+ * Fields are ordered deliberately: short ones first, `content` last, so a long
18
+ * result stays scannable.
19
+ */
20
+ export function buildQueryOutputData(input) {
21
+ const { queryText, chunks, stats, durationMs, root } = input;
22
+ const formattedChunks = chunks.map((chunk) => ({
20
23
  // Identifiers
21
24
  chunkId: chunk.chunkId,
22
25
  resourceId: chunk.resourceId,
23
26
  // Location metadata (short)
24
- filePath: chunk.filePath,
27
+ filePath: relativizePath(chunk.filePath, root),
25
28
  ...(chunk.headingPath ? { headingPath: chunk.headingPath } : {}),
26
29
  ...(chunk.headingLevel === undefined ? {} : { headingLevel: chunk.headingLevel }),
27
30
  ...(chunk.startLine === undefined ? {} : { startLine: chunk.startLine }),
@@ -41,14 +44,38 @@ export async function queryCommand(queryText, options) {
41
44
  // Content (long, last)
42
45
  content: chunk.content,
43
46
  }));
44
- // Output with stats/duration before chunks (short fields first)
45
- writeYamlOutput({
47
+ // Stats/duration before chunks (short fields first)
48
+ return {
46
49
  status: 'success',
50
+ root,
47
51
  query: queryText,
48
- stats: result.stats,
49
- duration: formatDuration(duration),
52
+ stats,
53
+ duration: formatDuration(durationMs),
50
54
  chunks: formattedChunks,
51
- });
55
+ };
56
+ }
57
+ export async function queryCommand(queryText, options) {
58
+ const startTime = Date.now();
59
+ const result = await executeRagOperation(options, async (ragProvider, logger) => {
60
+ logger.debug(`Querying for: "${queryText}"`);
61
+ // Execute query
62
+ const queryResult = await ragProvider.query({
63
+ text: queryText,
64
+ limit: options.limit ?? 10,
65
+ });
66
+ return queryResult;
67
+ }, 'Query');
68
+ // The index lives under the project (`<projectRoot>/.rag-db` by default) and
69
+ // its `resourceId`s are already project-relative, so projectRoot is the base
70
+ // that puts `filePath` in the same coordinate system.
71
+ const root = projectRootOrNull(process.cwd()) ?? safePath.resolve(process.cwd());
72
+ writeYamlOutput(buildQueryOutputData({
73
+ queryText,
74
+ chunks: result.chunks,
75
+ stats: result.stats,
76
+ durationMs: Date.now() - startTime,
77
+ root,
78
+ }));
52
79
  process.exit(0);
53
80
  }
54
81
  //# sourceMappingURL=query-command.js.map