@shrkcrft/cli 0.1.0-alpha.28 → 0.1.0-alpha.30
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/commands/baseline.command.d.ts +25 -0
- package/dist/commands/baseline.command.d.ts.map +1 -1
- package/dist/commands/baseline.command.js +64 -17
- package/dist/commands/changelog-data.d.ts.map +1 -1
- package/dist/commands/changelog-data.js +46 -0
- package/dist/commands/check.command.d.ts.map +1 -1
- package/dist/commands/check.command.js +137 -12
- package/dist/commands/code-intel.command.d.ts.map +1 -1
- package/dist/commands/code-intel.command.js +5 -1
- package/dist/commands/command-catalog.d.ts.map +1 -1
- package/dist/commands/command-catalog.js +8 -0
- package/dist/commands/daily.commands.d.ts.map +1 -1
- package/dist/commands/daily.commands.js +11 -1
- package/dist/commands/docs-references.command.d.ts +7 -0
- package/dist/commands/docs-references.command.d.ts.map +1 -0
- package/dist/commands/docs-references.command.js +323 -0
- package/dist/commands/doctor.command.d.ts.map +1 -1
- package/dist/commands/doctor.command.js +3 -2
- package/dist/commands/gates.command.d.ts +13 -1
- package/dist/commands/gates.command.d.ts.map +1 -1
- package/dist/commands/gates.command.js +693 -26
- package/dist/commands/generated.command.d.ts +32 -0
- package/dist/commands/generated.command.d.ts.map +1 -1
- package/dist/commands/generated.command.js +214 -53
- package/dist/commands/graph-code-subverbs.d.ts.map +1 -1
- package/dist/commands/graph-code-subverbs.js +5 -1
- package/dist/commands/help.command.d.ts.map +1 -1
- package/dist/commands/help.command.js +64 -2
- package/dist/commands/policy-lint.command.d.ts.map +1 -1
- package/dist/commands/policy-lint.command.js +52 -10
- package/dist/commands/registry.command.d.ts.map +1 -1
- package/dist/commands/registry.command.js +34 -9
- package/dist/commands/wiring.command.d.ts.map +1 -1
- package/dist/commands/wiring.command.js +4 -3
- package/dist/exit-codes.d.ts +27 -7
- package/dist/exit-codes.d.ts.map +1 -1
- package/dist/exit-codes.js +47 -8
- package/dist/gates/gate-envelope.d.ts +64 -0
- package/dist/gates/gate-envelope.d.ts.map +1 -0
- package/dist/gates/gate-envelope.js +26 -0
- package/dist/gates/gate-rule-globs.d.ts +33 -0
- package/dist/gates/gate-rule-globs.d.ts.map +1 -0
- package/dist/gates/gate-rule-globs.js +101 -0
- package/dist/gates/gate-rule-view.d.ts +9 -3
- package/dist/gates/gate-rule-view.d.ts.map +1 -1
- package/dist/gates/gate-rule-view.js +18 -4
- package/dist/gates/rule-coverage.d.ts +39 -1
- package/dist/gates/rule-coverage.d.ts.map +1 -1
- package/dist/gates/rule-coverage.js +123 -8
- package/dist/gates/run-gate-planes.d.ts +44 -0
- package/dist/gates/run-gate-planes.d.ts.map +1 -0
- package/dist/gates/run-gate-planes.js +261 -0
- package/dist/main.d.ts.map +1 -1
- package/dist/main.js +7 -2
- package/package.json +33 -33
|
@@ -1,6 +1,38 @@
|
|
|
1
|
+
import { type IGeneratedArtifactRule } from '@shrkcrft/core';
|
|
2
|
+
import { type IGeneratedTreeDiff, type IProvenanceFinding } from '@shrkcrft/boundaries';
|
|
1
3
|
import { type ICommandHandler } from '../command-registry.js';
|
|
4
|
+
/**
|
|
5
|
+
* One rule's outcome. Exported so `shrk gates check` aggregates the SAME
|
|
6
|
+
* evaluation the per-plane verb runs, rather than a second implementation that
|
|
7
|
+
* could drift from it.
|
|
8
|
+
*/
|
|
9
|
+
export interface IGeneratedOutcome {
|
|
10
|
+
readonly rule: IGeneratedArtifactRule;
|
|
11
|
+
readonly status: 'passed' | 'failed' | 'skipped' | 'error';
|
|
12
|
+
readonly committedCount: number;
|
|
13
|
+
readonly treeDiff?: IGeneratedTreeDiff;
|
|
14
|
+
readonly provenance: readonly IProvenanceFinding[];
|
|
15
|
+
readonly error?: string;
|
|
16
|
+
readonly skipReason?: string;
|
|
17
|
+
/** True when the drift half was deliberately not run (`--headers-only` / no `regen`). */
|
|
18
|
+
readonly driftChecked: boolean;
|
|
19
|
+
/** Files excluded from every check by `handMaintained`. */
|
|
20
|
+
readonly handMaintained: readonly string[];
|
|
21
|
+
/** Per-writer drift results, for a multi-writer rule. */
|
|
22
|
+
readonly writers: readonly IWriterOutcome[];
|
|
23
|
+
}
|
|
24
|
+
/** One writer's slice result inside a multi-writer rule. */
|
|
25
|
+
interface IWriterOutcome {
|
|
26
|
+
readonly label: string;
|
|
27
|
+
readonly committedCount: number;
|
|
28
|
+
readonly differences: number;
|
|
29
|
+
readonly error?: string;
|
|
30
|
+
}
|
|
31
|
+
export declare function evaluateGeneratedRule(cwd: string, rule: IGeneratedArtifactRule, excludeDirs: readonly string[], headersOnly: boolean): IGeneratedOutcome;
|
|
32
|
+
export declare function generatedHintFor(rule: IGeneratedArtifactRule): string;
|
|
2
33
|
export declare const generatedListCommand: ICommandHandler;
|
|
3
34
|
export declare const generatedCheckCommand: ICommandHandler;
|
|
4
35
|
export declare const generatedUpdateCommand: ICommandHandler;
|
|
5
36
|
export declare const generatedExplainCommand: ICommandHandler;
|
|
37
|
+
export {};
|
|
6
38
|
//# sourceMappingURL=generated.command.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"generated.command.d.ts","sourceRoot":"","sources":["../../src/commands/generated.command.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"generated.command.d.ts","sourceRoot":"","sources":["../../src/commands/generated.command.ts"],"names":[],"mappings":"AAsBA,OAAO,EAAkB,KAAK,sBAAsB,EAAE,MAAM,gBAAgB,CAAC;AAC7E,OAAO,EAML,KAAK,kBAAkB,EACvB,KAAK,kBAAkB,EACxB,MAAM,sBAAsB,CAAC;AAE9B,OAAO,EAIL,KAAK,eAAe,EAErB,MAAM,wBAAwB,CAAC;AA0LhC;;;;GAIG;AACH,MAAM,WAAW,iBAAiB;IAChC,QAAQ,CAAC,IAAI,EAAE,sBAAsB,CAAC;IACtC,QAAQ,CAAC,MAAM,EAAE,QAAQ,GAAG,QAAQ,GAAG,SAAS,GAAG,OAAO,CAAC;IAC3D,QAAQ,CAAC,cAAc,EAAE,MAAM,CAAC;IAChC,QAAQ,CAAC,QAAQ,CAAC,EAAE,kBAAkB,CAAC;IACvC,QAAQ,CAAC,UAAU,EAAE,SAAS,kBAAkB,EAAE,CAAC;IACnD,QAAQ,CAAC,KAAK,CAAC,EAAE,MAAM,CAAC;IACxB,QAAQ,CAAC,UAAU,CAAC,EAAE,MAAM,CAAC;IAC7B,yFAAyF;IACzF,QAAQ,CAAC,YAAY,EAAE,OAAO,CAAC;IAC/B,2DAA2D;IAC3D,QAAQ,CAAC,cAAc,EAAE,SAAS,MAAM,EAAE,CAAC;IAC3C,yDAAyD;IACzD,QAAQ,CAAC,OAAO,EAAE,SAAS,cAAc,EAAE,CAAC;CAC7C;AAED,4DAA4D;AAC5D,UAAU,cAAc;IACtB,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC;IACvB,QAAQ,CAAC,cAAc,EAAE,MAAM,CAAC;IAChC,QAAQ,CAAC,WAAW,EAAE,MAAM,CAAC;IAC7B,QAAQ,CAAC,KAAK,CAAC,EAAE,MAAM,CAAC;CACzB;AAED,wBAAgB,qBAAqB,CACnC,GAAG,EAAE,MAAM,EACX,IAAI,EAAE,sBAAsB,EAC5B,WAAW,EAAE,SAAS,MAAM,EAAE,EAC9B,WAAW,EAAE,OAAO,GACnB,iBAAiB,CAqFnB;AAED,wBAAgB,gBAAgB,CAAC,IAAI,EAAE,sBAAsB,GAAG,MAAM,CAOrE;AAwED,eAAO,MAAM,oBAAoB,EAAE,eA4DlC,CAAC;AAEF,eAAO,MAAM,qBAAqB,EAAE,eAgInC,CAAC;AAEF,eAAO,MAAM,sBAAsB,EAAE,eAgEpC,CAAC;AAEF,eAAO,MAAM,uBAAuB,EAAE,eAyGrC,CAAC"}
|
|
@@ -20,11 +20,13 @@ import { spawnSync } from 'node:child_process';
|
|
|
20
20
|
import { mkdtempSync, readFileSync, readdirSync, rmSync, statSync } from 'node:fs';
|
|
21
21
|
import * as nodeOs from 'node:os';
|
|
22
22
|
import * as nodePath from 'node:path';
|
|
23
|
+
import { failsWhenEmpty } from '@shrkcrft/core';
|
|
23
24
|
import { checkProvenanceHeaders, compareGeneratedTrees, scanGeneratedFiles, } from '@shrkcrft/boundaries';
|
|
24
25
|
import { resolveProjectConfig } from '@shrkcrft/inspector';
|
|
25
26
|
import { flagBool, flagString, resolveCwd, } from "../command-registry.js";
|
|
26
27
|
import { ExitCode } from "../exit-codes.js";
|
|
27
28
|
import { asJson, header, kv } from "../output/format-output.js";
|
|
29
|
+
import { buildGateEnvelope } from "../gates/gate-envelope.js";
|
|
28
30
|
const SCHEMA = 'sharkcraft.generated-drift/v1';
|
|
29
31
|
const DEFAULT_TIMEOUT_MS = 120_000;
|
|
30
32
|
/** Cap on the temp tree read — a runaway regen must not be read into memory whole. */
|
|
@@ -125,16 +127,23 @@ function alignToCommitted(temp, committed) {
|
|
|
125
127
|
}
|
|
126
128
|
return out;
|
|
127
129
|
}
|
|
128
|
-
/**
|
|
129
|
-
|
|
130
|
+
/**
|
|
131
|
+
* Run ONE regen command into a fresh temp dir and read the result back, keyed
|
|
132
|
+
* onto the committed paths it corresponds to. Always cleans up.
|
|
133
|
+
*
|
|
134
|
+
* `committed` is the slice this command OWNS, not the whole tree — that is what
|
|
135
|
+
* keeps a multi-writer tree honest: each command's output is aligned against
|
|
136
|
+
* (and later diffed against) only its own files, so writer A's output can never
|
|
137
|
+
* be reported as writer B's stale committed file.
|
|
138
|
+
*/
|
|
139
|
+
function runOneRegen(cwd, command, committed, timeoutMs) {
|
|
130
140
|
const tmp = mkdtempSync(nodePath.join(nodeOs.tmpdir(), 'shrk-generated-'));
|
|
131
141
|
try {
|
|
132
|
-
const
|
|
133
|
-
const child = spawnSync(command, {
|
|
142
|
+
const child = spawnSync(command.split('{TMP}').join(tmp), {
|
|
134
143
|
cwd,
|
|
135
144
|
shell: true,
|
|
136
145
|
encoding: 'utf8',
|
|
137
|
-
timeout:
|
|
146
|
+
timeout: timeoutMs,
|
|
138
147
|
maxBuffer: 16 * 1024 * 1024,
|
|
139
148
|
});
|
|
140
149
|
if (child.error)
|
|
@@ -153,21 +162,48 @@ function runRegen(cwd, rule, committed) {
|
|
|
153
162
|
rmSync(tmp, { recursive: true, force: true });
|
|
154
163
|
}
|
|
155
164
|
}
|
|
156
|
-
|
|
165
|
+
/**
|
|
166
|
+
* The regen units for a rule: one per `sources[]` writer, or a single unit for
|
|
167
|
+
* the classic `regen` form. A rule declaring neither yields none (header-only).
|
|
168
|
+
*/
|
|
169
|
+
function regenUnitsOf(rule, scan) {
|
|
170
|
+
const fallback = rule.timeoutMs ?? DEFAULT_TIMEOUT_MS;
|
|
171
|
+
if (scan.slices.length > 0) {
|
|
172
|
+
return scan.slices.map((slice) => ({
|
|
173
|
+
label: slice.label,
|
|
174
|
+
command: slice.regen,
|
|
175
|
+
committed: slice.files,
|
|
176
|
+
timeoutMs: slice.timeoutMs ?? fallback,
|
|
177
|
+
}));
|
|
178
|
+
}
|
|
179
|
+
if (rule.regen === undefined)
|
|
180
|
+
return [];
|
|
181
|
+
// Single-writer: the checkable set, so a hand-maintained bless inside the
|
|
182
|
+
// glob is not compared against output no generator produces.
|
|
183
|
+
return [{ label: rule.id, command: rule.regen, committed: scan.checkable, timeoutMs: fallback }];
|
|
184
|
+
}
|
|
185
|
+
export function evaluateGeneratedRule(cwd, rule, excludeDirs, headersOnly) {
|
|
157
186
|
const scan = scanGeneratedFiles(cwd, rule, excludeDirs);
|
|
158
187
|
const severity = rule.severity ?? 'error';
|
|
159
188
|
if (scan.generated.size === 0) {
|
|
160
|
-
const failed = rule
|
|
189
|
+
const failed = failsWhenEmpty(rule);
|
|
161
190
|
return {
|
|
162
191
|
rule,
|
|
163
192
|
status: failed ? 'failed' : 'skipped',
|
|
164
193
|
committedCount: 0,
|
|
165
194
|
provenance: [],
|
|
166
195
|
driftChecked: false,
|
|
196
|
+
handMaintained: [],
|
|
197
|
+
writers: [],
|
|
167
198
|
skipReason: `0 files matched generatedGlob (${rule.generatedGlob.join(', ')})`,
|
|
168
199
|
};
|
|
169
200
|
}
|
|
170
|
-
|
|
201
|
+
// Headers + byte checks run over the CHECKABLE set — a hand-maintained bless
|
|
202
|
+
// is excluded from both, which is the whole point of declaring it.
|
|
203
|
+
const headers = checkProvenanceHeaders(rule, scan.checkable, scan.outside, {
|
|
204
|
+
unclassified: scan.unclassified,
|
|
205
|
+
staleHandMaintained: scan.staleHandMaintained,
|
|
206
|
+
});
|
|
171
207
|
if (headers.error) {
|
|
172
208
|
return {
|
|
173
209
|
rule,
|
|
@@ -175,21 +211,39 @@ function evaluateRule(cwd, rule, excludeDirs, headersOnly) {
|
|
|
175
211
|
committedCount: scan.generated.size,
|
|
176
212
|
provenance: [],
|
|
177
213
|
driftChecked: false,
|
|
214
|
+
handMaintained: scan.handMaintained,
|
|
215
|
+
writers: [],
|
|
178
216
|
error: headers.error,
|
|
179
217
|
};
|
|
180
218
|
}
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
const
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
219
|
+
const units = headersOnly ? [] : regenUnitsOf(rule, scan);
|
|
220
|
+
const differences = [];
|
|
221
|
+
const writers = [];
|
|
222
|
+
const errors = [];
|
|
223
|
+
let committedCompared = 0;
|
|
224
|
+
let regeneratedCount = 0;
|
|
225
|
+
for (const unit of units) {
|
|
226
|
+
const regen = runOneRegen(cwd, unit.command, unit.committed, unit.timeoutMs);
|
|
227
|
+
if (regen.error) {
|
|
228
|
+
errors.push(units.length > 1 ? `${unit.label}: ${regen.error}` : regen.error);
|
|
229
|
+
writers.push({ label: unit.label, committedCount: unit.committed.size, differences: 0, error: regen.error });
|
|
230
|
+
continue;
|
|
231
|
+
}
|
|
232
|
+
const diff = compareGeneratedTrees(unit.committed, regen.files, rule.compare ?? 'bytes');
|
|
233
|
+
differences.push(...diff.differences);
|
|
234
|
+
committedCompared += diff.committedCount;
|
|
235
|
+
regeneratedCount += diff.regeneratedCount;
|
|
236
|
+
writers.push({ label: unit.label, committedCount: unit.committed.size, differences: diff.differences.length });
|
|
190
237
|
}
|
|
238
|
+
const ranAnyWriter = units.length > 0 && errors.length < units.length;
|
|
239
|
+
const treeDiff = ranAnyWriter
|
|
240
|
+
? { differences, committedCount: committedCompared, regeneratedCount }
|
|
241
|
+
: undefined;
|
|
242
|
+
const error = errors.length > 0 ? errors.join(' · ') : undefined;
|
|
191
243
|
const hardFindings = headers.findings.filter((f) => f.severity === 'error');
|
|
192
|
-
const drifted =
|
|
244
|
+
const drifted = differences.length > 0;
|
|
245
|
+
// A writer that failed to RUN proved nothing, so the rule is in error even if
|
|
246
|
+
// its siblings were clean — a partial regen must never read as a full pass.
|
|
193
247
|
const status = error !== undefined
|
|
194
248
|
? 'error'
|
|
195
249
|
: drifted || (hardFindings.length > 0 && severity === 'error')
|
|
@@ -202,12 +256,14 @@ function evaluateRule(cwd, rule, excludeDirs, headersOnly) {
|
|
|
202
256
|
...(treeDiff ? { treeDiff } : {}),
|
|
203
257
|
provenance: headers.findings,
|
|
204
258
|
...(error ? { error } : {}),
|
|
205
|
-
driftChecked:
|
|
259
|
+
driftChecked: units.length > 0 && errors.length === 0,
|
|
260
|
+
handMaintained: scan.handMaintained,
|
|
261
|
+
writers: writers.length > 1 ? writers : [],
|
|
206
262
|
};
|
|
207
263
|
}
|
|
208
|
-
function
|
|
264
|
+
export function generatedHintFor(rule) {
|
|
209
265
|
return (rule.hint ??
|
|
210
|
-
(rule.regen
|
|
266
|
+
(rule.regen || rule.sources
|
|
211
267
|
? `regenerate with \`shrk generated update --id ${rule.id}\` and commit the result`
|
|
212
268
|
: 'add the provenance header to the generated file, or move it out of the generated glob'));
|
|
213
269
|
}
|
|
@@ -219,11 +275,13 @@ function outcomeJson(o) {
|
|
|
219
275
|
severity: o.rule.severity ?? 'error',
|
|
220
276
|
committedCount: o.committedCount,
|
|
221
277
|
driftChecked: o.driftChecked,
|
|
278
|
+
handMaintained: o.handMaintained,
|
|
279
|
+
...(o.writers.length > 0 ? { writers: o.writers } : {}),
|
|
222
280
|
...(o.treeDiff ? { differences: o.treeDiff.differences, regeneratedCount: o.treeDiff.regeneratedCount } : {}),
|
|
223
281
|
provenance: o.provenance,
|
|
224
282
|
...(o.error ? { error: o.error } : {}),
|
|
225
283
|
...(o.skipReason ? { skipReason: o.skipReason } : {}),
|
|
226
|
-
hint:
|
|
284
|
+
hint: generatedHintFor(o.rule),
|
|
227
285
|
};
|
|
228
286
|
}
|
|
229
287
|
async function prepare(args) {
|
|
@@ -235,7 +293,7 @@ async function prepare(args) {
|
|
|
235
293
|
process.stdout.write(asJson({ schema: SCHEMA, error: loaded.message }) + '\n');
|
|
236
294
|
else
|
|
237
295
|
process.stderr.write(`Could not load config: ${loaded.message}\n Run \`shrk doctor\` for details.\n`);
|
|
238
|
-
return { ok: false, code: ExitCode.
|
|
296
|
+
return { ok: false, code: ExitCode.UsageError };
|
|
239
297
|
}
|
|
240
298
|
const id = flagString(args, 'id');
|
|
241
299
|
let rules = loaded.value.rules;
|
|
@@ -245,7 +303,7 @@ async function prepare(args) {
|
|
|
245
303
|
const unknown = wanted.filter((w) => !known.has(w));
|
|
246
304
|
if (unknown.length > 0) {
|
|
247
305
|
process.stderr.write(`Unknown generated-artifact id(s): ${unknown.join(', ')}. Declared: ${[...known].join(', ') || '(none)'}\n`);
|
|
248
|
-
return { ok: false, code: ExitCode.
|
|
306
|
+
return { ok: false, code: ExitCode.UsageError };
|
|
249
307
|
}
|
|
250
308
|
rules = rules.filter((r) => wanted.includes(r.id));
|
|
251
309
|
}
|
|
@@ -289,6 +347,9 @@ export const generatedListCommand = {
|
|
|
289
347
|
description: r.description ?? null,
|
|
290
348
|
generatedGlob: r.generatedGlob,
|
|
291
349
|
regen: r.regen ?? null,
|
|
350
|
+
sources: r.sources ?? null,
|
|
351
|
+
handMaintained: r.handMaintained ?? null,
|
|
352
|
+
handMaintainedMarker: r.handMaintainedMarker ?? null,
|
|
292
353
|
compare: r.compare ?? 'bytes',
|
|
293
354
|
provenanceHeader: r.provenanceHeader ?? null,
|
|
294
355
|
failOnEmpty: r.failOnEmpty === true,
|
|
@@ -301,7 +362,22 @@ export const generatedListCommand = {
|
|
|
301
362
|
for (const r of prep.all) {
|
|
302
363
|
process.stdout.write(` • ${r.id}\n`);
|
|
303
364
|
process.stdout.write(` glob ${r.generatedGlob.join(', ')}\n`);
|
|
304
|
-
|
|
365
|
+
if (r.sources && r.sources.length > 0) {
|
|
366
|
+
process.stdout.write(` regen ${r.sources.length} writer(s):\n`);
|
|
367
|
+
r.sources.forEach((src, i) => {
|
|
368
|
+
process.stdout.write(` [${src.id ?? i}] ${src.regen}\n`);
|
|
369
|
+
process.stdout.write(` owns ${src.glob.join(', ')}\n`);
|
|
370
|
+
});
|
|
371
|
+
}
|
|
372
|
+
else {
|
|
373
|
+
process.stdout.write(` regen ${r.regen ?? '(header-only — never spawns)'}\n`);
|
|
374
|
+
}
|
|
375
|
+
if (r.handMaintained && r.handMaintained.length > 0) {
|
|
376
|
+
process.stdout.write(` hand ${r.handMaintained.join(', ')} (exempt from header + byte checks)\n`);
|
|
377
|
+
}
|
|
378
|
+
if (r.handMaintainedMarker) {
|
|
379
|
+
process.stdout.write(` marker /${r.handMaintainedMarker}/ (in-file bless)\n`);
|
|
380
|
+
}
|
|
305
381
|
if (r.provenanceHeader) {
|
|
306
382
|
process.stdout.write(` header /${r.provenanceHeader.mustMatch}/${r.provenanceHeader.forbidOutside ? ' + mislabel check' : ''}\n`);
|
|
307
383
|
}
|
|
@@ -326,12 +402,13 @@ export const generatedCheckCommand = {
|
|
|
326
402
|
const headersOnly = flagBool(args, 'headers-only');
|
|
327
403
|
if (prep.rules.length === 0)
|
|
328
404
|
return writeNoRules(json);
|
|
329
|
-
const outcomes = prep.rules.map((r) =>
|
|
405
|
+
const outcomes = prep.rules.map((r) => evaluateGeneratedRule(prep.cwd, r, prep.excludeDirs, headersOnly));
|
|
330
406
|
const failed = outcomes.filter((o) => o.status === 'failed' || (o.status === 'error' && (o.rule.severity ?? 'error') === 'error'));
|
|
331
407
|
const evaluated = outcomes.filter((o) => o.status !== 'skipped').length;
|
|
408
|
+
const skippedCount = outcomes.length - evaluated;
|
|
332
409
|
const exit = failed.length > 0
|
|
333
410
|
? ExitCode.Failure
|
|
334
|
-
: evaluated === 0
|
|
411
|
+
: evaluated === 0 || skippedCount > 0
|
|
335
412
|
? ExitCode.NotVerified
|
|
336
413
|
: ExitCode.VerifiedPass;
|
|
337
414
|
if (json) {
|
|
@@ -343,6 +420,33 @@ export const generatedCheckCommand = {
|
|
|
343
420
|
skipped: outcomes.filter((o) => o.status === 'skipped').length,
|
|
344
421
|
verdict: failed.length > 0 ? 'errors' : evaluated === 0 ? 'not-verified' : 'pass',
|
|
345
422
|
diagnostics: prep.planeDiagnostics,
|
|
423
|
+
gate: buildGateEnvelope('generated check', exit, outcomes.map((o) => ({
|
|
424
|
+
id: o.rule.id,
|
|
425
|
+
type: 'generated',
|
|
426
|
+
status: o.status,
|
|
427
|
+
severity: o.rule.severity ?? 'error',
|
|
428
|
+
counts: {
|
|
429
|
+
files: o.committedCount,
|
|
430
|
+
differences: o.treeDiff?.differences.length ?? 0,
|
|
431
|
+
provenance: o.provenance.length,
|
|
432
|
+
},
|
|
433
|
+
violations: [
|
|
434
|
+
...(o.treeDiff?.differences ?? []).map((d) => ({
|
|
435
|
+
id: d.file,
|
|
436
|
+
file: d.file,
|
|
437
|
+
message: d.kind,
|
|
438
|
+
hint: generatedHintFor(o.rule),
|
|
439
|
+
})),
|
|
440
|
+
...o.provenance.map((f) => ({
|
|
441
|
+
id: f.file,
|
|
442
|
+
file: f.file,
|
|
443
|
+
message: f.message,
|
|
444
|
+
hint: generatedHintFor(o.rule),
|
|
445
|
+
})),
|
|
446
|
+
],
|
|
447
|
+
...(o.skipReason ? { skipReason: o.skipReason } : {}),
|
|
448
|
+
...(o.error ? { error: o.error } : {}),
|
|
449
|
+
}))),
|
|
346
450
|
}) + '\n');
|
|
347
451
|
return exit;
|
|
348
452
|
}
|
|
@@ -361,11 +465,18 @@ export const generatedCheckCommand = {
|
|
|
361
465
|
}
|
|
362
466
|
const diffs = o.treeDiff?.differences ?? [];
|
|
363
467
|
if (o.status === 'passed') {
|
|
364
|
-
|
|
468
|
+
const exempt = o.handMaintained.length > 0 ? `, ${o.handMaintained.length} hand-maintained` : '';
|
|
469
|
+
process.stdout.write(` ✓ ${o.rule.id} (${o.committedCount} files${exempt}` +
|
|
365
470
|
`${o.driftChecked ? ', byte-identical to a fresh regen' : ', headers only'})\n`);
|
|
471
|
+
for (const w of o.writers) {
|
|
472
|
+
process.stdout.write(` · ${w.label}: ${w.committedCount} file(s) verified\n`);
|
|
473
|
+
}
|
|
366
474
|
}
|
|
367
475
|
else {
|
|
368
476
|
process.stdout.write(` ✗ ${o.rule.id} ${diffs.length} file(s) differ from a fresh regen\n`);
|
|
477
|
+
for (const w of o.writers) {
|
|
478
|
+
process.stdout.write(` · ${w.label}: ${w.error ? `ERROR — ${w.error}` : `${w.differences} of ${w.committedCount} differ`}\n`);
|
|
479
|
+
}
|
|
369
480
|
for (const d of diffs.slice(0, 25)) {
|
|
370
481
|
const label = d.kind === 'content'
|
|
371
482
|
? 'hand-edited (or source changed)'
|
|
@@ -384,7 +495,7 @@ export const generatedCheckCommand = {
|
|
|
384
495
|
process.stdout.write(` … (${o.provenance.length - 25} more header finding(s))\n`);
|
|
385
496
|
}
|
|
386
497
|
if (o.status === 'failed')
|
|
387
|
-
process.stdout.write(` → ${
|
|
498
|
+
process.stdout.write(` → ${generatedHintFor(o.rule)}\n`);
|
|
388
499
|
}
|
|
389
500
|
for (const d of prep.planeDiagnostics)
|
|
390
501
|
process.stdout.write(` ! ${d}\n`);
|
|
@@ -411,29 +522,41 @@ export const generatedUpdateCommand = {
|
|
|
411
522
|
return writeNoRules(json);
|
|
412
523
|
const results = [];
|
|
413
524
|
for (const rule of prep.rules) {
|
|
414
|
-
|
|
525
|
+
// A multi-writer rule blesses by running EVERY writer — regenerating one
|
|
526
|
+
// slice and calling the artifact updated is how a mixed tree drifts.
|
|
527
|
+
const commands = rule.sources && rule.sources.length > 0
|
|
528
|
+
? rule.sources.map((src, i) => ({
|
|
529
|
+
label: `${rule.id}/${src.id ?? i}`,
|
|
530
|
+
command: src.regen,
|
|
531
|
+
timeoutMs: src.timeoutMs ?? rule.timeoutMs ?? DEFAULT_TIMEOUT_MS,
|
|
532
|
+
}))
|
|
533
|
+
: rule.regen
|
|
534
|
+
? [{ label: rule.id, command: rule.regen, timeoutMs: rule.timeoutMs ?? DEFAULT_TIMEOUT_MS }]
|
|
535
|
+
: [];
|
|
536
|
+
if (commands.length === 0) {
|
|
415
537
|
results.push({ id: rule.id, ran: false, error: 'header-only rule — nothing to regenerate' });
|
|
416
538
|
continue;
|
|
417
539
|
}
|
|
418
|
-
|
|
419
|
-
|
|
420
|
-
|
|
421
|
-
|
|
422
|
-
|
|
423
|
-
|
|
424
|
-
|
|
425
|
-
|
|
426
|
-
|
|
427
|
-
|
|
428
|
-
|
|
429
|
-
|
|
430
|
-
|
|
431
|
-
|
|
432
|
-
|
|
433
|
-
|
|
434
|
-
|
|
435
|
-
|
|
436
|
-
|
|
540
|
+
for (const { label, command, timeoutMs } of commands) {
|
|
541
|
+
// `{TMP}` is the CHECK contract; `update` writes in place, so it is
|
|
542
|
+
// substituted with the project root and the regen writes its real output.
|
|
543
|
+
const child = spawnSync(command.split('{TMP}').join(prep.cwd), {
|
|
544
|
+
cwd: prep.cwd,
|
|
545
|
+
shell: true,
|
|
546
|
+
encoding: 'utf8',
|
|
547
|
+
timeout: timeoutMs,
|
|
548
|
+
maxBuffer: 16 * 1024 * 1024,
|
|
549
|
+
stdio: json ? 'pipe' : 'inherit',
|
|
550
|
+
});
|
|
551
|
+
if (child.error) {
|
|
552
|
+
results.push({ id: label, ran: false, error: child.error.message });
|
|
553
|
+
}
|
|
554
|
+
else if (child.status !== 0) {
|
|
555
|
+
results.push({ id: label, ran: true, error: `exited ${child.status ?? 'null'}` });
|
|
556
|
+
}
|
|
557
|
+
else {
|
|
558
|
+
results.push({ id: label, ran: true });
|
|
559
|
+
}
|
|
437
560
|
}
|
|
438
561
|
}
|
|
439
562
|
const failed = results.filter((r) => r.error !== undefined);
|
|
@@ -460,7 +583,7 @@ export const generatedExplainCommand = {
|
|
|
460
583
|
const id = flagString(args, 'id') ?? args.positional[0];
|
|
461
584
|
if (!id) {
|
|
462
585
|
process.stderr.write('Usage: shrk generated explain --id <id>\n');
|
|
463
|
-
return ExitCode.
|
|
586
|
+
return ExitCode.UsageError;
|
|
464
587
|
}
|
|
465
588
|
const prep = await prepare(args);
|
|
466
589
|
if (!prep.ok)
|
|
@@ -468,16 +591,27 @@ export const generatedExplainCommand = {
|
|
|
468
591
|
const rule = prep.all.find((r) => r.id === id);
|
|
469
592
|
if (!rule) {
|
|
470
593
|
process.stderr.write(`No generated-artifact rule "${id}". Declared: ${prep.all.map((r) => r.id).join(', ') || '(none)'}\n`);
|
|
471
|
-
return ExitCode.
|
|
594
|
+
return ExitCode.UsageError;
|
|
472
595
|
}
|
|
473
596
|
// explain never spawns — the point is to show what the rule SEES.
|
|
474
597
|
const scan = scanGeneratedFiles(prep.cwd, rule, prep.excludeDirs);
|
|
475
|
-
const outcome =
|
|
598
|
+
const outcome = evaluateGeneratedRule(prep.cwd, rule, prep.excludeDirs, true);
|
|
476
599
|
if (flagBool(args, 'json')) {
|
|
477
600
|
process.stdout.write(asJson({
|
|
478
601
|
schema: 'sharkcraft.generated-explain/v1',
|
|
479
602
|
...outcomeJson(outcome),
|
|
480
603
|
files: [...scan.generated.keys()],
|
|
604
|
+
checkable: [...scan.checkable.keys()],
|
|
605
|
+
handMaintained: scan.handMaintained,
|
|
606
|
+
markedHandMaintained: scan.markedHandMaintained,
|
|
607
|
+
staleHandMaintained: scan.staleHandMaintained,
|
|
608
|
+
unclassified: scan.unclassified,
|
|
609
|
+
slices: scan.slices.map((sl) => ({
|
|
610
|
+
label: sl.label,
|
|
611
|
+
regen: sl.regen,
|
|
612
|
+
glob: sl.glob,
|
|
613
|
+
files: [...sl.files.keys()],
|
|
614
|
+
})),
|
|
481
615
|
outsideScanned: scan.outside.size,
|
|
482
616
|
outsideGlobs: scan.outsideGlobs,
|
|
483
617
|
regen: rule.regen ?? null,
|
|
@@ -489,7 +623,34 @@ export const generatedExplainCommand = {
|
|
|
489
623
|
process.stdout.write(` ${rule.description}\n`);
|
|
490
624
|
process.stdout.write(kv('glob', rule.generatedGlob.join(', ')) + '\n');
|
|
491
625
|
process.stdout.write(kv('files matched', String(scan.generated.size)) + '\n');
|
|
492
|
-
|
|
626
|
+
if (scan.slices.length > 0) {
|
|
627
|
+
process.stdout.write(kv('writers', String(scan.slices.length)) + '\n');
|
|
628
|
+
for (const sl of scan.slices) {
|
|
629
|
+
process.stdout.write(` [${sl.label}] ${sl.files.size} file(s) — ${sl.regen}\n`);
|
|
630
|
+
process.stdout.write(` owns ${sl.glob.join(', ')}\n`);
|
|
631
|
+
}
|
|
632
|
+
}
|
|
633
|
+
else {
|
|
634
|
+
process.stdout.write(kv('regen', rule.regen ?? '(header-only)') + '\n');
|
|
635
|
+
}
|
|
636
|
+
if (scan.handMaintained.length > 0) {
|
|
637
|
+
process.stdout.write(kv('hand-maintained', `${scan.handMaintained.length} file(s) — exempt from header + byte checks`) + '\n');
|
|
638
|
+
const marked = new Set(scan.markedHandMaintained);
|
|
639
|
+
// Say WHICH mechanism blessed each file: a config entry and an in-file
|
|
640
|
+
// marker are reviewed in different places, so "why is this exempt?" has
|
|
641
|
+
// two different answers and the reader needs to know which one applies.
|
|
642
|
+
for (const f of scan.handMaintained.slice(0, 20)) {
|
|
643
|
+
process.stdout.write(` ${f}${marked.has(f) ? ' (in-file marker)' : ' (handMaintained[])'}\n`);
|
|
644
|
+
}
|
|
645
|
+
}
|
|
646
|
+
if (scan.unclassified.length > 0) {
|
|
647
|
+
process.stdout.write(kv('unclassified', `${scan.unclassified.length} file(s) — owned by no writer, not blessed`) + '\n');
|
|
648
|
+
for (const f of scan.unclassified.slice(0, 20))
|
|
649
|
+
process.stdout.write(` ${f}\n`);
|
|
650
|
+
}
|
|
651
|
+
for (const pattern of scan.staleHandMaintained) {
|
|
652
|
+
process.stdout.write(` ! handMaintained "${pattern}" matches no file — stale bless\n`);
|
|
653
|
+
}
|
|
493
654
|
process.stdout.write(kv('compare', rule.compare ?? 'bytes') + '\n');
|
|
494
655
|
if (rule.provenanceHeader) {
|
|
495
656
|
process.stdout.write(kv('header', `/${rule.provenanceHeader.mustMatch}/`) + '\n');
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"graph-code-subverbs.d.ts","sourceRoot":"","sources":["../../src/commands/graph-code-subverbs.ts"],"names":[],"mappings":"AA2BA,OAAO,EAAiE,KAAK,UAAU,EAAE,MAAM,wBAAwB,CAAC;AAgLxH,wBAAsB,aAAa,CAAC,IAAI,EAAE,UAAU,GAAG,OAAO,CAAC,MAAM,CAAC,CAkBrE;AA4FD,wBAAsB,cAAc,CAAC,IAAI,EAAE,UAAU,GAAG,OAAO,CAAC,MAAM,CAAC,CAkFtE;AAiBD,wBAAsB,kBAAkB,CAAC,IAAI,EAAE,UAAU,GAAG,OAAO,CAAC,MAAM,CAAC,CA2F1E;AAID,wBAAsB,YAAY,CAAC,IAAI,EAAE,UAAU,GAAG,OAAO,CAAC,MAAM,CAAC,CA+EpE;AAID,wBAAsB,cAAc,CAAC,IAAI,EAAE,UAAU,GAAG,OAAO,CAAC,MAAM,CAAC,
|
|
1
|
+
{"version":3,"file":"graph-code-subverbs.d.ts","sourceRoot":"","sources":["../../src/commands/graph-code-subverbs.ts"],"names":[],"mappings":"AA2BA,OAAO,EAAiE,KAAK,UAAU,EAAE,MAAM,wBAAwB,CAAC;AAgLxH,wBAAsB,aAAa,CAAC,IAAI,EAAE,UAAU,GAAG,OAAO,CAAC,MAAM,CAAC,CAkBrE;AA4FD,wBAAsB,cAAc,CAAC,IAAI,EAAE,UAAU,GAAG,OAAO,CAAC,MAAM,CAAC,CAkFtE;AAiBD,wBAAsB,kBAAkB,CAAC,IAAI,EAAE,UAAU,GAAG,OAAO,CAAC,MAAM,CAAC,CA2F1E;AAID,wBAAsB,YAAY,CAAC,IAAI,EAAE,UAAU,GAAG,OAAO,CAAC,MAAM,CAAC,CA+EpE;AAID,wBAAsB,cAAc,CAAC,IAAI,EAAE,UAAU,GAAG,OAAO,CAAC,MAAM,CAAC,CAmGtE;AAID,wBAAsB,cAAc,CAAC,IAAI,EAAE,UAAU,GAAG,OAAO,CAAC,MAAM,CAAC,CAwEtE;AAID,wBAAsB,eAAe,CAAC,IAAI,EAAE,UAAU,GAAG,OAAO,CAAC,MAAM,CAAC,CA2MvE;AAID,wBAAsB,cAAc,CAAC,IAAI,EAAE,UAAU,GAAG,OAAO,CAAC,MAAM,CAAC,CA+HtE;AAID;;;;;;GAMG;AACH,wBAAsB,YAAY,CAAC,IAAI,EAAE,UAAU,GAAG,OAAO,CAAC,MAAM,CAAC,CAgEpE;AAID,wBAAsB,eAAe,CAAC,IAAI,EAAE,UAAU,GAAG,OAAO,CAAC,MAAM,CAAC,CAiGvE;AAyBD;;;;;;;;;;;;GAYG;AACH,wBAAsB,YAAY,CAAC,IAAI,EAAE,UAAU,GAAG,OAAO,CAAC,MAAM,CAAC,CAgHpE"}
|
|
@@ -594,7 +594,11 @@ export async function runGraphStatus(args) {
|
|
|
594
594
|
}
|
|
595
595
|
process.stdout.write(header('Graph status'));
|
|
596
596
|
process.stdout.write(kv('schema', payload.schema) + '\n');
|
|
597
|
-
|
|
597
|
+
// "files indexed", not "files": this is the size of the STORED snapshot, and
|
|
598
|
+
// it deliberately does not move when a new file appears on disk — that shows
|
|
599
|
+
// up on the `drift` line below. Reading it as a live count is how an added
|
|
600
|
+
// file looks invisible to the index.
|
|
601
|
+
process.stdout.write(kv('files indexed', String(payload.fileCount)) + '\n');
|
|
598
602
|
process.stdout.write(kv('nodes', String(payload.nodeCount)) + '\n');
|
|
599
603
|
process.stdout.write(kv('edges', String(payload.edgeCount)) + '\n');
|
|
600
604
|
process.stdout.write(kv('packages', String(payload.workspacePackages.length)) + '\n');
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"help.command.d.ts","sourceRoot":"","sources":["../../src/commands/help.command.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,wBAAwB,CAAC;
|
|
1
|
+
{"version":3,"file":"help.command.d.ts","sourceRoot":"","sources":["../../src/commands/help.command.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,wBAAwB,CAAC;AA4H9D;;;;;;;;GAQG;AACH,wBAAgB,iBAAiB,IAAI,MAAM,CAwC1C;AAED,wBAAgB,eAAe,CAAC,QAAQ,EAAE,eAAe;;;;cAK3C;QAAE,UAAU,EAAE,MAAM,EAAE,CAAC;QAAC,KAAK,EAAE,GAAG,CAAC,MAAM,EAAE,MAAM,GAAG,OAAO,CAAC,CAAA;KAAE,GAAG,MAAM;EA2KpF"}
|
|
@@ -1,5 +1,45 @@
|
|
|
1
1
|
import { header } from "../output/format-output.js";
|
|
2
2
|
import { COMMAND_CATALOG, defaultShowInHelp, listExplainFamily } from "./command-catalog.js";
|
|
3
|
+
/**
|
|
4
|
+
* Every multi-token command path the catalog documents. These are real,
|
|
5
|
+
* callable verbs that the command trie never sees, because their parent
|
|
6
|
+
* dispatches them from a positional argument rather than registering them.
|
|
7
|
+
*/
|
|
8
|
+
function catalogHelpPaths() {
|
|
9
|
+
const paths = new Set();
|
|
10
|
+
for (const entry of COMMAND_CATALOG) {
|
|
11
|
+
// Strip the flag/argument tail a few catalog entries carry in `command`.
|
|
12
|
+
const clean = entry.command.split(/\s+--/)[0].trim();
|
|
13
|
+
if (clean.length > 0)
|
|
14
|
+
paths.add(clean);
|
|
15
|
+
}
|
|
16
|
+
return paths;
|
|
17
|
+
}
|
|
18
|
+
/**
|
|
19
|
+
* Render help for a command path the trie could not resolve but the catalog
|
|
20
|
+
* documents, plus its sibling verbs under the same parent so the family is
|
|
21
|
+
* discoverable from any one member.
|
|
22
|
+
*/
|
|
23
|
+
function renderCatalogHelp(tokens) {
|
|
24
|
+
const want = tokens.join(' ');
|
|
25
|
+
const entry = COMMAND_CATALOG.find((e) => e.command.split(/\s+--/)[0].trim() === want);
|
|
26
|
+
if (!entry)
|
|
27
|
+
return undefined;
|
|
28
|
+
let out = `${want} — ${entry.description}\n`;
|
|
29
|
+
const extra = EXTRA_HELP_LINES[want];
|
|
30
|
+
if (extra)
|
|
31
|
+
out += extra.join('\n') + '\n';
|
|
32
|
+
const parent = tokens.slice(0, -1).join(' ');
|
|
33
|
+
if (parent.length > 0) {
|
|
34
|
+
const siblings = [...catalogHelpPaths()]
|
|
35
|
+
.filter((p) => p !== want && p.startsWith(parent + ' ') && !p.slice(parent.length + 1).includes(' '))
|
|
36
|
+
.sort();
|
|
37
|
+
if (siblings.length > 0) {
|
|
38
|
+
out += `\nSiblings: ${siblings.join(', ')}\n`;
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
return out;
|
|
42
|
+
}
|
|
3
43
|
/** First sentence of a catalog description, for the compact explain-family list. */
|
|
4
44
|
function firstSentence(description) {
|
|
5
45
|
const dot = description.indexOf('. ');
|
|
@@ -156,8 +196,17 @@ export function makeHelpCommand(registry) {
|
|
|
156
196
|
// that exits 0. Error out honestly instead, with a did-you-mean when
|
|
157
197
|
// a real topic is a near-typo of the request.
|
|
158
198
|
const attempt = tokens.join(' ');
|
|
199
|
+
// The trie matched nothing, but the CATALOG may still document this
|
|
200
|
+
// path — a documented verb whose parent isn't a registered command
|
|
201
|
+
// is still real and callable.
|
|
202
|
+
const viaCatalog = renderCatalogHelp(tokens);
|
|
203
|
+
if (viaCatalog !== undefined) {
|
|
204
|
+
process.stdout.write(viaCatalog);
|
|
205
|
+
return 0;
|
|
206
|
+
}
|
|
159
207
|
process.stderr.write(`no such help topic: '${attempt}'\n`);
|
|
160
|
-
const suggestion = nearestHelpTopic(attempt, realHelpTopics(registry))
|
|
208
|
+
const suggestion = nearestHelpTopic(attempt, realHelpTopics(registry)) ??
|
|
209
|
+
nearestHelpTopic(attempt, catalogHelpPaths());
|
|
161
210
|
if (suggestion)
|
|
162
211
|
process.stderr.write(`Did you mean: ${suggestion}?\n`);
|
|
163
212
|
return 1;
|
|
@@ -199,7 +248,20 @@ export function makeHelpCommand(registry) {
|
|
|
199
248
|
}
|
|
200
249
|
return 0;
|
|
201
250
|
}
|
|
202
|
-
|
|
251
|
+
// The trie could not resolve the full path, but the CATALOG may still
|
|
252
|
+
// document it. Verbs like `check wiring` are dispatched from inside
|
|
253
|
+
// their parent's handler on a positional, so they are real, callable
|
|
254
|
+
// and documented — yet never trie nodes. Falling through to "Unknown
|
|
255
|
+
// command" made an entire documented surface look non-existent.
|
|
256
|
+
const catalogHelp = renderCatalogHelp(tokens);
|
|
257
|
+
if (catalogHelp !== undefined) {
|
|
258
|
+
process.stdout.write(catalogHelp);
|
|
259
|
+
return 0;
|
|
260
|
+
}
|
|
261
|
+
process.stderr.write(`no such help topic: '${tokens.join(' ')}'\n`);
|
|
262
|
+
const near = nearestHelpTopic(tokens.join(' '), catalogHelpPaths());
|
|
263
|
+
if (near)
|
|
264
|
+
process.stderr.write(`Did you mean: shrk help ${near}?\n`);
|
|
203
265
|
return 1;
|
|
204
266
|
}
|
|
205
267
|
if (!wantsFull) {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"policy-lint.command.d.ts","sourceRoot":"","sources":["../../src/commands/policy-lint.command.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,WAAW,EAAE,aAAa,EAAE,MAAM,gBAAgB,CAAC;AACjE,OAAO,EAEL,KAAK,cAAc,EAEnB,KAAK,kBAAkB,EACxB,MAAM,sBAAsB,CAAC;AAE9B,OAAO,EAIL,KAAK,eAAe,EAErB,MAAM,wBAAwB,CAAC;
|
|
1
|
+
{"version":3,"file":"policy-lint.command.d.ts","sourceRoot":"","sources":["../../src/commands/policy-lint.command.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,WAAW,EAAE,aAAa,EAAE,MAAM,gBAAgB,CAAC;AACjE,OAAO,EAEL,KAAK,cAAc,EAEnB,KAAK,kBAAkB,EACxB,MAAM,sBAAsB,CAAC;AAE9B,OAAO,EAIL,KAAK,eAAe,EAErB,MAAM,wBAAwB,CAAC;AAQhC,eAAO,MAAM,qBAAqB,EAAG,8BAAuC,CAAC;AAE7E,8DAA8D;AAC9D,MAAM,WAAW,cAAc;IAC7B,QAAQ,CAAC,MAAM,EAAE,OAAO,qBAAqB,CAAC;IAC9C,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;IACxB,QAAQ,CAAC,WAAW,CAAC,EAAE,MAAM,CAAC;IAC9B,QAAQ,CAAC,OAAO,EAAE,aAAa,CAAC;IAChC,QAAQ,CAAC,QAAQ,EAAE,OAAO,GAAG,SAAS,CAAC;IACvC,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAC;IACzB,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,yEAAyE;IACzE,QAAQ,CAAC,YAAY,EAAE,MAAM,CAAC;IAC9B,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;IACxB,8CAA8C;IAC9C,QAAQ,CAAC,QAAQ,EAAE,SAAS,cAAc,EAAE,CAAC;IAC7C,8EAA8E;IAC9E,QAAQ,CAAC,UAAU,EAAE,SAAS,kBAAkB,EAAE,CAAC;IACnD,QAAQ,CAAC,WAAW,EAAE,SAAS,MAAM,EAAE,CAAC;IACxC,QAAQ,CAAC,WAAW,CAAC,EAAE,MAAM,CAAC;IAC9B,QAAQ,CAAC,WAAW,EAAE,SAAS,MAAM,EAAE,CAAC;IACxC,iDAAiD;IACjD,QAAQ,CAAC,UAAU,CAAC,EAAE,MAAM,CAAC;CAC9B;AAED;;;;;;;GAOG;AACH,wBAAgB,gBAAgB,CAC9B,GAAG,EAAE,MAAM,EACX,IAAI,EAAE,WAAW,EACjB,WAAW,EAAE,SAAS,MAAM,EAAE,GAC7B,cAAc,CAqBhB;AAED,qFAAqF;AACrF,wBAAgB,mBAAmB,CAAC,OAAO,EAAE,cAAc,EAAE,QAAQ,EAAE,OAAO,GAAG,MAAM,CA0CtF;AAGD,eAAO,MAAM,wBAAwB,EAAE,eA8BtC,CAAC;AAEF,eAAO,MAAM,iBAAiB,EAAE,eAoQ/B,CAAC"}
|