@vibe-agent-toolkit/cli 0.1.41-rc.7 → 0.1.41-rc.8
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 +12 -1
- 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.d.ts +34 -1
- package/dist/commands/audit.d.ts.map +1 -1
- package/dist/commands/audit.js +220 -88
- 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 +89 -24
- package/dist/commands/build.js.map +1 -1
- package/dist/commands/claude/marketplace/validate.d.ts +97 -0
- package/dist/commands/claude/marketplace/validate.d.ts.map +1 -1
- package/dist/commands/claude/marketplace/validate.js +154 -40
- 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 +25 -2
- package/dist/commands/claude/plugin/build.d.ts.map +1 -1
- package/dist/commands/claude/plugin/build.js +99 -10
- package/dist/commands/claude/plugin/build.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/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/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/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.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 +96 -7
- package/dist/commands/skills/build.d.ts.map +1 -1
- package/dist/commands/skills/build.js +277 -60
- 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/validate-command.d.ts.map +1 -1
- package/dist/commands/skills/validate-command.js +22 -6
- 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 +180 -46
- 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 +73 -66
- package/dist/commands/validate.js.map +1 -1
- package/dist/commands/verify.d.ts +38 -1
- package/dist/commands/verify.d.ts.map +1 -1
- package/dist/commands/verify.js +203 -83
- 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 +88 -0
- package/dist/utils/issue-rendering.d.ts.map +1 -1
- package/dist/utils/issue-rendering.js +94 -0
- package/dist/utils/issue-rendering.js.map +1 -1
- 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/docs/rag.md +9 -4
- package/docs/resources.md +30 -14
- package/docs/skills.md +9 -5
- package/package.json +12 -12
|
@@ -6,27 +6,37 @@
|
|
|
6
6
|
* packaging config (schema defaults -> config defaults -> per-skill overrides),
|
|
7
7
|
* validates, and packages into dist/skills/<name>/.
|
|
8
8
|
*/
|
|
9
|
-
import { type SeverityCounts } from '@vibe-agent-toolkit/agent-schema';
|
|
10
|
-
import { type PackageSkillResult, type PackagingValidationResult } from '@vibe-agent-toolkit/agent-skills';
|
|
9
|
+
import { type SeverityCounts, type ValidationIssue } from '@vibe-agent-toolkit/agent-schema';
|
|
10
|
+
import { type DeclaredEvalSuite, type PackageSkillResult, type PackagingValidationResult, type SkillPackagingConfig } from '@vibe-agent-toolkit/agent-skills';
|
|
11
11
|
import { Command } from 'commander';
|
|
12
|
+
import { type createLogger } from '../../utils/logger.js';
|
|
13
|
+
import { type DiscoveredSkill } from './command-helpers.js';
|
|
12
14
|
export interface SkillsBuildCommandOptions {
|
|
13
15
|
skill?: string;
|
|
14
16
|
dryRun?: boolean;
|
|
15
17
|
debug?: boolean;
|
|
18
|
+
verbose?: boolean;
|
|
16
19
|
}
|
|
17
20
|
export declare function createBuildCommand(): Command;
|
|
18
21
|
/**
|
|
19
22
|
* Render every emitted pre-build finding, each labelled with its own severity.
|
|
20
23
|
*
|
|
21
24
|
* `allErrors` is the full emitted set INCLUDING info (its name lies — see the
|
|
22
|
-
* doc comment on `PackagingValidationResult`). Walking
|
|
23
|
-
*
|
|
25
|
+
* doc comment on `PackagingValidationResult`). Walking only the errors plus the
|
|
26
|
+
* `ALLOW_EXPIRED` subset of the warnings, which is what this used to do,
|
|
24
27
|
* dropped every other warning and every info finding from a report that had
|
|
25
28
|
* already decided to abort the build.
|
|
26
29
|
*
|
|
30
|
+
* `verbose` picks how much of that set is spelled out, never how much of it is
|
|
31
|
+
* COUNTED: the heading is built from `allErrors` either way, so the severity
|
|
32
|
+
* breakdown stays whole even when the bodies below it do not (see
|
|
33
|
+
* `issuesToRenderAtVerbosity`). Every error is printed at both verbosities —
|
|
34
|
+
* these are the findings that just aborted the build, so putting one behind a
|
|
35
|
+
* flag would mean re-running to learn what broke.
|
|
36
|
+
*
|
|
27
37
|
* Pure so the whole set is assertable, not a chosen subset of it.
|
|
28
38
|
*/
|
|
29
|
-
export declare function formatPreBuildIssueReport(validationResult: PackagingValidationResult): string[];
|
|
39
|
+
export declare function formatPreBuildIssueReport(validationResult: PackagingValidationResult, verbose: boolean): string[];
|
|
30
40
|
/**
|
|
31
41
|
* Render post-build integrity issues, each prefixed by its OWN resolved severity.
|
|
32
42
|
*
|
|
@@ -35,10 +45,18 @@ export declare function formatPreBuildIssueReport(validationResult: PackagingVal
|
|
|
35
45
|
* failed it, and the heading names the set's actual severity mix rather than
|
|
36
46
|
* calling every set by its worst member.
|
|
37
47
|
*
|
|
48
|
+
* The heading is unconditional and counts the WHOLE set; `verbose` decides only
|
|
49
|
+
* which findings get a block beneath it (see `issuesToRenderAtVerbosity`). This
|
|
50
|
+
* loop printing every occurrence is what made a 90-skill build emit 6,552 stderr
|
|
51
|
+
* lines against the 804 `vat skills validate` emitted for the same corpus — 1,620
|
|
52
|
+
* of them one high-cardinality warning code. A set whose findings all collapse
|
|
53
|
+
* still renders its heading: collapsing that too would turn a warning-carrying
|
|
54
|
+
* build into silence, which is the reassuring direction this module warns about.
|
|
55
|
+
*
|
|
38
56
|
* Pure: returns the lines instead of writing them, so the whole rendered set is
|
|
39
57
|
* assertable without capturing a stream.
|
|
40
58
|
*/
|
|
41
|
-
export declare function formatPostBuildIssueReport(result: PackageSkillResult): string[];
|
|
59
|
+
export declare function formatPostBuildIssueReport(result: PackageSkillResult, verbose: boolean): string[];
|
|
42
60
|
/**
|
|
43
61
|
* The archived summary of a build, as YAML fields.
|
|
44
62
|
*
|
|
@@ -48,20 +66,91 @@ export declare function formatPostBuildIssueReport(result: PackageSkillResult):
|
|
|
48
66
|
* from the same issues the human stream renders, and the per-severity counts
|
|
49
67
|
* ride beside it because a status cannot express a three-valued distribution:
|
|
50
68
|
* `success` here means "nothing you must act on", not "there was nothing to see".
|
|
69
|
+
*
|
|
70
|
+
* The header total reconciles against the document, by construction:
|
|
71
|
+
*
|
|
72
|
+
* issueCounts === Σ skills[].issueCounts
|
|
73
|
+
* + Σ failedSkills[].issueCounts
|
|
74
|
+
* + runIssueCounts
|
|
75
|
+
*
|
|
76
|
+
* Every addend therefore has a ROW a reader can point at. Counting the failures
|
|
77
|
+
* only in the header — which is how this first shipped — reproduced, one command
|
|
78
|
+
* over, the exact defect `vat skills validate` was fixed for: a header reporting
|
|
79
|
+
* more than its rows summed to (there, 1814 warnings against 1800), leaving a
|
|
80
|
+
* consumer to hand-count a list to find out what the difference was. `--help`
|
|
81
|
+
* states this identity; changing it means changing that text too.
|
|
51
82
|
*/
|
|
52
83
|
export declare function buildYamlSummary(results: Array<{
|
|
53
84
|
name: string;
|
|
54
85
|
result: PackageSkillResult;
|
|
55
|
-
}>, duration: number): {
|
|
86
|
+
}>, failures: readonly SkillBuildFailure[], duration: number, runIssues: readonly ValidationIssue[], skillsWithErrors: readonly string[]): {
|
|
56
87
|
status: 'success' | 'warning' | 'error';
|
|
57
88
|
issueCounts: SeverityCounts;
|
|
89
|
+
runIssueCounts: SeverityCounts;
|
|
58
90
|
skillsBuilt: number;
|
|
91
|
+
skillsFailed: number;
|
|
92
|
+
skillsWithErrors: string[];
|
|
59
93
|
skills: Array<{
|
|
60
94
|
name: string;
|
|
61
95
|
outputPath: string;
|
|
62
96
|
filesPackaged: number;
|
|
63
97
|
issueCounts: SeverityCounts;
|
|
64
98
|
}>;
|
|
99
|
+
failedSkills: Array<{
|
|
100
|
+
name: string;
|
|
101
|
+
error: string;
|
|
102
|
+
issueCounts: SeverityCounts;
|
|
103
|
+
}>;
|
|
104
|
+
runIssues: ValidationIssue[];
|
|
65
105
|
duration: string;
|
|
66
106
|
};
|
|
107
|
+
/** One discovered skill paired with the packaging config merged for it. */
|
|
108
|
+
export interface BuildSkillSpec {
|
|
109
|
+
skill: DiscoveredSkill;
|
|
110
|
+
packagingConfig: SkillPackagingConfig;
|
|
111
|
+
}
|
|
112
|
+
/**
|
|
113
|
+
* A skill whose packaging THREW — it produced no artifact at all.
|
|
114
|
+
*
|
|
115
|
+
* Deliberately distinct from `skillsWithErrors`, which names skills that built
|
|
116
|
+
* successfully and then failed post-build validation. Collapsing the two would
|
|
117
|
+
* lose the only distinction that matters to the reader: whether `dist/skills/`
|
|
118
|
+
* contains anything for that name.
|
|
119
|
+
*/
|
|
120
|
+
export interface SkillBuildFailure {
|
|
121
|
+
name: string;
|
|
122
|
+
message: string;
|
|
123
|
+
}
|
|
124
|
+
/** Everything one `vat build` invocation produced, ready to report on. */
|
|
125
|
+
export interface SkillBuildRun {
|
|
126
|
+
results: Array<{
|
|
127
|
+
name: string;
|
|
128
|
+
result: PackageSkillResult;
|
|
129
|
+
}>;
|
|
130
|
+
/** Findings that belong to the run, not to any one skill (ALLOW_UNUSED). */
|
|
131
|
+
runIssues: ValidationIssue[];
|
|
132
|
+
/** Names of skills that BUILT and whose own post-build validation errored. */
|
|
133
|
+
skillsWithErrors: string[];
|
|
134
|
+
/** Skills that never built because packaging threw. */
|
|
135
|
+
failures: SkillBuildFailure[];
|
|
136
|
+
}
|
|
137
|
+
/**
|
|
138
|
+
* Validate, package, and drain — the whole span of ONE `vat build` invocation.
|
|
139
|
+
*
|
|
140
|
+
* The allow-usage ledger created here spans EVERY skill and BOTH validation
|
|
141
|
+
* lanes (the source-tree pre-build check and the two lanes inside
|
|
142
|
+
* `packageSkill`), because `validation.allow` is declared once for the package
|
|
143
|
+
* while being evaluated once per skill per lane. Anything narrower reports
|
|
144
|
+
* entries that legitimately matched somewhere else as unused: measured on this
|
|
145
|
+
* repo's own 13-skill package, 3 live entries produced 32 false ALLOW_UNUSED
|
|
146
|
+
* warnings — 6 from the cross-skill seam, 26 because the two lanes inside
|
|
147
|
+
* `packageSkill` see a FILTERED issue population against a file packaging has
|
|
148
|
+
* renamed to `SKILL.md`, so entries scoped to a source filename are structurally
|
|
149
|
+
* incapable of matching there. A lane that sees a subset cannot answer "matched
|
|
150
|
+
* nothing"; only the union can. Hence one ledger, drained once, here.
|
|
151
|
+
*
|
|
152
|
+
* Extracted from the command body so the span is testable without driving
|
|
153
|
+
* `process.exit` — the drain seam is the thing worth asserting.
|
|
154
|
+
*/
|
|
155
|
+
export declare function runSkillBuild(specs: readonly BuildSkillSpec[], cwd: string, logger: ReturnType<typeof createLogger>, projectSkills: readonly DeclaredEvalSuite[], verbose?: boolean): Promise<SkillBuildRun>;
|
|
67
156
|
//# sourceMappingURL=build.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"build.d.ts","sourceRoot":"","sources":["../../../src/commands/skills/build.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAKH,OAAO,
|
|
1
|
+
{"version":3,"file":"build.d.ts","sourceRoot":"","sources":["../../../src/commands/skills/build.ts"],"names":[],"mappings":"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"}
|
|
@@ -8,16 +8,16 @@
|
|
|
8
8
|
*/
|
|
9
9
|
import { existsSync } from 'node:fs';
|
|
10
10
|
import { rm } from 'node:fs/promises';
|
|
11
|
-
import { calculateValidationStatus, countBySeverity, } from '@vibe-agent-toolkit/agent-schema';
|
|
11
|
+
import { allowUnusedIssues, calculateValidationStatus, countBySeverity, createAllowUsageLedger, } from '@vibe-agent-toolkit/agent-schema';
|
|
12
12
|
import { packageSkills, packagingConfigToPackageOptions, skillNameToFsPath, validateSkillForPackaging, } from '@vibe-agent-toolkit/agent-skills';
|
|
13
13
|
import { safePath } from '@vibe-agent-toolkit/utils';
|
|
14
14
|
import { Command } from 'commander';
|
|
15
15
|
import * as yaml from 'yaml';
|
|
16
|
-
import { handleCommandError } from '../../utils/command-error.js';
|
|
16
|
+
import { handleCommandError, handleValidationGateFailure } from '../../utils/command-error.js';
|
|
17
17
|
import { loadConfig } from '../../utils/config-loader.js';
|
|
18
|
-
import { collectPostBuildIssues, formatIssueLines, formatIssueSetHeading, sumSeverityCounts, } from '../../utils/issue-rendering.js';
|
|
18
|
+
import { collectPostBuildIssues, formatIssueLines, formatIssueSetHeading, formatRunIssueLines, issuesToRenderAtVerbosity, sumSeverityCounts, } from '../../utils/issue-rendering.js';
|
|
19
19
|
import { requireProjectRoot } from '../../utils/project-root-policy.js';
|
|
20
|
-
import { mergeSkillPackagingConfig } from '../../utils/skill-packaging-config.js';
|
|
20
|
+
import { collectDeclaredEvalSuites, mergeSkillPackagingConfig } from '../../utils/skill-packaging-config.js';
|
|
21
21
|
import { applyConfigVerdicts } from '../../utils/verdict-helpers.js';
|
|
22
22
|
import { filterSkillsByName, setupCommandContext, writeYamlHeader, } from './command-helpers.js';
|
|
23
23
|
import { discoverSkillsFromConfig } from './skill-discovery.js';
|
|
@@ -28,6 +28,7 @@ export function createBuildCommand() {
|
|
|
28
28
|
.argument('[path]', 'Path to project directory (default: current directory)')
|
|
29
29
|
.option('--skill <name>', 'Build specific skill only')
|
|
30
30
|
.option('--dry-run', 'Preview build without creating files')
|
|
31
|
+
.option('-v, --verbose', 'Show every individual finding, not just the errors')
|
|
31
32
|
.option('--debug', 'Enable debug logging')
|
|
32
33
|
.action(buildCommand)
|
|
33
34
|
.addHelpText('after', `
|
|
@@ -67,9 +68,38 @@ Output:
|
|
|
67
68
|
YAML summary -> stdout (for programmatic parsing)
|
|
68
69
|
Build progress -> stderr (for human reading)
|
|
69
70
|
|
|
71
|
+
On stderr, every findings heading names the whole set and its severity
|
|
72
|
+
breakdown, and errors are always printed in full beneath it. Warnings and
|
|
73
|
+
info findings stay collapsed into that heading unless --verbose, because
|
|
74
|
+
they are the high-cardinality ones (one adopter skill carries 348
|
|
75
|
+
LINK_DROPPED_BY_DEPTH warnings alone). The stdout YAML is NOT affected by
|
|
76
|
+
--verbose: it carries every finding at every verbosity.
|
|
77
|
+
|
|
78
|
+
skills: one row per skill that produced a bundle
|
|
79
|
+
failedSkills: one row per skill that could not be packaged AT ALL (no
|
|
80
|
+
bundle exists for it); each carries name, error and an
|
|
81
|
+
issueCounts of one error
|
|
82
|
+
skillsWithErrors / skillsWithErrorNames:
|
|
83
|
+
the OTHER failure mode — skills that packaged fine and then
|
|
84
|
+
emitted post-build validation errors. They are counted in
|
|
85
|
+
skillsBuilt, not skillsFailed, so read BOTH before concluding
|
|
86
|
+
a run was clean: the exit code follows this one too.
|
|
87
|
+
runIssueCounts: findings that belong to the run rather than to any one
|
|
88
|
+
skill (ALLOW_UNUSED)
|
|
89
|
+
issueCounts: the run total, which reconciles against the rows above:
|
|
90
|
+
|
|
91
|
+
issueCounts = sum(skills[].issueCounts)
|
|
92
|
+
+ sum(failedSkills[].issueCounts)
|
|
93
|
+
+ runIssueCounts
|
|
94
|
+
|
|
95
|
+
Every error, warning and info in the header total is
|
|
96
|
+
therefore attributable to a row you can point at.
|
|
97
|
+
|
|
70
98
|
Exit Codes:
|
|
71
99
|
0 - All skills built successfully (or dry-run preview)
|
|
72
|
-
1 - One or more skills emitted validation errors
|
|
100
|
+
1 - One or more skills emitted validation errors, or could not be packaged
|
|
101
|
+
at all (a skill that fails to package does NOT abort the others; the
|
|
102
|
+
rest still build and the failures are listed under failedSkills)
|
|
73
103
|
2 - System error (config invalid, directory not found)
|
|
74
104
|
|
|
75
105
|
Requirements:
|
|
@@ -87,18 +117,25 @@ Example:
|
|
|
87
117
|
* Render every emitted pre-build finding, each labelled with its own severity.
|
|
88
118
|
*
|
|
89
119
|
* `allErrors` is the full emitted set INCLUDING info (its name lies — see the
|
|
90
|
-
* doc comment on `PackagingValidationResult`). Walking
|
|
91
|
-
*
|
|
120
|
+
* doc comment on `PackagingValidationResult`). Walking only the errors plus the
|
|
121
|
+
* `ALLOW_EXPIRED` subset of the warnings, which is what this used to do,
|
|
92
122
|
* dropped every other warning and every info finding from a report that had
|
|
93
123
|
* already decided to abort the build.
|
|
94
124
|
*
|
|
125
|
+
* `verbose` picks how much of that set is spelled out, never how much of it is
|
|
126
|
+
* COUNTED: the heading is built from `allErrors` either way, so the severity
|
|
127
|
+
* breakdown stays whole even when the bodies below it do not (see
|
|
128
|
+
* `issuesToRenderAtVerbosity`). Every error is printed at both verbosities —
|
|
129
|
+
* these are the findings that just aborted the build, so putting one behind a
|
|
130
|
+
* flag would mean re-running to learn what broke.
|
|
131
|
+
*
|
|
95
132
|
* Pure so the whole set is assertable, not a chosen subset of it.
|
|
96
133
|
*/
|
|
97
|
-
export function formatPreBuildIssueReport(validationResult) {
|
|
134
|
+
export function formatPreBuildIssueReport(validationResult, verbose) {
|
|
98
135
|
const lines = [];
|
|
99
136
|
if (validationResult.allErrors.length > 0) {
|
|
100
137
|
lines.push(`\n ${formatIssueSetHeading(validationResult.allErrors)}:`);
|
|
101
|
-
for (const issue of validationResult.allErrors) {
|
|
138
|
+
for (const issue of issuesToRenderAtVerbosity(validationResult.allErrors, verbose)) {
|
|
102
139
|
lines.push(...formatIssueLines(issue, ' '));
|
|
103
140
|
}
|
|
104
141
|
}
|
|
@@ -112,15 +149,23 @@ export function formatPreBuildIssueReport(validationResult) {
|
|
|
112
149
|
* failed it, and the heading names the set's actual severity mix rather than
|
|
113
150
|
* calling every set by its worst member.
|
|
114
151
|
*
|
|
152
|
+
* The heading is unconditional and counts the WHOLE set; `verbose` decides only
|
|
153
|
+
* which findings get a block beneath it (see `issuesToRenderAtVerbosity`). This
|
|
154
|
+
* loop printing every occurrence is what made a 90-skill build emit 6,552 stderr
|
|
155
|
+
* lines against the 804 `vat skills validate` emitted for the same corpus — 1,620
|
|
156
|
+
* of them one high-cardinality warning code. A set whose findings all collapse
|
|
157
|
+
* still renders its heading: collapsing that too would turn a warning-carrying
|
|
158
|
+
* build into silence, which is the reassuring direction this module warns about.
|
|
159
|
+
*
|
|
115
160
|
* Pure: returns the lines instead of writing them, so the whole rendered set is
|
|
116
161
|
* assertable without capturing a stream.
|
|
117
162
|
*/
|
|
118
|
-
export function formatPostBuildIssueReport(result) {
|
|
163
|
+
export function formatPostBuildIssueReport(result, verbose) {
|
|
119
164
|
const issues = collectPostBuildIssues(result);
|
|
120
165
|
if (issues.length === 0)
|
|
121
166
|
return [];
|
|
122
167
|
const lines = [` ${formatIssueSetHeading(issues, 'post-build')}:`];
|
|
123
|
-
for (const issue of issues) {
|
|
168
|
+
for (const issue of issuesToRenderAtVerbosity(issues, verbose)) {
|
|
124
169
|
lines.push(...formatIssueLines(issue, ' '));
|
|
125
170
|
}
|
|
126
171
|
return lines;
|
|
@@ -129,8 +174,8 @@ export function formatPostBuildIssueReport(result) {
|
|
|
129
174
|
* Log post-build integrity issues to stderr (the human stream; stdout is
|
|
130
175
|
* reserved for the YAML summary).
|
|
131
176
|
*/
|
|
132
|
-
function logPostBuildIssues(result, logger) {
|
|
133
|
-
for (const line of formatPostBuildIssueReport(result)) {
|
|
177
|
+
function logPostBuildIssues(result, logger, verbose) {
|
|
178
|
+
for (const line of formatPostBuildIssueReport(result, verbose)) {
|
|
134
179
|
logger.info(line);
|
|
135
180
|
}
|
|
136
181
|
}
|
|
@@ -145,12 +190,17 @@ function displayIgnoredErrors(validationResult, logger) {
|
|
|
145
190
|
}
|
|
146
191
|
}
|
|
147
192
|
}
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
*/
|
|
151
|
-
async function validateSkillOrExit(skillName, sourcePath, packagingConfig, logger, locationRoot) {
|
|
193
|
+
async function validateSkillOrExit(input) {
|
|
194
|
+
const { skillName, sourcePath, packagingConfig, logger, locationRoot, allowLedger, projectSkills, verbose } = input;
|
|
152
195
|
logger.debug(` Validating skill: ${skillName}`);
|
|
153
|
-
|
|
196
|
+
// The run's ledger, not this call's: an allow entry scoped to a SOURCE
|
|
197
|
+
// filename can only ever match here — packaging renames the file to
|
|
198
|
+
// `SKILL.md` and the built lane drops the source-only codes — so a build that
|
|
199
|
+
// withholds this lane's matches from the run reports live entries as dead.
|
|
200
|
+
//
|
|
201
|
+
// The run's declared eval suites likewise: this lane must model the same bundle
|
|
202
|
+
// the packager below produces, and that bundle excludes EVERY skill's test input.
|
|
203
|
+
const validationResult = await validateSkillForPackaging(sourcePath, packagingConfig, 'source', { allowLedger, projectSkills });
|
|
154
204
|
applyConfigVerdicts(validationResult, packagingConfig.targets, sourcePath, locationRoot);
|
|
155
205
|
if (validationResult.status !== 'error') {
|
|
156
206
|
if (validationResult.ignoredErrors.length > 0) {
|
|
@@ -161,12 +211,15 @@ async function validateSkillOrExit(skillName, sourcePath, packagingConfig, logge
|
|
|
161
211
|
// Validation failed - display every emitted finding and exit
|
|
162
212
|
logger.error(`\nSkill validation failed: ${skillName}`);
|
|
163
213
|
logger.error(` Source: ${sourcePath}`);
|
|
164
|
-
for (const line of formatPreBuildIssueReport(validationResult)) {
|
|
214
|
+
for (const line of formatPreBuildIssueReport(validationResult, verbose)) {
|
|
165
215
|
logger.error(line);
|
|
166
216
|
}
|
|
167
217
|
displayIgnoredErrors(validationResult, logger);
|
|
168
218
|
logger.error(`\n Build aborted due to validation errors`);
|
|
169
|
-
|
|
219
|
+
// Every finding above went to STDERR. Exiting here without the stdout summary
|
|
220
|
+
// is what made `vat skills build | jq .status` return an empty document
|
|
221
|
+
// alongside exit 1 — the one case the help text documents exit 1 for.
|
|
222
|
+
handleValidationGateFailure(skillName, validationResult.allErrors);
|
|
170
223
|
}
|
|
171
224
|
/**
|
|
172
225
|
* Output dry-run results
|
|
@@ -206,6 +259,14 @@ function performDryRun(skillsToBuild, duration, logger) {
|
|
|
206
259
|
logger.info(`\nDry-run complete (no files created)`);
|
|
207
260
|
logger.info(` Run without --dry-run to build the skills`);
|
|
208
261
|
}
|
|
262
|
+
/**
|
|
263
|
+
* What ONE unpackageable skill contributes to the run's counts.
|
|
264
|
+
*
|
|
265
|
+
* A fresh object per row: these are published as separate YAML nodes, and a
|
|
266
|
+
* shared reference is how a document grows anchors (or a later mutation edits
|
|
267
|
+
* every row at once).
|
|
268
|
+
*/
|
|
269
|
+
const failureIssueCounts = () => ({ errors: 1, warnings: 0, info: 0 });
|
|
209
270
|
/**
|
|
210
271
|
* The archived summary of a build, as YAML fields.
|
|
211
272
|
*
|
|
@@ -215,12 +276,37 @@ function performDryRun(skillsToBuild, duration, logger) {
|
|
|
215
276
|
* from the same issues the human stream renders, and the per-severity counts
|
|
216
277
|
* ride beside it because a status cannot express a three-valued distribution:
|
|
217
278
|
* `success` here means "nothing you must act on", not "there was nothing to see".
|
|
279
|
+
*
|
|
280
|
+
* The header total reconciles against the document, by construction:
|
|
281
|
+
*
|
|
282
|
+
* issueCounts === Σ skills[].issueCounts
|
|
283
|
+
* + Σ failedSkills[].issueCounts
|
|
284
|
+
* + runIssueCounts
|
|
285
|
+
*
|
|
286
|
+
* Every addend therefore has a ROW a reader can point at. Counting the failures
|
|
287
|
+
* only in the header — which is how this first shipped — reproduced, one command
|
|
288
|
+
* over, the exact defect `vat skills validate` was fixed for: a header reporting
|
|
289
|
+
* more than its rows summed to (there, 1814 warnings against 1800), leaving a
|
|
290
|
+
* consumer to hand-count a list to find out what the difference was. `--help`
|
|
291
|
+
* states this identity; changing it means changing that text too.
|
|
218
292
|
*/
|
|
219
|
-
export function buildYamlSummary(results, duration) {
|
|
293
|
+
export function buildYamlSummary(results, failures, duration, runIssues, skillsWithErrors) {
|
|
220
294
|
const perSkill = results.map(({ name, result }) => {
|
|
221
295
|
const issues = collectPostBuildIssues(result);
|
|
222
296
|
return {
|
|
223
297
|
name,
|
|
298
|
+
// KNOWN, DELIBERATELY NOT FIXED — this is an ABSOLUTE path, so stdout carries
|
|
299
|
+
// `$HOME`. Confirmed on a real 90-skill adopter run:
|
|
300
|
+
// `outputPath: /Users/<user>/Workspaces/.../dist/skills/<name>`. It is absolute
|
|
301
|
+
// because `runSkillBuild` builds it with `safePath.resolve(cwd, 'dist', ...)`.
|
|
302
|
+
//
|
|
303
|
+
// Do NOT "helpfully" relativize it. It is blocked on an approved-but-unbuilt
|
|
304
|
+
// design decision that is the project owner's call: the document must state one
|
|
305
|
+
// `root:` and re-base every path onto it, the same coordinate-system rule
|
|
306
|
+
// `vat audit` already follows (see `deriveScanRoot` in ../audit.ts — "the ONE base
|
|
307
|
+
// every `path` and `location` in a report is expressed relative to"). Making this
|
|
308
|
+
// one field relative ahead of that decision picks the anchor by accident and
|
|
309
|
+
// leaves the document in two coordinate systems.
|
|
224
310
|
outputPath: result.outputPath,
|
|
225
311
|
filesPackaged: result.files.dependencies.length + 1,
|
|
226
312
|
issueCounts: countBySeverity(issues),
|
|
@@ -228,26 +314,76 @@ export function buildYamlSummary(results, duration) {
|
|
|
228
314
|
};
|
|
229
315
|
});
|
|
230
316
|
const allIssues = perSkill.flatMap((s) => s.issues);
|
|
317
|
+
const runIssueCounts = countBySeverity(runIssues);
|
|
318
|
+
// A skill that THREW emits no issues at all — it never reached the lanes that
|
|
319
|
+
// produce them. Deriving the header purely from issue channels therefore said
|
|
320
|
+
// `success` for a run the command then exited 1 on, which is exactly the
|
|
321
|
+
// reassuring contradiction this summary exists to prevent. Each failure is
|
|
322
|
+
// counted as one error so `status`, `issueCounts` and the exit code agree —
|
|
323
|
+
// and that error is published ON the failure's own row (see
|
|
324
|
+
// `failureIssueCounts`), never as a header-only addend, so the identity
|
|
325
|
+
// documented in `--help` holds.
|
|
326
|
+
const failedSkills = failures.map(({ name, message }) => ({
|
|
327
|
+
name,
|
|
328
|
+
error: message,
|
|
329
|
+
issueCounts: failureIssueCounts(),
|
|
330
|
+
}));
|
|
231
331
|
return {
|
|
232
|
-
status:
|
|
233
|
-
|
|
332
|
+
status: failures.length > 0
|
|
333
|
+
? 'error'
|
|
334
|
+
: calculateValidationStatus([...allIssues, ...runIssues]),
|
|
335
|
+
issueCounts: sumSeverityCounts([
|
|
336
|
+
...perSkill.map((s) => s.issueCounts),
|
|
337
|
+
...failedSkills.map((s) => s.issueCounts),
|
|
338
|
+
runIssueCounts,
|
|
339
|
+
]),
|
|
340
|
+
runIssueCounts,
|
|
234
341
|
skillsBuilt: results.length,
|
|
342
|
+
skillsFailed: failures.length,
|
|
343
|
+
// The OTHER meaning of "failed", published because the exit code follows
|
|
344
|
+
// THIS one and nothing in the document did. `skillsFailed` counts skills
|
|
345
|
+
// that could not be packaged at all; a skill that packaged fine and then
|
|
346
|
+
// emitted post-build validation errors is a `skillsBuilt`, so a real run
|
|
347
|
+
// printed "Build failed: 3 skill(s) emitted post-build validation errors"
|
|
348
|
+
// over `skillsFailed: 0` and `failedSkills: []`, and exited 1. A CI job
|
|
349
|
+
// reading either field saw a clean build. Both categories are now named.
|
|
350
|
+
skillsWithErrors: [...skillsWithErrors],
|
|
351
|
+
// `skills` lists what exists on disk. A failed skill is published in its own
|
|
352
|
+
// list rather than here, because every field of this shape (outputPath,
|
|
353
|
+
// filesPackaged) would have to be invented for a bundle that was not written.
|
|
235
354
|
skills: perSkill.map(({ name, outputPath, filesPackaged, issueCounts }) => ({
|
|
236
355
|
name,
|
|
237
356
|
outputPath,
|
|
238
357
|
filesPackaged,
|
|
239
358
|
issueCounts,
|
|
240
359
|
})),
|
|
360
|
+
failedSkills,
|
|
361
|
+
runIssues: [...runIssues],
|
|
241
362
|
duration: `${duration}ms`,
|
|
242
363
|
};
|
|
243
364
|
}
|
|
244
365
|
/**
|
|
245
366
|
* Output build results
|
|
246
367
|
*/
|
|
247
|
-
function outputBuildYaml(results, duration) {
|
|
248
|
-
const
|
|
249
|
-
|
|
250
|
-
|
|
368
|
+
function outputBuildYaml(results, failures, duration, runIssues, skillsWithErrors) {
|
|
369
|
+
const summary = buildYamlSummary(results, failures, duration, runIssues, skillsWithErrors);
|
|
370
|
+
const { status, skillsBuilt, skillsFailed, issueCounts, runIssueCounts, skills, failedSkills, duration: durationText, } = summary;
|
|
371
|
+
// In the header, beside the other two counts: this is the number the exit code
|
|
372
|
+
// actually follows, so a reader who stops at the header is not misled by it.
|
|
373
|
+
writeYamlHeader({
|
|
374
|
+
status,
|
|
375
|
+
skillsBuilt,
|
|
376
|
+
skillsFailed,
|
|
377
|
+
skillsWithErrors: summary.skillsWithErrors.length,
|
|
378
|
+
});
|
|
379
|
+
process.stdout.write(yaml.stringify({
|
|
380
|
+
issueCounts,
|
|
381
|
+
runIssueCounts,
|
|
382
|
+
skills,
|
|
383
|
+
failedSkills,
|
|
384
|
+
skillsWithErrorNames: summary.skillsWithErrors,
|
|
385
|
+
runIssues: summary.runIssues,
|
|
386
|
+
}, { indent: 2, lineWidth: 0, aliasDuplicateObjects: false }));
|
|
251
387
|
process.stdout.write(`duration: ${durationText}\n`);
|
|
252
388
|
}
|
|
253
389
|
/**
|
|
@@ -270,6 +406,94 @@ async function cleanStaleSkillOutputs(cwd, skillName) {
|
|
|
270
406
|
}
|
|
271
407
|
}
|
|
272
408
|
}
|
|
409
|
+
/**
|
|
410
|
+
* Validate, package, and drain — the whole span of ONE `vat build` invocation.
|
|
411
|
+
*
|
|
412
|
+
* The allow-usage ledger created here spans EVERY skill and BOTH validation
|
|
413
|
+
* lanes (the source-tree pre-build check and the two lanes inside
|
|
414
|
+
* `packageSkill`), because `validation.allow` is declared once for the package
|
|
415
|
+
* while being evaluated once per skill per lane. Anything narrower reports
|
|
416
|
+
* entries that legitimately matched somewhere else as unused: measured on this
|
|
417
|
+
* repo's own 13-skill package, 3 live entries produced 32 false ALLOW_UNUSED
|
|
418
|
+
* warnings — 6 from the cross-skill seam, 26 because the two lanes inside
|
|
419
|
+
* `packageSkill` see a FILTERED issue population against a file packaging has
|
|
420
|
+
* renamed to `SKILL.md`, so entries scoped to a source filename are structurally
|
|
421
|
+
* incapable of matching there. A lane that sees a subset cannot answer "matched
|
|
422
|
+
* nothing"; only the union can. Hence one ledger, drained once, here.
|
|
423
|
+
*
|
|
424
|
+
* Extracted from the command body so the span is testable without driving
|
|
425
|
+
* `process.exit` — the drain seam is the thing worth asserting.
|
|
426
|
+
*/
|
|
427
|
+
export async function runSkillBuild(specs, cwd, logger, projectSkills, verbose = false) {
|
|
428
|
+
const allowLedger = createAllowUsageLedger();
|
|
429
|
+
// Validate all skills before building
|
|
430
|
+
for (const { skill, packagingConfig } of specs) {
|
|
431
|
+
const outputDir = safePath.resolve(cwd, 'dist', 'skills', skillNameToFsPath(skill.name));
|
|
432
|
+
logger.info(`\nBuilding skill: ${skill.name}`);
|
|
433
|
+
logger.info(` Source: ${skill.sourcePath}`);
|
|
434
|
+
logger.info(` Output: ${outputDir}`);
|
|
435
|
+
await validateSkillOrExit({
|
|
436
|
+
skillName: skill.name,
|
|
437
|
+
sourcePath: skill.sourcePath,
|
|
438
|
+
packagingConfig,
|
|
439
|
+
logger,
|
|
440
|
+
locationRoot: cwd,
|
|
441
|
+
allowLedger,
|
|
442
|
+
projectSkills,
|
|
443
|
+
verbose,
|
|
444
|
+
});
|
|
445
|
+
}
|
|
446
|
+
// Build all skills with a shared registry.
|
|
447
|
+
//
|
|
448
|
+
// `projectSkills` is the run's declared eval suites — the whole project's, not
|
|
449
|
+
// `specs`'. `--skill x` narrows what gets BUILT; it never narrows what counts as
|
|
450
|
+
// test input, because an excluded skill's suite is still an answer key that must
|
|
451
|
+
// not ship inside x's bundle.
|
|
452
|
+
const buildSpecs = specs.map(({ skill, packagingConfig }) => ({
|
|
453
|
+
skillPath: skill.sourcePath,
|
|
454
|
+
options: packagingConfigToPackageOptions(packagingConfig, {
|
|
455
|
+
skillPath: skill.sourcePath,
|
|
456
|
+
outputPath: safePath.resolve(cwd, 'dist', 'skills', skillNameToFsPath(skill.name)),
|
|
457
|
+
}, projectSkills),
|
|
458
|
+
}));
|
|
459
|
+
const outcomes = await packageSkills(buildSpecs, cwd, allowLedger);
|
|
460
|
+
const results = [];
|
|
461
|
+
const skillsWithErrors = [];
|
|
462
|
+
const failures = [];
|
|
463
|
+
for (const [i, spec] of specs.entries()) {
|
|
464
|
+
const outcome = outcomes[i];
|
|
465
|
+
if (!outcome)
|
|
466
|
+
continue;
|
|
467
|
+
if (outcome.status === 'failed') {
|
|
468
|
+
// No `Built N files` line here: nothing was built, and claiming a count
|
|
469
|
+
// for an absent bundle is the misreport this branch exists to avoid.
|
|
470
|
+
logger.error(`\nBuild failed for skill: ${spec.skill.name}`);
|
|
471
|
+
logger.error(` ${outcome.error.message}`);
|
|
472
|
+
failures.push({ name: spec.skill.name, message: outcome.error.message });
|
|
473
|
+
continue;
|
|
474
|
+
}
|
|
475
|
+
const { result } = outcome;
|
|
476
|
+
logger.info(` Built ${result.files.dependencies.length + 1} files`);
|
|
477
|
+
logPostBuildIssues(result, logger, verbose);
|
|
478
|
+
if (result.hasErrors) {
|
|
479
|
+
skillsWithErrors.push(spec.skill.name);
|
|
480
|
+
}
|
|
481
|
+
results.push({ name: spec.skill.name, result });
|
|
482
|
+
}
|
|
483
|
+
// Drain point: every skill and every lane has now contributed, so this is the
|
|
484
|
+
// first place the run can honestly say an entry matched nothing. A skill that
|
|
485
|
+
// threw still contributed the matches it made before throwing — which is why
|
|
486
|
+
// the drain must stay here, after a partially-failed batch, and not move into
|
|
487
|
+
// a success-only path. (Before per-skill containment the drain never ran at
|
|
488
|
+
// all on a throw, because the exception propagated straight past it.)
|
|
489
|
+
//
|
|
490
|
+
// Known residual: a skill that threw never reached its later lanes, so an
|
|
491
|
+
// allow entry only THAT skill could have matched may now be reported
|
|
492
|
+
// ALLOW_UNUSED. That is a warning, and `runHasErrors` gates on `error` only,
|
|
493
|
+
// so it cannot fail a build on its own — and the run is already exiting 1 on
|
|
494
|
+
// the failure the operator actually needs to fix.
|
|
495
|
+
return { results, runIssues: allowUnusedIssues(allowLedger), skillsWithErrors, failures };
|
|
496
|
+
}
|
|
273
497
|
async function buildCommand(pathArg, options) {
|
|
274
498
|
const { logger, cwd, startTime } = setupCommandContext(pathArg, options.debug);
|
|
275
499
|
try {
|
|
@@ -303,47 +527,40 @@ async function buildCommand(pathArg, options) {
|
|
|
303
527
|
performDryRun(skillsToBuild, duration, logger);
|
|
304
528
|
process.exit(0);
|
|
305
529
|
}
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
const packagingConfig = mergeSkillPackagingConfig(skillsConfig.defaults, skillsConfig.config?.[skill.name]);
|
|
310
|
-
const outputDir = safePath.resolve(cwd, 'dist', 'skills', skillNameToFsPath(skill.name));
|
|
311
|
-
logger.info(`\nBuilding skill: ${skill.name}`);
|
|
312
|
-
logger.info(` Source: ${skill.sourcePath}`);
|
|
313
|
-
logger.info(` Output: ${outputDir}`);
|
|
314
|
-
await validateSkillOrExit(skill.name, skill.sourcePath, packagingConfig, logger, cwd);
|
|
315
|
-
validatedSpecs.push({ skill, packagingConfig });
|
|
316
|
-
}
|
|
317
|
-
// Build all skills with a shared registry
|
|
318
|
-
const specs = validatedSpecs.map(({ skill, packagingConfig }) => ({
|
|
319
|
-
skillPath: skill.sourcePath,
|
|
320
|
-
options: packagingConfigToPackageOptions(packagingConfig, {
|
|
321
|
-
skillPath: skill.sourcePath,
|
|
322
|
-
outputPath: safePath.resolve(cwd, 'dist', 'skills', skillNameToFsPath(skill.name)),
|
|
323
|
-
}),
|
|
530
|
+
const buildSpecs = skillsToBuild.map((skill) => ({
|
|
531
|
+
skill,
|
|
532
|
+
packagingConfig: mergeSkillPackagingConfig(skillsConfig.defaults, skillsConfig.config?.[skill.name]),
|
|
324
533
|
}));
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
const
|
|
328
|
-
|
|
329
|
-
const result = packageResults[i];
|
|
330
|
-
if (result) {
|
|
331
|
-
logger.info(` Built ${result.files.dependencies.length + 1} files`);
|
|
332
|
-
logPostBuildIssues(result, logger);
|
|
333
|
-
if (result.hasErrors) {
|
|
334
|
-
skillsWithErrors.push(spec.skill.name);
|
|
335
|
-
}
|
|
336
|
-
results.push({ name: spec.skill.name, result });
|
|
337
|
-
}
|
|
338
|
-
}
|
|
534
|
+
// Assembled ONCE, from the UNFILTERED discovery: `--skill x` narrows the build,
|
|
535
|
+
// not the set of files that count as some skill's declared test input.
|
|
536
|
+
const projectSkills = collectDeclaredEvalSuites(skillsConfig, discoveredSkills);
|
|
537
|
+
const { results, runIssues, skillsWithErrors, failures } = await runSkillBuild(buildSpecs, cwd, logger, projectSkills, options.verbose === true);
|
|
339
538
|
const duration = Date.now() - startTime;
|
|
340
539
|
// Output YAML results
|
|
341
|
-
outputBuildYaml(results, duration);
|
|
540
|
+
outputBuildYaml(results, failures, duration, runIssues, skillsWithErrors);
|
|
541
|
+
for (const line of formatRunIssueLines(runIssues)) {
|
|
542
|
+
logger.info(line);
|
|
543
|
+
}
|
|
544
|
+
if (failures.length > 0) {
|
|
545
|
+
logger.error(`\nBuild failed: ${failures.length} skill(s) could not be packaged at all`);
|
|
546
|
+
for (const { name, message } of failures) {
|
|
547
|
+
logger.error(` - ${name}: ${message.split('\n')[0] ?? message}`);
|
|
548
|
+
}
|
|
549
|
+
}
|
|
342
550
|
if (skillsWithErrors.length > 0) {
|
|
343
551
|
logger.error(`\nBuild failed: ${skillsWithErrors.length} skill(s) emitted post-build validation errors`);
|
|
344
552
|
for (const name of skillsWithErrors) {
|
|
345
553
|
logger.error(` - ${name}`);
|
|
346
554
|
}
|
|
555
|
+
}
|
|
556
|
+
// A run-level finding belongs to no skill, so the loop above cannot carry
|
|
557
|
+
// it. Only `error` severity gates: ALLOW_UNUSED ships as a `warning`, and a
|
|
558
|
+
// warning must never abort a build that produced its artifacts.
|
|
559
|
+
const runHasErrors = runIssues.some((i) => i.severity === 'error');
|
|
560
|
+
if (runHasErrors) {
|
|
561
|
+
logger.error(`\nBuild failed: run-level validation errors (project config, not any one skill)`);
|
|
562
|
+
}
|
|
563
|
+
if (skillsWithErrors.length > 0 || runHasErrors || failures.length > 0) {
|
|
347
564
|
process.exit(1);
|
|
348
565
|
}
|
|
349
566
|
logger.info(`\nBuilt ${results.length} skill(s) successfully`);
|