@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.
- package/dist/bin/vat +24 -1
- package/dist/bin/vat.js +24 -1
- package/dist/bin/vat.js.map +1 -1
- package/dist/bin.js +23 -2
- package/dist/bin.js.map +1 -1
- package/dist/commands/agent/list.d.ts +11 -0
- package/dist/commands/agent/list.d.ts.map +1 -1
- package/dist/commands/agent/list.js +30 -11
- package/dist/commands/agent/list.js.map +1 -1
- package/dist/commands/audit/distributed-tree.d.ts +172 -0
- package/dist/commands/audit/distributed-tree.d.ts.map +1 -0
- package/dist/commands/audit/distributed-tree.js +319 -0
- package/dist/commands/audit/distributed-tree.js.map +1 -0
- package/dist/commands/audit.d.ts +69 -1
- package/dist/commands/audit.d.ts.map +1 -1
- package/dist/commands/audit.js +525 -174
- package/dist/commands/audit.js.map +1 -1
- package/dist/commands/build.d.ts +14 -0
- package/dist/commands/build.d.ts.map +1 -1
- package/dist/commands/build.js +103 -26
- package/dist/commands/build.js.map +1 -1
- package/dist/commands/claude/marketplace/git-publish.d.ts.map +1 -1
- package/dist/commands/claude/marketplace/git-publish.js +21 -3
- package/dist/commands/claude/marketplace/git-publish.js.map +1 -1
- package/dist/commands/claude/marketplace/validate.d.ts +125 -0
- package/dist/commands/claude/marketplace/validate.d.ts.map +1 -1
- package/dist/commands/claude/marketplace/validate.js +251 -44
- package/dist/commands/claude/marketplace/validate.js.map +1 -1
- package/dist/commands/claude/org/stubs.d.ts +9 -1
- package/dist/commands/claude/org/stubs.d.ts.map +1 -1
- package/dist/commands/claude/org/stubs.js +11 -3
- package/dist/commands/claude/org/stubs.js.map +1 -1
- package/dist/commands/claude/plugin/build.d.ts +34 -4
- package/dist/commands/claude/plugin/build.d.ts.map +1 -1
- package/dist/commands/claude/plugin/build.js +187 -16
- package/dist/commands/claude/plugin/build.js.map +1 -1
- package/dist/commands/claude/plugin/plugin-files.d.ts.map +1 -1
- package/dist/commands/claude/plugin/plugin-files.js +6 -2
- package/dist/commands/claude/plugin/plugin-files.js.map +1 -1
- package/dist/commands/claude/plugin/plugin-json-merge.d.ts.map +1 -1
- package/dist/commands/claude/plugin/plugin-json-merge.js +15 -0
- package/dist/commands/claude/plugin/plugin-json-merge.js.map +1 -1
- package/dist/commands/claude/plugin/tree-copy.d.ts +40 -0
- package/dist/commands/claude/plugin/tree-copy.d.ts.map +1 -1
- package/dist/commands/claude/plugin/tree-copy.js +100 -4
- package/dist/commands/claude/plugin/tree-copy.js.map +1 -1
- package/dist/commands/corpus/report.d.ts +22 -4
- package/dist/commands/corpus/report.d.ts.map +1 -1
- package/dist/commands/corpus/report.js +1 -0
- package/dist/commands/corpus/report.js.map +1 -1
- package/dist/commands/corpus/runner.d.ts +16 -1
- package/dist/commands/corpus/runner.d.ts.map +1 -1
- package/dist/commands/corpus/runner.js +40 -22
- package/dist/commands/corpus/runner.js.map +1 -1
- package/dist/commands/doctor.js +1 -1
- package/dist/commands/doctor.js.map +1 -1
- package/dist/commands/inventory.d.ts +2 -0
- package/dist/commands/inventory.d.ts.map +1 -1
- package/dist/commands/inventory.js +45 -4
- package/dist/commands/inventory.js.map +1 -1
- package/dist/commands/phase-utils.d.ts +183 -14
- package/dist/commands/phase-utils.d.ts.map +1 -1
- package/dist/commands/phase-utils.js +294 -29
- package/dist/commands/phase-utils.js.map +1 -1
- package/dist/commands/positional-args.d.ts +36 -0
- package/dist/commands/positional-args.d.ts.map +1 -0
- package/dist/commands/positional-args.js +52 -0
- package/dist/commands/positional-args.js.map +1 -0
- package/dist/commands/rag/query-command.d.ts +40 -0
- package/dist/commands/rag/query-command.d.ts.map +1 -1
- package/dist/commands/rag/query-command.js +47 -20
- package/dist/commands/rag/query-command.js.map +1 -1
- package/dist/commands/resources/index.d.ts.map +1 -1
- package/dist/commands/resources/index.js +27 -9
- package/dist/commands/resources/index.js.map +1 -1
- package/dist/commands/resources/scan.d.ts +37 -0
- package/dist/commands/resources/scan.d.ts.map +1 -1
- package/dist/commands/resources/scan.js +47 -32
- package/dist/commands/resources/scan.js.map +1 -1
- package/dist/commands/resources/validate.d.ts +136 -1
- package/dist/commands/resources/validate.d.ts.map +1 -1
- package/dist/commands/resources/validate.js +105 -66
- package/dist/commands/resources/validate.js.map +1 -1
- package/dist/commands/skill/review-checklist.d.ts.map +1 -1
- package/dist/commands/skill/review-checklist.js +5 -0
- package/dist/commands/skill/review-checklist.js.map +1 -1
- package/dist/commands/skill/review.d.ts.map +1 -1
- package/dist/commands/skill/review.js +7 -3
- package/dist/commands/skill/review.js.map +1 -1
- package/dist/commands/skill/test/run.d.ts +1 -1
- package/dist/commands/skill/test/run.d.ts.map +1 -1
- package/dist/commands/skill/test/run.js +8 -6
- package/dist/commands/skill/test/run.js.map +1 -1
- package/dist/commands/skills/build.d.ts +349 -11
- package/dist/commands/skills/build.d.ts.map +1 -1
- package/dist/commands/skills/build.js +901 -97
- package/dist/commands/skills/build.js.map +1 -1
- package/dist/commands/skills/command-helpers.d.ts +6 -10
- package/dist/commands/skills/command-helpers.d.ts.map +1 -1
- package/dist/commands/skills/command-helpers.js +6 -22
- package/dist/commands/skills/command-helpers.js.map +1 -1
- package/dist/commands/skills/list.d.ts +18 -0
- package/dist/commands/skills/list.d.ts.map +1 -1
- package/dist/commands/skills/list.js +41 -15
- package/dist/commands/skills/list.js.map +1 -1
- package/dist/commands/skills/package.d.ts +15 -0
- package/dist/commands/skills/package.d.ts.map +1 -1
- package/dist/commands/skills/package.js +30 -20
- package/dist/commands/skills/package.js.map +1 -1
- package/dist/commands/skills/scope-guard.d.ts +64 -0
- package/dist/commands/skills/scope-guard.d.ts.map +1 -0
- package/dist/commands/skills/scope-guard.js +86 -0
- package/dist/commands/skills/scope-guard.js.map +1 -0
- package/dist/commands/skills/validate-command.d.ts.map +1 -1
- package/dist/commands/skills/validate-command.js +41 -7
- package/dist/commands/skills/validate-command.js.map +1 -1
- package/dist/commands/skills/validate.d.ts +44 -3
- package/dist/commands/skills/validate.d.ts.map +1 -1
- package/dist/commands/skills/validate.js +217 -53
- package/dist/commands/skills/validate.js.map +1 -1
- package/dist/commands/validate.d.ts +18 -0
- package/dist/commands/validate.d.ts.map +1 -1
- package/dist/commands/validate.js +89 -68
- package/dist/commands/validate.js.map +1 -1
- package/dist/commands/verify.d.ts +113 -6
- package/dist/commands/verify.d.ts.map +1 -1
- package/dist/commands/verify.js +440 -123
- package/dist/commands/verify.js.map +1 -1
- package/dist/index.d.ts +1 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +7 -1
- package/dist/index.js.map +1 -1
- package/dist/skill-resolution/index.d.ts +1 -1
- package/dist/skill-resolution/index.d.ts.map +1 -1
- package/dist/skill-resolution/index.js +1 -1
- package/dist/skill-resolution/index.js.map +1 -1
- package/dist/skill-resolution/packaging-config.d.ts +15 -2
- package/dist/skill-resolution/packaging-config.d.ts.map +1 -1
- package/dist/skill-resolution/packaging-config.js +39 -2
- package/dist/skill-resolution/packaging-config.js.map +1 -1
- package/dist/utils/command-error.d.ts +34 -1
- package/dist/utils/command-error.d.ts.map +1 -1
- package/dist/utils/command-error.js +32 -1
- package/dist/utils/command-error.js.map +1 -1
- package/dist/utils/help-loader.d.ts +6 -2
- package/dist/utils/help-loader.d.ts.map +1 -1
- package/dist/utils/help-loader.js +9 -16
- package/dist/utils/help-loader.js.map +1 -1
- package/dist/utils/issue-rendering.d.ts +130 -0
- package/dist/utils/issue-rendering.d.ts.map +1 -1
- package/dist/utils/issue-rendering.js +147 -0
- package/dist/utils/issue-rendering.js.map +1 -1
- package/dist/utils/issue-severity.d.ts +51 -0
- package/dist/utils/issue-severity.d.ts.map +1 -0
- package/dist/utils/issue-severity.js +63 -0
- package/dist/utils/issue-severity.js.map +1 -0
- package/dist/utils/output.d.ts +54 -5
- package/dist/utils/output.d.ts.map +1 -1
- package/dist/utils/output.js +111 -17
- package/dist/utils/output.js.map +1 -1
- package/dist/utils/relativize-paths.d.ts +45 -0
- package/dist/utils/relativize-paths.d.ts.map +1 -0
- package/dist/utils/relativize-paths.js +67 -0
- package/dist/utils/relativize-paths.js.map +1 -0
- package/dist/utils/resource-loader.d.ts +21 -2
- package/dist/utils/resource-loader.d.ts.map +1 -1
- package/dist/utils/resource-loader.js +85 -11
- package/dist/utils/resource-loader.js.map +1 -1
- package/dist/utils/skill-packaging-config.d.ts +22 -1
- package/dist/utils/skill-packaging-config.d.ts.map +1 -1
- package/dist/utils/skill-packaging-config.js +26 -0
- package/dist/utils/skill-packaging-config.js.map +1 -1
- package/dist/utils/verdict-helpers.d.ts +4 -3
- package/dist/utils/verdict-helpers.d.ts.map +1 -1
- package/dist/utils/verdict-helpers.js +6 -13
- package/dist/utils/verdict-helpers.js.map +1 -1
- package/dist/version.d.ts +22 -2
- package/dist/version.d.ts.map +1 -1
- package/dist/version.js +31 -2
- package/dist/version.js.map +1 -1
- package/docs/index.md +12 -0
- package/docs/rag.md +9 -4
- package/docs/resources.md +30 -14
- package/docs/skills.md +25 -7
- 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
|
|
21
|
-
*
|
|
22
|
-
*
|
|
23
|
-
*
|
|
24
|
-
*
|
|
25
|
-
*
|
|
26
|
-
* @
|
|
27
|
-
*
|
|
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
|
|
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
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
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
|
|
79
|
-
exitCode
|
|
80
|
-
|
|
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', '
|
|
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
|
-
|
|
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":"AAAA;;GAEG;AAEH,OAAO,EAAE,SAAS,EAAE,MAAM,oBAAoB,CAAC;AAG/C,OAAO,EAAE,QAAQ,EAAE,MAAM,2BAA2B,CAAC;
|
|
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;
|
|
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
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
const formattedChunks =
|
|
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
|
-
//
|
|
45
|
-
|
|
47
|
+
// Stats/duration before chunks (short fields first)
|
|
48
|
+
return {
|
|
46
49
|
status: 'success',
|
|
50
|
+
root,
|
|
47
51
|
query: queryText,
|
|
48
|
-
stats
|
|
49
|
-
duration: formatDuration(
|
|
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
|