@shrkcrft/cli 0.1.0-alpha.25 → 0.1.0-alpha.26
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/command-registry.d.ts +10 -0
- package/dist/command-registry.d.ts.map +1 -1
- package/dist/command-registry.js +16 -0
- package/dist/commands/changelog-data.d.ts.map +1 -1
- package/dist/commands/changelog-data.js +24 -0
- package/dist/commands/check.command.d.ts.map +1 -1
- package/dist/commands/check.command.js +65 -8
- package/dist/commands/compress.command.d.ts.map +1 -1
- package/dist/commands/compress.command.js +31 -1
- package/dist/commands/gate.command.d.ts.map +1 -1
- package/dist/commands/gate.command.js +57 -2
- package/dist/commands/graph.command.d.ts.map +1 -1
- package/dist/commands/graph.command.js +68 -1
- package/dist/commands/registry-resolve.d.ts +41 -0
- package/dist/commands/registry-resolve.d.ts.map +1 -0
- package/dist/commands/registry-resolve.js +89 -0
- package/dist/commands/registry.command.d.ts.map +1 -1
- package/dist/commands/registry.command.js +23 -8
- package/dist/commands/reuse.command.d.ts +20 -0
- package/dist/commands/reuse.command.d.ts.map +1 -1
- package/dist/commands/reuse.command.js +81 -11
- package/dist/exit-codes.d.ts +49 -0
- package/dist/exit-codes.d.ts.map +1 -0
- package/dist/exit-codes.js +61 -0
- package/dist/main.d.ts.map +1 -1
- package/dist/main.js +24 -1
- package/package.json +33 -33
|
@@ -191,5 +191,15 @@ export interface IFlagListOptions {
|
|
|
191
191
|
}
|
|
192
192
|
export declare function flagList(args: ParsedArgs, name: string, options?: IFlagListOptions): string[];
|
|
193
193
|
export declare function flagVars(args: ParsedArgs): Record<string, string>;
|
|
194
|
+
/**
|
|
195
|
+
* Return the first parsed flag whose name is NOT in `allowed`, or `undefined`
|
|
196
|
+
* when every flag is recognized. The parser does not reject unknown flags on its
|
|
197
|
+
* own — without a per-command allow-list a typo'd flag (`--no-such-flag`) parses
|
|
198
|
+
* as `true`, reads as a confident opt-in, and the verb runs the bare command at
|
|
199
|
+
* exit `0`. A verb that opts into strict flag handling calls this with its known
|
|
200
|
+
* set and rejects the result loudly, so a mistyped/renamed flag can never read
|
|
201
|
+
* as success (see docs/exit-codes.md · a25 §2.1).
|
|
202
|
+
*/
|
|
203
|
+
export declare function firstUnknownFlag(args: ParsedArgs, allowed: ReadonlySet<string>): string | undefined;
|
|
194
204
|
export {};
|
|
195
205
|
//# sourceMappingURL=command-registry.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"command-registry.d.ts","sourceRoot":"","sources":["../src/command-registry.ts"],"names":[],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"command-registry.d.ts","sourceRoot":"","sources":["../src/command-registry.ts"],"names":[],"mappings":"AAEA,MAAM,WAAW,UAAU;IACzB,UAAU,EAAE,MAAM,EAAE,CAAC;IACrB,KAAK,EAAE,GAAG,CAAC,MAAM,EAAE,MAAM,GAAG,OAAO,CAAC,CAAC;IACrC,0EAA0E;IAC1E,UAAU,EAAE,GAAG,CAAC,MAAM,EAAE,MAAM,EAAE,CAAC,CAAC;IAClC,4EAA4E;IAC5E,SAAS,CAAC,EAAE,MAAM,CAAC;CACpB;AAED,MAAM,WAAW,eAAe;IAC9B,IAAI,EAAE,MAAM,CAAC;IACb,WAAW,EAAE,MAAM,CAAC;IACpB,KAAK,EAAE,MAAM,CAAC;IACd;;;;;;OAMG;IACH,YAAY,CAAC,EAAE,WAAW,CAAC,MAAM,CAAC,CAAC;IACnC,GAAG,CAAC,IAAI,EAAE,UAAU,GAAG,OAAO,CAAC,MAAM,CAAC,GAAG,MAAM,CAAC;CACjD;AAED;;;;;GAKG;AACH,UAAU,gBAAgB;IACxB,OAAO,CAAC,EAAE,eAAe,CAAC;IAC1B,QAAQ,CAAC,QAAQ,EAAE,GAAG,CAAC,MAAM,EAAE,gBAAgB,CAAC,CAAC;IACjD,QAAQ,CAAC,OAAO,EAAE,GAAG,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;CACvC;AAMD,mDAAmD;AACnD,MAAM,WAAW,kBAAkB;IACjC,mFAAmF;IACnF,OAAO,CAAC,EAAE,eAAe,CAAC;IAC1B,sEAAsE;IACtE,WAAW,EAAE,MAAM,EAAE,CAAC;IACtB,0EAA0E;IAC1E,IAAI,EAAE,MAAM,EAAE,CAAC;IACf,6EAA6E;IAC7E,IAAI,EAAE,gBAAgB,CAAC;CACxB;AAED;;;;;;;;;GASG;AACH,qBAAa,eAAe;IAC1B,OAAO,CAAC,QAAQ,CAAC,IAAI,CAAoC;IACzD,uFAAuF;IACvF,OAAO,CAAC,QAAQ,CAAC,YAAY,CAA6B;IAC1D,OAAO,CAAC,QAAQ,CAAC,cAAc,CAA6B;IAE5D,oDAAoD;IACpD,QAAQ,CAAC,OAAO,EAAE,eAAe,GAAG,IAAI;IAIxC,0DAA0D;IAC1D,kBAAkB,CAAC,KAAK,EAAE,MAAM,EAAE,OAAO,EAAE,eAAe,GAAG,IAAI;IAIjE;;;;OAIG;IACH,UAAU,CAAC,IAAI,EAAE,SAAS,MAAM,EAAE,EAAE,OAAO,EAAE,eAAe,GAAG,IAAI;IAgBnE,qCAAqC;IACrC,UAAU,CAAC,KAAK,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,GAAG,IAAI;IAKlD,uCAAuC;IACvC,YAAY,CAAC,KAAK,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,GAAG,IAAI;IAKpD,iEAAiE;IACjE,OAAO,CAAC,UAAU,EAAE,SAAS,MAAM,EAAE,EAAE,KAAK,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,GAAG,IAAI;IAa9E,gCAAgC;IAChC,GAAG,CAAC,IAAI,EAAE,MAAM,GAAG,eAAe,GAAG,SAAS;IAK9C,8BAA8B;IAC9B,MAAM,CAAC,KAAK,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,GAAG,eAAe,GAAG,SAAS;IAOhE,8DAA8D;IAC9D,KAAK,CAAC,IAAI,EAAE,SAAS,MAAM,EAAE,GAAG,eAAe,GAAG,SAAS;IAK3D,YAAY,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM;IAInC,UAAU,IAAI,SAAS,MAAM,EAAE;IAW/B,SAAS,CAAC,KAAK,EAAE,MAAM,GAAG,SAAS,eAAe,EAAE;IAWpD,2EAA2E;IAC3E,aAAa,CAAC,IAAI,EAAE,SAAS,MAAM,EAAE,GAAG,SAAS,MAAM,EAAE;IAUzD,gBAAgB,IAAI,WAAW,CAAC,MAAM,EAAE,MAAM,CAAC;IAI/C,kBAAkB,IAAI,WAAW,CAAC,MAAM,EAAE,MAAM,CAAC;IAIjD,gDAAgD;IAChD,IAAI,IAAI,SAAS,eAAe,EAAE;IAQlC,oDAAoD;IACpD,OAAO,IAAI,aAAa,CAAC;QAAE,QAAQ,CAAC,IAAI,EAAE,SAAS,MAAM,EAAE,CAAC;QAAC,QAAQ,CAAC,OAAO,EAAE,eAAe,CAAA;KAAE,CAAC;IAMjG;;;;;;;;OAQG;IACH,OAAO,CAAC,MAAM,EAAE,SAAS,MAAM,EAAE,GAAG,kBAAkB;IAsBtD,OAAO,CAAC,OAAO;IAUf,OAAO,CAAC,UAAU;CAWnB;AAQD,MAAM,WAAW,gBAAgB;IAC/B,uEAAuE;IACvE,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,yEAAyE;IACzE,YAAY,CAAC,EAAE,WAAW,CAAC,MAAM,CAAC,CAAC;CACpC;AAED,wBAAgB,SAAS,CAAC,IAAI,EAAE,SAAS,MAAM,EAAE,EAAE,OAAO,GAAE,gBAAqB,GAAG,UAAU,CA6C7F;AAED;;;GAGG;AACH,wBAAgB,gBAAgB,CAAC,IAAI,EAAE,SAAS,MAAM,EAAE,GAAG;IACzD,GAAG,CAAC,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,MAAM,EAAE,CAAC;CAChB,CA+BA;AAED,8EAA8E;AAC9E,MAAM,WAAW,wBAAwB;IACvC,kEAAkE;IAClE,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,uEAAuE;IACvE,KAAK,CAAC,EAAE,MAAM,CAAC;CAChB;AAED;;;;;;GAMG;AACH,wBAAgB,qBAAqB,CAAC,IAAI,EAAE,SAAS,MAAM,EAAE,GAAG;IAC9D,SAAS,CAAC,EAAE,wBAAwB,CAAC;IACrC,IAAI,EAAE,MAAM,EAAE,CAAC;CAChB,CAkEA;AAED;;;;;GAKG;AACH,wBAAgB,UAAU,CAAC,IAAI,EAAE,UAAU,GAAG,MAAM,CAKnD;AAED,wBAAgB,UAAU,CAAC,IAAI,EAAE,UAAU,EAAE,IAAI,EAAE,MAAM,GAAG,MAAM,GAAG,SAAS,CAG7E;AAED,wBAAgB,QAAQ,CAAC,IAAI,EAAE,UAAU,EAAE,IAAI,EAAE,MAAM,GAAG,OAAO,CAGhE;AAED,wBAAgB,UAAU,CAAC,IAAI,EAAE,UAAU,EAAE,IAAI,EAAE,MAAM,GAAG,MAAM,GAAG,SAAS,CAK7E;AAED;;;;;;;GAOG;AACH,wBAAgB,eAAe,CAAC,IAAI,EAAE,UAAU,EAAE,IAAI,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,GAAG,MAAM,CAKxF;AAED;;;;;;;;;;;;;GAaG;AACH,MAAM,WAAW,gBAAgB;IAC/B,0EAA0E;IAC1E,MAAM,CAAC,EAAE,OAAO,CAAC;IACjB,qEAAqE;IACrE,KAAK,CAAC,EAAE,SAAS,MAAM,EAAE,CAAC;IAC1B;;;;;;;;;OASG;IACH,KAAK,CAAC,EAAE,QAAQ,GAAG,OAAO,GAAG,MAAM,CAAC;CACrC;AAED,wBAAgB,QAAQ,CACtB,IAAI,EAAE,UAAU,EAChB,IAAI,EAAE,MAAM,EACZ,OAAO,GAAE,gBAAqB,GAC7B,MAAM,EAAE,CAkCV;AAED,wBAAgB,QAAQ,CAAC,IAAI,EAAE,UAAU,GAAG,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAQjE;AAED;;;;;;;;GAQG;AACH,wBAAgB,gBAAgB,CAC9B,IAAI,EAAE,UAAU,EAChB,OAAO,EAAE,WAAW,CAAC,MAAM,CAAC,GAC3B,MAAM,GAAG,SAAS,CAKpB"}
|
package/dist/command-registry.js
CHANGED
|
@@ -451,3 +451,19 @@ export function flagVars(args) {
|
|
|
451
451
|
}
|
|
452
452
|
return out;
|
|
453
453
|
}
|
|
454
|
+
/**
|
|
455
|
+
* Return the first parsed flag whose name is NOT in `allowed`, or `undefined`
|
|
456
|
+
* when every flag is recognized. The parser does not reject unknown flags on its
|
|
457
|
+
* own — without a per-command allow-list a typo'd flag (`--no-such-flag`) parses
|
|
458
|
+
* as `true`, reads as a confident opt-in, and the verb runs the bare command at
|
|
459
|
+
* exit `0`. A verb that opts into strict flag handling calls this with its known
|
|
460
|
+
* set and rejects the result loudly, so a mistyped/renamed flag can never read
|
|
461
|
+
* as success (see docs/exit-codes.md · a25 §2.1).
|
|
462
|
+
*/
|
|
463
|
+
export function firstUnknownFlag(args, allowed) {
|
|
464
|
+
for (const key of args.flags.keys()) {
|
|
465
|
+
if (!allowed.has(key))
|
|
466
|
+
return key;
|
|
467
|
+
}
|
|
468
|
+
return undefined;
|
|
469
|
+
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"changelog-data.d.ts","sourceRoot":"","sources":["../../src/commands/changelog-data.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AAEH,2CAA2C;AAC3C,MAAM,WAAW,oBAAoB;IACnC,oDAAoD;IACpD,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAC;IACzB,yCAAyC;IACzC,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC;IACvB,iDAAiD;IACjD,QAAQ,CAAC,KAAK,EAAE,SAAS,MAAM,EAAE,CAAC;IAClC,wDAAwD;IACxD,QAAQ,CAAC,OAAO,EAAE,SAAS,MAAM,EAAE,CAAC;IACpC,6CAA6C;IAC7C,QAAQ,CAAC,OAAO,EAAE,SAAS,MAAM,EAAE,CAAC;CACrC;AAED,eAAO,MAAM,sBAAsB,EAAE,SAAS,oBAAoB,
|
|
1
|
+
{"version":3,"file":"changelog-data.d.ts","sourceRoot":"","sources":["../../src/commands/changelog-data.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AAEH,2CAA2C;AAC3C,MAAM,WAAW,oBAAoB;IACnC,oDAAoD;IACpD,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAC;IACzB,yCAAyC;IACzC,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC;IACvB,iDAAiD;IACjD,QAAQ,CAAC,KAAK,EAAE,SAAS,MAAM,EAAE,CAAC;IAClC,wDAAwD;IACxD,QAAQ,CAAC,OAAO,EAAE,SAAS,MAAM,EAAE,CAAC;IACpC,6CAA6C;IAC7C,QAAQ,CAAC,OAAO,EAAE,SAAS,MAAM,EAAE,CAAC;CACrC;AAED,eAAO,MAAM,sBAAsB,EAAE,SAAS,oBAAoB,EAmFjE,CAAC"}
|
|
@@ -67,4 +67,28 @@ export const RELEASE_SURFACE_DELTAS = [
|
|
|
67
67
|
],
|
|
68
68
|
removed: [],
|
|
69
69
|
},
|
|
70
|
+
{
|
|
71
|
+
version: '0.1.0-alpha.26',
|
|
72
|
+
title: 'Honest exit codes',
|
|
73
|
+
added: [
|
|
74
|
+
'A unified exit-code contract across every gate/verify/check verb: `0` verified pass, `1` failure, `2` NOT-verified (empty scope / degraded / timeout). See docs/exit-codes.md.',
|
|
75
|
+
'Global `--strict` — promote a NOT-verified (`2`) verdict to a failure-class nonzero (`1`) across every gate, for a hard CI gate in one switch.',
|
|
76
|
+
'`shrk gate baseline --refreeze` — re-freeze the architecture baseline to the current state (operational reset).',
|
|
77
|
+
'`shrk check wiring --base <ref>` (synonym of `--since`); `check wiring` now shows the rule ids selected by footprint under a scoped run.',
|
|
78
|
+
'`shrk reuse … --all` — the full candidate catalog (default is now a scored top-K did-you-mean).',
|
|
79
|
+
],
|
|
80
|
+
changed: [
|
|
81
|
+
'`shrk check wiring` (0 rules evaluated) and `shrk registry lifecycle` / `check registry-lifecycle` (0 registrations, or wall-clock timeout) now exit `2` (NOT verified), not a green `0` a chained `&& next` would march past.',
|
|
82
|
+
'The graph/query family (`graph cycles|hubs|callers|impact|search|context|…`) rejects an unknown/misspelled flag (`unknown option --x`, exit `2`) instead of silently swallowing it as a confident success.',
|
|
83
|
+
'Piping any streaming list (`… | head`, `| grep`) no longer crashes with `write EPIPE` — a downstream early-close is swallowed and the real exit code is preserved.',
|
|
84
|
+
'`shrk check wiring --help` documents its own scoping flags instead of running the bare check.',
|
|
85
|
+
'`shrk reuse "<intent>"` returns a scored top-K did-you-mean (score per row) on a weak/no-match intent instead of dumping the whole catalog.',
|
|
86
|
+
'`shrk registry <name> exists <id> --resolve` also normalizes (case-fold, singular/plural, suffix strip/append), not just the declared `aliases` map.',
|
|
87
|
+
'`shrk compress` prints a `fidelity: lossy|lossless|passthrough` banner on the human text path (parity with `--json`).',
|
|
88
|
+
'`shrk changes summary` ships a built-in config/tooling area for non-lib paths — only genuinely unclassifiable files stay `unknown`.',
|
|
89
|
+
'`shrk gen` saved plans persist the rendered file `body` + a per-entry `sha256` digest (reviewable/diffable/re-appliable), not just `sizeBytes`.',
|
|
90
|
+
'`shrk gate` counts only change-attributable (diff-vs-HEAD) architecture errors as blocking; stale-baseline drift in untouched files is informational.',
|
|
91
|
+
],
|
|
92
|
+
removed: [],
|
|
93
|
+
},
|
|
70
94
|
];
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"check.command.d.ts","sourceRoot":"","sources":["../../src/commands/check.command.ts"],"names":[],"mappings":"AAoBA,OAAO,EAML,KAAK,eAAe,EAErB,MAAM,wBAAwB,CAAC;
|
|
1
|
+
{"version":3,"file":"check.command.d.ts","sourceRoot":"","sources":["../../src/commands/check.command.ts"],"names":[],"mappings":"AAoBA,OAAO,EAML,KAAK,eAAe,EAErB,MAAM,wBAAwB,CAAC;AAu4BhC,eAAO,MAAM,YAAY,EAAE,eA+G1B,CAAC"}
|
|
@@ -3,6 +3,7 @@ import { mkdirSync, writeFileSync, readFileSync, existsSync } from 'node:fs';
|
|
|
3
3
|
import * as nodePath from 'node:path';
|
|
4
4
|
import { flagBool, flagNumber, flagString, flagVars, resolveCwd, } from "../command-registry.js";
|
|
5
5
|
import { asJson, header, kv } from "../output/format-output.js";
|
|
6
|
+
import { ExitCode } from "../exit-codes.js";
|
|
6
7
|
import { maybeRunInWatchMode } from "../output/watch-loop.js";
|
|
7
8
|
import { computeDeletedOrphans } from "../diff/deleted-orphans.js";
|
|
8
9
|
import { renderWiringExplain } from "./wiring.command.js";
|
|
@@ -522,11 +523,29 @@ async function checkBoundariesOnce(args) {
|
|
|
522
523
|
// ────────────────────────────────────────────────────────────────────────
|
|
523
524
|
// Subcommand: wiring — "declared but not wired" completeness checks
|
|
524
525
|
// ────────────────────────────────────────────────────────────────────────
|
|
526
|
+
const WIRING_CHECK_USAGE = 'shrk check wiring [--changed-only] [--since <ref>] [--base <ref>] [--only <ids>] [--explain <ruleId>] [--json] [--strict]\n' +
|
|
527
|
+
' Cross-file "declared but not wired" completeness gate. Scope flags select rules by\n' +
|
|
528
|
+
' FOOTPRINT — a rule fires when the diff touches EITHER its declared or its registered\n' +
|
|
529
|
+
' side (so a registration edited in file B fires a rule declared in file A).\n' +
|
|
530
|
+
' --changed-only run only rules whose footprint intersects the working diff\n' +
|
|
531
|
+
' --since <ref> scope the diff to changes since <ref> (--base is a synonym)\n' +
|
|
532
|
+
' --only <ids> run only these rule ids (comma-separated)\n' +
|
|
533
|
+
' --explain <id> dry-run ONE rule and print the declared/registered sets it extracts\n' +
|
|
534
|
+
' Exit: 0 verified pass · 1 violations · 2 not-verified (0 rules evaluated in scope).';
|
|
525
535
|
async function checkWiring(args) {
|
|
526
536
|
const cwd = resolveCwd(args);
|
|
537
|
+
// `--help`/`-h` on the subverb documents its own scoping flags instead of
|
|
538
|
+
// silently running the bare check (a25 §3.2). The check dispatcher doesn't
|
|
539
|
+
// intercept a subverb-level `--help`, so handle it here.
|
|
540
|
+
if (flagBool(args, 'help') || flagBool(args, 'h')) {
|
|
541
|
+
process.stdout.write(WIRING_CHECK_USAGE + '\n');
|
|
542
|
+
return 0;
|
|
543
|
+
}
|
|
527
544
|
const wantJson = flagBool(args, 'json');
|
|
528
545
|
const changedOnly = flagBool(args, 'changed-only');
|
|
529
|
-
|
|
546
|
+
// `--base <ref>` is an accepted synonym for `--since <ref>` (a25 §3.2) —
|
|
547
|
+
// scope the footprint diff to changes since an arbitrary ref.
|
|
548
|
+
const since = flagString(args, 'since') ?? flagString(args, 'base');
|
|
530
549
|
const only = flagString(args, 'only');
|
|
531
550
|
// Distinguish "config is invalid" from "config valid with no wiring rules":
|
|
532
551
|
// an invalid config (e.g. a malformed wiringRule) must NOT fail open with a
|
|
@@ -613,22 +632,50 @@ async function checkWiring(args) {
|
|
|
613
632
|
if (matchedNothing > 0)
|
|
614
633
|
parts.push(`${matchedNothing} matched no files`);
|
|
615
634
|
const breakdown = parts.length > 0 ? ` (${parts.join(', ')})` : '';
|
|
635
|
+
// Rule ids selected by footprint (declared OR registered side intersecting the
|
|
636
|
+
// diff) — positive evidence the gate ran the RIGHT rules for the change's
|
|
637
|
+
// blast radius, not just the rules whose literal files were edited (a25 §3.2).
|
|
638
|
+
const selectedRuleIds = report.rules.map((r) => r.ruleId);
|
|
639
|
+
const scoped = changedOnly || since !== undefined;
|
|
616
640
|
if (wantJson) {
|
|
617
641
|
// Carry the honest counts so a machine consumer can tell "0 evaluated" from
|
|
618
|
-
// a real green, and see how many rules the scope skipped.
|
|
619
|
-
process.stdout.write(asJson({
|
|
620
|
-
|
|
642
|
+
// a real green, and see how many rules the scope skipped + which fired.
|
|
643
|
+
process.stdout.write(asJson({
|
|
644
|
+
...report,
|
|
645
|
+
configured,
|
|
646
|
+
selected,
|
|
647
|
+
evaluated,
|
|
648
|
+
skippedByScope,
|
|
649
|
+
matchedNothing,
|
|
650
|
+
notVerified,
|
|
651
|
+
selectedRuleIds,
|
|
652
|
+
// Distinguish verified-pass / failure / not-verified for a chained gate.
|
|
653
|
+
exitCode: evaluated === 0 ? ExitCode.NotVerified : report.verdict === 'errors' ? ExitCode.Failure : ExitCode.VerifiedPass,
|
|
654
|
+
}) + '\n');
|
|
655
|
+
// `evaluated === 0` = nothing checked in scope → NOT verified (`2`), never a
|
|
656
|
+
// silent `0` an agent's `&& next` would march past (a25 §1.1).
|
|
657
|
+
return evaluated === 0
|
|
658
|
+
? ExitCode.NotVerified
|
|
659
|
+
: report.verdict === 'errors'
|
|
660
|
+
? ExitCode.Failure
|
|
661
|
+
: ExitCode.VerifiedPass;
|
|
621
662
|
}
|
|
622
663
|
process.stdout.write(header('Wiring check'));
|
|
623
664
|
// `evaluated` counts rules that actually ran a comparison (globs matched >0
|
|
624
665
|
// files). When 0 rules evaluated but rules ARE configured, say so loudly —
|
|
625
|
-
// "checked nothing" must never read as the green "every token is wired" pass
|
|
666
|
+
// "checked nothing" must never read as the green "every token is wired" pass,
|
|
667
|
+
// and the exit code must say NOT verified (`2`) too, not a lying `0`.
|
|
626
668
|
if (evaluated === 0) {
|
|
627
669
|
process.stdout.write(` ! 0 rules evaluated — NOT verified. ${configured} rule(s) configured${breakdown}; ` +
|
|
628
670
|
'none ran a comparison in scope. Wiring was not checked — this is not a pass.\n');
|
|
629
|
-
return
|
|
671
|
+
return ExitCode.NotVerified;
|
|
630
672
|
}
|
|
631
673
|
process.stdout.write(kv('rules evaluated', `${evaluated} of ${configured}${breakdown}`) + '\n');
|
|
674
|
+
if (scoped && selectedRuleIds.length > 0) {
|
|
675
|
+
// Show WHICH rules the diff's footprint selected so the scoping is provable,
|
|
676
|
+
// not indistinguishable from plain changed-file scoping.
|
|
677
|
+
process.stdout.write(kv('selected by footprint', selectedRuleIds.join(', ')) + '\n');
|
|
678
|
+
}
|
|
632
679
|
const errors = report.violations.filter((v) => v.severity === 'error').length;
|
|
633
680
|
const warnings = report.violations.filter((v) => v.severity === 'warning').length;
|
|
634
681
|
process.stdout.write(kv('violations', `${errors} error(s), ${warnings} warning(s)`) + '\n');
|
|
@@ -821,8 +868,18 @@ export const checkCommand = {
|
|
|
821
868
|
...(scope ? { scope } : {}),
|
|
822
869
|
...(skipDirs ? { skipDirs } : {}),
|
|
823
870
|
});
|
|
824
|
-
//
|
|
825
|
-
|
|
871
|
+
// Honest exit-code contract (a25 §1 / §2.5):
|
|
872
|
+
// timedOut → NOT verified (2): the budget flushed partial results.
|
|
873
|
+
// registersFound=0 → NOT verified (2): nothing to check in scope — a
|
|
874
|
+
// "nothing to verify" run must never read as a green
|
|
875
|
+
// pass (an agent's `&& next` would march past it).
|
|
876
|
+
// missingRemovers>0 → failure (1).
|
|
877
|
+
// otherwise → verified pass (0).
|
|
878
|
+
const exit = report.timedOut || report.registersFound === 0
|
|
879
|
+
? ExitCode.NotVerified
|
|
880
|
+
: report.missingRemovers.length === 0
|
|
881
|
+
? ExitCode.VerifiedPass
|
|
882
|
+
: ExitCode.Failure;
|
|
826
883
|
if (flagBool(args, 'json')) {
|
|
827
884
|
process.stdout.write(asJson(report) + '\n');
|
|
828
885
|
return exit;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"compress.command.d.ts","sourceRoot":"","sources":["../../src/commands/compress.command.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"compress.command.d.ts","sourceRoot":"","sources":["../../src/commands/compress.command.ts"],"names":[],"mappings":"AASA,OAAO,EAKL,KAAK,eAAe,EAErB,MAAM,wBAAwB,CAAC;AA8FhC,eAAO,MAAM,eAAe,EAAE,eA0H7B,CAAC;AAEF;;;GAGG;AACH,eAAO,MAAM,aAAa,EAAE,eA4B3B,CAAC"}
|
|
@@ -38,6 +38,31 @@ function resolveContentType(raw) {
|
|
|
38
38
|
// legitimately have nothing to compress). Above it, a silent `−0%` re-emit is
|
|
39
39
|
// the opposite of the tool's purpose — nudge the user toward `--type`.
|
|
40
40
|
const PASSTHROUGH_HINT_MIN_BYTES = 128;
|
|
41
|
+
/**
|
|
42
|
+
* The no-win / passthrough test, shared by the `--json` envelope and the human
|
|
43
|
+
* text banner: a Passthrough strategy or a non-positive saving means the engine
|
|
44
|
+
* declined to compress and `compressed` is the verbatim original. Keeping it in
|
|
45
|
+
* one place is what makes the two output paths agree on fidelity.
|
|
46
|
+
*/
|
|
47
|
+
function isNoWin(result) {
|
|
48
|
+
return result.strategy === ECompressionStrategy.Passthrough || result.savings.saved <= 0;
|
|
49
|
+
}
|
|
50
|
+
/**
|
|
51
|
+
* The fidelity label for the human text path, mirroring the `fidelity` field
|
|
52
|
+
* the `--json` envelope surfaces: `passthrough` for a no-win re-emit, `lossy`
|
|
53
|
+
* for a reduction that drops detail (markdown line-omission or the code
|
|
54
|
+
* outline), and `lossless` otherwise. Same classification as `--json` — the
|
|
55
|
+
* text path just names the no-win case explicitly instead of via a separate
|
|
56
|
+
* `passthrough` boolean, so an agent reading stderr sees the fidelity at a
|
|
57
|
+
* glance.
|
|
58
|
+
*/
|
|
59
|
+
function textFidelity(result) {
|
|
60
|
+
if (isNoWin(result))
|
|
61
|
+
return 'passthrough';
|
|
62
|
+
if (result.strategy === ECompressionStrategy.Code || result.lossy)
|
|
63
|
+
return 'lossy';
|
|
64
|
+
return 'lossless';
|
|
65
|
+
}
|
|
41
66
|
function readInput(args) {
|
|
42
67
|
const positional = args.positional[0];
|
|
43
68
|
const useStdin = flagBool(args, 'stdin') || positional === undefined || positional === '-';
|
|
@@ -133,7 +158,7 @@ export const compressCommand = {
|
|
|
133
158
|
// VERBATIM original as `compressed`. Echoing it back inside the JSON
|
|
134
159
|
// envelope (plus scaffold) costs more tokens than the input. Signal
|
|
135
160
|
// passthrough and omit the duplicated content — the caller still has it.
|
|
136
|
-
const noWin = result
|
|
161
|
+
const noWin = isNoWin(result);
|
|
137
162
|
const payload = noWin
|
|
138
163
|
? { ...base, passthrough: true, inputBytes: Buffer.byteLength(content, 'utf8') }
|
|
139
164
|
: { ...base, compressed: result.compressed };
|
|
@@ -143,6 +168,11 @@ export const compressCommand = {
|
|
|
143
168
|
process.stdout.write(result.compressed + '\n');
|
|
144
169
|
const cached = result.ccrKey ? ` · original cached as ${result.ccrKey} (shrk expand ${result.ccrKey})` : '';
|
|
145
170
|
process.stderr.write(`${result.strategy}: ~${result.savings.before} → ~${result.savings.after} tokens (−${pct}%, est.)${cached}\n`);
|
|
171
|
+
// Fidelity parity with `--json`: print the same classification the JSON
|
|
172
|
+
// envelope carries as a one-line banner so an agent reading only stderr can
|
|
173
|
+
// see the output was lossy — and see the no-win `passthrough` case named
|
|
174
|
+
// explicitly rather than inferred from a bare `−0%` ratio.
|
|
175
|
+
process.stderr.write(`fidelity: ${textFidelity(result)}\n`);
|
|
146
176
|
// Fidelity banner: the code outline elides function bodies, so it is a
|
|
147
177
|
// footgun as a cheaper Read. Say so loudly — same failure mode as a lossy
|
|
148
178
|
// result that doesn't *look* lossy.
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"gate.command.d.ts","sourceRoot":"","sources":["../../src/commands/gate.command.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"gate.command.d.ts","sourceRoot":"","sources":["../../src/commands/gate.command.ts"],"names":[],"mappings":"AAcA,OAAO,EAIL,KAAK,eAAe,EAErB,MAAM,wBAAwB,CAAC;AAGhC;;;;;;;;;;;GAWG;AACH,eAAO,MAAM,WAAW,EAAE,eAwNzB,CAAC"}
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { QualityGateReportStore, renderGateReportMarkdown, runQualityGates, } from '@shrkcrft/quality-gates';
|
|
2
|
+
import { ArchReportStore, runArchCheck } from '@shrkcrft/architecture-guard';
|
|
2
3
|
import { inspectSharkcraft, resolveChangedFiles, resolveProjectConfig, } from '@shrkcrft/inspector';
|
|
3
4
|
import { chmodSync, existsSync, mkdirSync, writeFileSync } from 'node:fs';
|
|
4
5
|
import * as nodePath from 'node:path';
|
|
@@ -19,7 +20,7 @@ import { asJson, header, kv } from "../output/format-output.js";
|
|
|
19
20
|
export const gateCommand = {
|
|
20
21
|
name: 'gate',
|
|
21
22
|
description: 'Aggregator: runs the code-intelligence quality gates (graph freshness, architecture, impact-since-ref) and reports a single pass/fail.',
|
|
22
|
-
usage: 'shrk gate [--since <gitref>] [--changed-only] [--staged] [--files a,b,c] [--fail-on critical,high] [--arch-all] [--disable arch,impact,policy,knowledge-symbol,api-diff] [--api-baseline <path>] [--no-fail-on-breaking] [--strict] [--no-persist] [--json] [--markdown] [--output <path>]\n (the arch gate is
|
|
23
|
+
usage: 'shrk gate [--since <gitref>] [--changed-only] [--staged] [--files a,b,c] [--fail-on critical,high] [--arch-all] [--disable arch,impact,policy,knowledge-symbol,api-diff] [--api-baseline <path>] [--no-fail-on-breaking] [--strict] [--no-persist] [--json] [--markdown] [--output <path>]\n (the arch gate is change-scoped once a baseline is frozen — a NEW error blocks only when the working diff vs HEAD touched its origin file; drift in untouched files is informational — --arch-all fails on total, --strict escalates the warn)\n (--changed-only / --staged / --files / --since scope the wiring + policy + knowledge-symbol gates to the changeset; they also drive the impact gate — --since diffs the gitref, the others analyze the changed-file set)\n shrk gate scaffold-ci [--provider github|generic] [--force] [--json]\n shrk gate scaffold-hook [--provider husky|raw] [--force] [--json]\n shrk gate baseline --refreeze [--json] (operational reset: re-freeze the arch baseline to the current state — NOT the change-scoped gate)',
|
|
23
24
|
async run(args) {
|
|
24
25
|
if (args.positional[0] === 'scaffold-ci') {
|
|
25
26
|
const sliced = { ...args, positional: args.positional.slice(1) };
|
|
@@ -29,6 +30,10 @@ export const gateCommand = {
|
|
|
29
30
|
const sliced = { ...args, positional: args.positional.slice(1) };
|
|
30
31
|
return runGateScaffoldHook(sliced);
|
|
31
32
|
}
|
|
33
|
+
if (args.positional[0] === 'baseline') {
|
|
34
|
+
const sliced = { ...args, positional: args.positional.slice(1) };
|
|
35
|
+
return runGateBaseline(sliced);
|
|
36
|
+
}
|
|
32
37
|
const cwd = resolveCwd(args);
|
|
33
38
|
const wantJson = flagBool(args, 'json');
|
|
34
39
|
const wantMarkdown = flagBool(args, 'markdown');
|
|
@@ -101,6 +106,17 @@ export const gateCommand = {
|
|
|
101
106
|
const scopeOpts = wantChangedScope
|
|
102
107
|
? { changedOnly: true, changedFiles: changedFiles ?? [] }
|
|
103
108
|
: {};
|
|
109
|
+
// §3.1 — the architecture gate's "NEW" is ALWAYS change-scoped: a NEW error
|
|
110
|
+
// means one introduced by the working change (diff vs HEAD), never drift
|
|
111
|
+
// against a frozen (possibly months-old) baseline in a file the change never
|
|
112
|
+
// touched. When an explicit scope flag is passed we reuse its resolution;
|
|
113
|
+
// otherwise we default to the worktree diff vs HEAD — empty in a clean tree,
|
|
114
|
+
// so pre-existing baseline drift stays informational and can't red the gate
|
|
115
|
+
// on its own. `--arch-all` (baselineRelative:false) ignores this and fails
|
|
116
|
+
// on total errors, keeping a clean-tree CI demand expressible.
|
|
117
|
+
const archChangedFiles = wantChangedScope
|
|
118
|
+
? changedFiles ?? []
|
|
119
|
+
: resolveChangedFiles({ projectRoot: cwd, includeWorktree: true }).files;
|
|
104
120
|
// Knowledge symbol-ref integrity needs the loaded knowledge entries. The
|
|
105
121
|
// inspection is async, so we build it here and inject it; the gate stays
|
|
106
122
|
// synchronous and resolves the code graph itself. Best-effort — a failed
|
|
@@ -116,7 +132,10 @@ export const gateCommand = {
|
|
|
116
132
|
}
|
|
117
133
|
const report = runQualityGates({
|
|
118
134
|
projectRoot: cwd,
|
|
119
|
-
|
|
135
|
+
arch: {
|
|
136
|
+
...(archAll ? { baselineRelative: false } : {}),
|
|
137
|
+
changedFiles: archChangedFiles,
|
|
138
|
+
},
|
|
120
139
|
wiring: {
|
|
121
140
|
...(configError
|
|
122
141
|
? { configError }
|
|
@@ -400,3 +419,39 @@ async function runGateScaffoldCi(args) {
|
|
|
400
419
|
process.stdout.write(`Scaffolded ${provider} CI runner → ${target}\n`);
|
|
401
420
|
return 0;
|
|
402
421
|
}
|
|
422
|
+
/**
|
|
423
|
+
* `shrk gate baseline --refreeze` — deliberate operational reset that re-freezes
|
|
424
|
+
* the architecture baseline to the CURRENT state, absorbing accumulated drift so
|
|
425
|
+
* the informational "baseline drift" line resets to zero.
|
|
426
|
+
*
|
|
427
|
+
* This is an operational complement, NOT the gate itself: the gate's blocking
|
|
428
|
+
* verdict is change-scoped (a NEW error blocks only when the working diff touched
|
|
429
|
+
* its origin file), so a stale baseline never reds the gate on its own. Refreeze
|
|
430
|
+
* is only for tidying the informational drift line. It mirrors `shrk arch
|
|
431
|
+
* baseline write`.
|
|
432
|
+
*/
|
|
433
|
+
async function runGateBaseline(args) {
|
|
434
|
+
const cwd = resolveCwd(args);
|
|
435
|
+
const wantJson = flagBool(args, 'json');
|
|
436
|
+
const refreeze = flagBool(args, 'refreeze');
|
|
437
|
+
if (!refreeze) {
|
|
438
|
+
process.stderr.write('Usage: shrk gate baseline --refreeze [--json]\n' +
|
|
439
|
+
' Re-freeze the architecture baseline to the current state (operational reset,\n' +
|
|
440
|
+
' not the change-scoped gate). Equivalent to `shrk arch baseline write`.\n');
|
|
441
|
+
return 2;
|
|
442
|
+
}
|
|
443
|
+
const report = runArchCheck({ projectRoot: cwd });
|
|
444
|
+
if (report.diagnostics.some((d) => d.includes('code-graph store missing'))) {
|
|
445
|
+
process.stderr.write('Cannot refreeze — graph index missing. Run `shrk graph index` first.\n');
|
|
446
|
+
return 2;
|
|
447
|
+
}
|
|
448
|
+
const store = new ArchReportStore(cwd);
|
|
449
|
+
const snap = store.writeBaseline(report);
|
|
450
|
+
if (wantJson) {
|
|
451
|
+
process.stdout.write(asJson({ ok: true, wrote: store.baselinePath, baseline: snap }) + '\n');
|
|
452
|
+
return 0;
|
|
453
|
+
}
|
|
454
|
+
process.stdout.write(`Architecture baseline re-frozen → ${store.baselinePath}\n`);
|
|
455
|
+
process.stdout.write(kv('violations', `${snap.countsBySeverity.error} error, ${snap.countsBySeverity.warning} warning`) + '\n');
|
|
456
|
+
return 0;
|
|
457
|
+
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"graph.command.d.ts","sourceRoot":"","sources":["../../src/commands/graph.command.ts"],"names":[],"mappings":"AAUA,OAAO,
|
|
1
|
+
{"version":3,"file":"graph.command.d.ts","sourceRoot":"","sources":["../../src/commands/graph.command.ts"],"names":[],"mappings":"AAUA,OAAO,EAKL,KAAK,eAAe,EAErB,MAAM,wBAAwB,CAAC;AAqFhC,eAAO,MAAM,YAAY,EAAE,eAqO1B,CAAC"}
|
|
@@ -1,8 +1,63 @@
|
|
|
1
1
|
import { mkdirSync, writeFileSync } from 'node:fs';
|
|
2
2
|
import * as nodePath from 'node:path';
|
|
3
3
|
import { analyzeImportGraph, buildKnowledgeGraph, findGraphPath, getGraphNode, inspectSharkcraft, } from '@shrkcrft/inspector';
|
|
4
|
-
import { flagBool, flagString, resolveCwd, } from "../command-registry.js";
|
|
4
|
+
import { firstUnknownFlag, flagBool, flagString, resolveCwd, } from "../command-registry.js";
|
|
5
|
+
import { ExitCode } from "../exit-codes.js";
|
|
5
6
|
import { asJson, header, kv } from "../output/format-output.js";
|
|
7
|
+
/**
|
|
8
|
+
* The code-intelligence subverbs that share one arg parser. Each is guarded so
|
|
9
|
+
* an unrecognized/misspelled flag is rejected loudly instead of parsing as a
|
|
10
|
+
* silent `true` that reads as a confident opt-in (a25 §2.1). The allow-set is
|
|
11
|
+
* the UNION of every flag any code-graph subverb reads, plus the global flags,
|
|
12
|
+
* so a real flag is never false-rejected — only a genuinely unknown token is.
|
|
13
|
+
*/
|
|
14
|
+
const CODE_GRAPH_SUBVERBS = new Set([
|
|
15
|
+
'index',
|
|
16
|
+
'status',
|
|
17
|
+
'search',
|
|
18
|
+
'context',
|
|
19
|
+
'impact',
|
|
20
|
+
'path',
|
|
21
|
+
'hubs',
|
|
22
|
+
'callers',
|
|
23
|
+
'cycles',
|
|
24
|
+
'unresolved',
|
|
25
|
+
'deps',
|
|
26
|
+
]);
|
|
27
|
+
const CODE_GRAPH_ALLOWED_FLAGS = new Set([
|
|
28
|
+
// code-subverb flags (union across index/status/search/context/impact/path/
|
|
29
|
+
// hubs/callers/cycles/unresolved/deps)
|
|
30
|
+
'changed',
|
|
31
|
+
'compact',
|
|
32
|
+
'depth',
|
|
33
|
+
'full',
|
|
34
|
+
'has-unresolved-imports',
|
|
35
|
+
'include-type-edges',
|
|
36
|
+
'json',
|
|
37
|
+
'kind',
|
|
38
|
+
'limit',
|
|
39
|
+
'max-depth',
|
|
40
|
+
'min-size',
|
|
41
|
+
'mode',
|
|
42
|
+
'no-bridge',
|
|
43
|
+
'no-framework',
|
|
44
|
+
'no-refresh',
|
|
45
|
+
'path',
|
|
46
|
+
'since',
|
|
47
|
+
'table',
|
|
48
|
+
// --watch loop (graph index --watch)
|
|
49
|
+
'watch',
|
|
50
|
+
'paths',
|
|
51
|
+
'debounce',
|
|
52
|
+
'once',
|
|
53
|
+
// global / meta flags that reach any verb
|
|
54
|
+
'cwd',
|
|
55
|
+
'strict',
|
|
56
|
+
'help',
|
|
57
|
+
'h',
|
|
58
|
+
'no-color',
|
|
59
|
+
'color',
|
|
60
|
+
]);
|
|
6
61
|
import { runGraphCallers, runGraphContext, runGraphCycles, runGraphDeps, runGraphHubs, runGraphImpact, runGraphIndex, runGraphPath, runGraphSearch, runGraphStatus, runGraphUnresolved, } from "./graph-code-subverbs.js";
|
|
7
62
|
const KNOWN_KINDS = [
|
|
8
63
|
'knowledge',
|
|
@@ -26,6 +81,18 @@ export const graphCommand = {
|
|
|
26
81
|
// Code-intelligence subverbs (R65) don't need the knowledge graph —
|
|
27
82
|
// dispatch them before the expensive inspection so they stay fast.
|
|
28
83
|
const earlySub = args.positional[0];
|
|
84
|
+
// Reject unknown/misspelled flags on the code-graph family BEFORE dispatch:
|
|
85
|
+
// an unrecognized flag must never parse as a silent success (a25 §2.1). Any
|
|
86
|
+
// real flag is in the union allow-set, so this only fires on a genuine typo.
|
|
87
|
+
if (typeof earlySub === 'string' && CODE_GRAPH_SUBVERBS.has(earlySub)) {
|
|
88
|
+
const unknown = firstUnknownFlag(args, CODE_GRAPH_ALLOWED_FLAGS);
|
|
89
|
+
if (unknown) {
|
|
90
|
+
const dash = unknown.length === 1 ? '-' : '--';
|
|
91
|
+
process.stderr.write(`unknown option '${dash}${unknown}' for 'shrk graph ${earlySub}'. ` +
|
|
92
|
+
`Run 'shrk graph --help' for valid flags.\n`);
|
|
93
|
+
return ExitCode.NotVerified;
|
|
94
|
+
}
|
|
95
|
+
}
|
|
29
96
|
if (earlySub === 'index')
|
|
30
97
|
return runGraphIndex(args);
|
|
31
98
|
if (earlySub === 'status')
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* `--resolve` support for `shrk registry <name> exists <id>`.
|
|
3
|
+
*
|
|
4
|
+
* The noun an author types is not always the exact registered slug. `--resolve`
|
|
5
|
+
* bridges that vocabulary gap before the existence check so a duplicate guard
|
|
6
|
+
* can't return a false "not declared" for a construct that DOES exist under its
|
|
7
|
+
* canonical id (a25 §2.4). Resolution is deterministic and layered, most
|
|
8
|
+
* author-controlled first:
|
|
9
|
+
*
|
|
10
|
+
* 1. the registry's declared `aliases` map (explicit synonym → canonical),
|
|
11
|
+
* 2. a case-insensitive exact match against the declared ids,
|
|
12
|
+
* 3. singular/plural normalization (`commands` ↔ `command`),
|
|
13
|
+
* 4. suffix strip/append (`button` ↔ `button-command`, `foo` ↔ `foo.tool`).
|
|
14
|
+
*
|
|
15
|
+
* The first layer that lands on a DECLARED id wins; when nothing resolves, the
|
|
16
|
+
* noun is returned unchanged and unmatched (the honest "genuinely not declared"
|
|
17
|
+
* answer). No layer invents an id that isn't in the registry.
|
|
18
|
+
*/
|
|
19
|
+
/** How a noun resolved to its canonical registered id (for a truthful report). */
|
|
20
|
+
export declare enum ERegistryResolveVia {
|
|
21
|
+
Identity = "identity",
|
|
22
|
+
Alias = "alias",
|
|
23
|
+
Case = "case-fold",
|
|
24
|
+
SingularPlural = "singular/plural",
|
|
25
|
+
Suffix = "suffix"
|
|
26
|
+
}
|
|
27
|
+
export interface IRegistryResolution {
|
|
28
|
+
/** The canonical id to test for existence (may equal the input noun). */
|
|
29
|
+
readonly canonical: string;
|
|
30
|
+
/** True when `canonical` is actually a declared id in the registry. */
|
|
31
|
+
readonly matched: boolean;
|
|
32
|
+
/** Which normalization layer produced `canonical`. */
|
|
33
|
+
readonly via: ERegistryResolveVia;
|
|
34
|
+
}
|
|
35
|
+
/**
|
|
36
|
+
* Resolve a human/synonym `noun` to a canonical registered id. `declaredIds` is
|
|
37
|
+
* the registry's actual declared id list (so no layer can resolve to something
|
|
38
|
+
* that isn't declared); `aliases` is the registry's optional declared map.
|
|
39
|
+
*/
|
|
40
|
+
export declare function resolveRegistryNoun(declaredIds: readonly string[], aliases: Readonly<Record<string, string>> | undefined, noun: string): IRegistryResolution;
|
|
41
|
+
//# sourceMappingURL=registry-resolve.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"registry-resolve.d.ts","sourceRoot":"","sources":["../../src/commands/registry-resolve.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;GAiBG;AAEH,kFAAkF;AAClF,oBAAY,mBAAmB;IAC7B,QAAQ,aAAa;IACrB,KAAK,UAAU;IACf,IAAI,cAAc;IAClB,cAAc,oBAAoB;IAClC,MAAM,WAAW;CAClB;AAED,MAAM,WAAW,mBAAmB;IAClC,yEAAyE;IACzE,QAAQ,CAAC,SAAS,EAAE,MAAM,CAAC;IAC3B,uEAAuE;IACvE,QAAQ,CAAC,OAAO,EAAE,OAAO,CAAC;IAC1B,sDAAsD;IACtD,QAAQ,CAAC,GAAG,EAAE,mBAAmB,CAAC;CACnC;AAYD;;;;GAIG;AACH,wBAAgB,mBAAmB,CACjC,WAAW,EAAE,SAAS,MAAM,EAAE,EAC9B,OAAO,EAAE,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC,GAAG,SAAS,EACrD,IAAI,EAAE,MAAM,GACX,mBAAmB,CAmDrB"}
|
|
@@ -0,0 +1,89 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* `--resolve` support for `shrk registry <name> exists <id>`.
|
|
3
|
+
*
|
|
4
|
+
* The noun an author types is not always the exact registered slug. `--resolve`
|
|
5
|
+
* bridges that vocabulary gap before the existence check so a duplicate guard
|
|
6
|
+
* can't return a false "not declared" for a construct that DOES exist under its
|
|
7
|
+
* canonical id (a25 §2.4). Resolution is deterministic and layered, most
|
|
8
|
+
* author-controlled first:
|
|
9
|
+
*
|
|
10
|
+
* 1. the registry's declared `aliases` map (explicit synonym → canonical),
|
|
11
|
+
* 2. a case-insensitive exact match against the declared ids,
|
|
12
|
+
* 3. singular/plural normalization (`commands` ↔ `command`),
|
|
13
|
+
* 4. suffix strip/append (`button` ↔ `button-command`, `foo` ↔ `foo.tool`).
|
|
14
|
+
*
|
|
15
|
+
* The first layer that lands on a DECLARED id wins; when nothing resolves, the
|
|
16
|
+
* noun is returned unchanged and unmatched (the honest "genuinely not declared"
|
|
17
|
+
* answer). No layer invents an id that isn't in the registry.
|
|
18
|
+
*/
|
|
19
|
+
/** How a noun resolved to its canonical registered id (for a truthful report). */
|
|
20
|
+
export var ERegistryResolveVia;
|
|
21
|
+
(function (ERegistryResolveVia) {
|
|
22
|
+
ERegistryResolveVia["Identity"] = "identity";
|
|
23
|
+
ERegistryResolveVia["Alias"] = "alias";
|
|
24
|
+
ERegistryResolveVia["Case"] = "case-fold";
|
|
25
|
+
ERegistryResolveVia["SingularPlural"] = "singular/plural";
|
|
26
|
+
ERegistryResolveVia["Suffix"] = "suffix";
|
|
27
|
+
})(ERegistryResolveVia || (ERegistryResolveVia = {}));
|
|
28
|
+
function singularPluralVariants(noun) {
|
|
29
|
+
const out = [];
|
|
30
|
+
const lower = noun.toLowerCase();
|
|
31
|
+
if (lower.endsWith('ies'))
|
|
32
|
+
out.push(noun.slice(0, -3) + 'y');
|
|
33
|
+
if (lower.endsWith('s'))
|
|
34
|
+
out.push(noun.slice(0, -1));
|
|
35
|
+
if (lower.endsWith('y'))
|
|
36
|
+
out.push(noun.slice(0, -1) + 'ies');
|
|
37
|
+
out.push(noun + 's');
|
|
38
|
+
return out;
|
|
39
|
+
}
|
|
40
|
+
/**
|
|
41
|
+
* Resolve a human/synonym `noun` to a canonical registered id. `declaredIds` is
|
|
42
|
+
* the registry's actual declared id list (so no layer can resolve to something
|
|
43
|
+
* that isn't declared); `aliases` is the registry's optional declared map.
|
|
44
|
+
*/
|
|
45
|
+
export function resolveRegistryNoun(declaredIds, aliases, noun) {
|
|
46
|
+
const idSet = new Set(declaredIds);
|
|
47
|
+
// 1. Author-declared alias map — highest priority, honored even if it points
|
|
48
|
+
// at an id the current scan didn't find (the author asserted the mapping).
|
|
49
|
+
const aliased = aliases?.[noun];
|
|
50
|
+
if (aliased !== undefined) {
|
|
51
|
+
return { canonical: aliased, matched: idSet.has(aliased), via: ERegistryResolveVia.Alias };
|
|
52
|
+
}
|
|
53
|
+
// Exact identity.
|
|
54
|
+
if (idSet.has(noun)) {
|
|
55
|
+
return { canonical: noun, matched: true, via: ERegistryResolveVia.Identity };
|
|
56
|
+
}
|
|
57
|
+
const lower = noun.toLowerCase();
|
|
58
|
+
// 2. Case-insensitive exact.
|
|
59
|
+
const ciHit = declaredIds.find((d) => d.toLowerCase() === lower);
|
|
60
|
+
if (ciHit !== undefined) {
|
|
61
|
+
return { canonical: ciHit, matched: true, via: ERegistryResolveVia.Case };
|
|
62
|
+
}
|
|
63
|
+
// 3. Singular/plural.
|
|
64
|
+
for (const variant of singularPluralVariants(noun)) {
|
|
65
|
+
const v = variant.toLowerCase();
|
|
66
|
+
const hit = declaredIds.find((d) => d.toLowerCase() === v);
|
|
67
|
+
if (hit !== undefined) {
|
|
68
|
+
return { canonical: hit, matched: true, via: ERegistryResolveVia.SingularPlural };
|
|
69
|
+
}
|
|
70
|
+
}
|
|
71
|
+
// 4. Suffix strip/append. A declared id whose trailing `-`/`.`/`_` segment,
|
|
72
|
+
// once stripped, equals the noun (`button` ← `button-command`); or the noun
|
|
73
|
+
// plus a suffix another declared id carries yields a declared id.
|
|
74
|
+
const suffixStripped = declaredIds.find((d) => {
|
|
75
|
+
const stripped = d.replace(/[-_.][a-z0-9]+$/i, '');
|
|
76
|
+
return stripped.toLowerCase() === lower && stripped.toLowerCase() !== d.toLowerCase();
|
|
77
|
+
});
|
|
78
|
+
if (suffixStripped !== undefined) {
|
|
79
|
+
return { canonical: suffixStripped, matched: true, via: ERegistryResolveVia.Suffix };
|
|
80
|
+
}
|
|
81
|
+
for (const d of declaredIds) {
|
|
82
|
+
const m = d.match(/([-_.][a-z0-9]+)$/i);
|
|
83
|
+
if (m && `${lower}${m[1].toLowerCase()}` === d.toLowerCase()) {
|
|
84
|
+
return { canonical: d, matched: true, via: ERegistryResolveVia.Suffix };
|
|
85
|
+
}
|
|
86
|
+
}
|
|
87
|
+
// Nothing resolved — the honest unmatched identity.
|
|
88
|
+
return { canonical: noun, matched: false, via: ERegistryResolveVia.Identity };
|
|
89
|
+
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"registry.command.d.ts","sourceRoot":"","sources":["../../src/commands/registry.command.ts"],"names":[],"mappings":"AA4BA,OAAO,EAIL,KAAK,eAAe,EAErB,MAAM,wBAAwB,CAAC;
|
|
1
|
+
{"version":3,"file":"registry.command.d.ts","sourceRoot":"","sources":["../../src/commands/registry.command.ts"],"names":[],"mappings":"AA4BA,OAAO,EAIL,KAAK,eAAe,EAErB,MAAM,wBAAwB,CAAC;AAKhC,eAAO,MAAM,wBAAwB,EAAE,eA8CtC,CAAC;AA6IF,eAAO,MAAM,eAAe,EAAE,eA4B7B,CAAC"}
|
|
@@ -16,7 +16,9 @@
|
|
|
16
16
|
import { buildRegistryLifecycleReport, renderRegistryLifecycleReportText, resolveChangedFiles, resolveProjectConfig, } from '@shrkcrft/inspector';
|
|
17
17
|
import { scanRegistry, registryExists, registryWhere, } from '@shrkcrft/boundaries';
|
|
18
18
|
import { flagBool, flagString, resolveCwd, } from "../command-registry.js";
|
|
19
|
+
import { ExitCode } from "../exit-codes.js";
|
|
19
20
|
import { asJson } from "../output/format-output.js";
|
|
21
|
+
import { resolveRegistryNoun } from "./registry-resolve.js";
|
|
20
22
|
export const registryLifecycleCommand = {
|
|
21
23
|
name: 'lifecycle',
|
|
22
24
|
description: 'Scan the workspace for register/remove symmetry. Read-only.',
|
|
@@ -48,7 +50,14 @@ export const registryLifecycleCommand = {
|
|
|
48
50
|
...(scope ? { scope } : {}),
|
|
49
51
|
...(skipDirs ? { skipDirs } : {}),
|
|
50
52
|
});
|
|
51
|
-
|
|
53
|
+
// Honest exit-code contract (a25 §1 / §2.5): a wedged/timed-out scan OR a
|
|
54
|
+
// scope with zero registrations to check is NOT verified (`2`), never a
|
|
55
|
+
// green `0` an agent's `&& next` would march past.
|
|
56
|
+
const exit = report.timedOut || report.registersFound === 0
|
|
57
|
+
? ExitCode.NotVerified
|
|
58
|
+
: report.missingRemovers.length === 0
|
|
59
|
+
? ExitCode.VerifiedPass
|
|
60
|
+
: ExitCode.Failure;
|
|
52
61
|
if (flagBool(args, 'json')) {
|
|
53
62
|
process.stdout.write(asJson(report) + '\n');
|
|
54
63
|
return exit;
|
|
@@ -123,11 +132,16 @@ async function runRegistryInventory(args, name) {
|
|
|
123
132
|
process.stderr.write('Pass at most one of --fail-if-taken / --fail-if-missing.\n');
|
|
124
133
|
return 2;
|
|
125
134
|
}
|
|
126
|
-
// `--resolve` maps a human noun to the canonical registered id
|
|
127
|
-
// registry's `aliases` map
|
|
128
|
-
//
|
|
135
|
+
// `--resolve` maps a human noun to the canonical registered id before the
|
|
136
|
+
// existence test — via the registry's declared `aliases` map AND generic
|
|
137
|
+
// normalization (case-fold, singular/plural, suffix strip/append) — so a
|
|
138
|
+
// duplicate guard can't return a false "free" on a synonym of an
|
|
139
|
+
// already-taken slug (a25 §2.4).
|
|
129
140
|
const doResolve = flagBool(args, 'resolve');
|
|
130
|
-
const
|
|
141
|
+
const resolution = doResolve
|
|
142
|
+
? resolveRegistryNoun(inventory.entries.map((e) => e.id), decl.aliases, id)
|
|
143
|
+
: undefined;
|
|
144
|
+
const canonical = resolution ? resolution.canonical : id;
|
|
131
145
|
const resolved = canonical !== id;
|
|
132
146
|
const exists = registryExists(inventory, canonical);
|
|
133
147
|
// Exit-code convention:
|
|
@@ -140,14 +154,15 @@ async function runRegistryInventory(args, name) {
|
|
|
140
154
|
process.stdout.write(asJson({
|
|
141
155
|
name: inventory.name,
|
|
142
156
|
id,
|
|
143
|
-
...(resolved ? { resolvedId: canonical } : {}),
|
|
157
|
+
...(resolved ? { resolvedId: canonical, resolvedVia: resolution?.via } : {}),
|
|
144
158
|
exists,
|
|
145
159
|
exitCode: code,
|
|
146
160
|
}) + '\n');
|
|
147
161
|
return code;
|
|
148
162
|
}
|
|
149
|
-
if (resolved)
|
|
150
|
-
process.stdout.write(`resolved "${id}" → "${canonical}" (
|
|
163
|
+
if (resolved) {
|
|
164
|
+
process.stdout.write(`resolved "${id}" → "${canonical}" (${resolution?.via})\n`);
|
|
165
|
+
}
|
|
151
166
|
process.stdout.write(`${exists ? 'yes' : 'no'} — "${canonical}" is ${exists ? 'declared' : 'NOT declared'} in registry "${inventory.name}".\n`);
|
|
152
167
|
return code;
|
|
153
168
|
}
|
|
@@ -1,3 +1,23 @@
|
|
|
1
|
+
import type { IReusePrimitive } from '@shrkcrft/core';
|
|
1
2
|
import { type ICommandHandler } from '../command-registry.js';
|
|
3
|
+
/** A weak (below-confidence) candidate offered as a did-you-mean, never as an answer. */
|
|
4
|
+
interface IReuseSuggestion {
|
|
5
|
+
symbol: string;
|
|
6
|
+
score: number;
|
|
7
|
+
confidence: number;
|
|
8
|
+
matched: readonly string[];
|
|
9
|
+
roles: readonly string[];
|
|
10
|
+
}
|
|
11
|
+
/**
|
|
12
|
+
* Rank ALL primitives by the matcher's own score (descending; ties broken by
|
|
13
|
+
* symbol name so the order is deterministic), then return the top-`k` as scored
|
|
14
|
+
* did-you-mean suggestions. Pure — no graph, no IO — so it is directly
|
|
15
|
+
* unit-testable. When every candidate scores 0 (a nonsense intent that shares no
|
|
16
|
+
* term) the result is the alphabetically-first `k` primitives, each with
|
|
17
|
+
* `score: 0`; the caller states "no candidate shares any term" in that case
|
|
18
|
+
* rather than dumping the whole catalog.
|
|
19
|
+
*/
|
|
20
|
+
export declare function rankReuseSuggestions(primitives: readonly IReusePrimitive[], tokens: readonly string[], k: number): IReuseSuggestion[];
|
|
2
21
|
export declare const reuseCommand: ICommandHandler;
|
|
22
|
+
export {};
|
|
3
23
|
//# sourceMappingURL=reuse.command.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"reuse.command.d.ts","sourceRoot":"","sources":["../../src/commands/reuse.command.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"reuse.command.d.ts","sourceRoot":"","sources":["../../src/commands/reuse.command.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,gBAAgB,CAAC;AACtD,OAAO,EAIL,KAAK,eAAe,EAErB,MAAM,wBAAwB,CAAC;AAkGhC,yFAAyF;AACzF,UAAU,gBAAgB;IACxB,MAAM,EAAE,MAAM,CAAC;IACf,KAAK,EAAE,MAAM,CAAC;IACd,UAAU,EAAE,MAAM,CAAC;IACnB,OAAO,EAAE,SAAS,MAAM,EAAE,CAAC;IAC3B,KAAK,EAAE,SAAS,MAAM,EAAE,CAAC;CAC1B;AAED;;;;;;;;GAQG;AACH,wBAAgB,oBAAoB,CAClC,UAAU,EAAE,SAAS,eAAe,EAAE,EACtC,MAAM,EAAE,SAAS,MAAM,EAAE,EACzB,CAAC,EAAE,MAAM,GACR,gBAAgB,EAAE,CAapB;AAED,eAAO,MAAM,YAAY,EAAE,eA6Q1B,CAAC"}
|
|
@@ -60,17 +60,47 @@ function isConfidentMatch(detail, queryTokenCount) {
|
|
|
60
60
|
return queryTokenCount <= 1;
|
|
61
61
|
}
|
|
62
62
|
const INDEX_RE = /(^|\/)index\.[cm]?[jt]sx?$/;
|
|
63
|
+
/**
|
|
64
|
+
* Rank ALL primitives by the matcher's own score (descending; ties broken by
|
|
65
|
+
* symbol name so the order is deterministic), then return the top-`k` as scored
|
|
66
|
+
* did-you-mean suggestions. Pure — no graph, no IO — so it is directly
|
|
67
|
+
* unit-testable. When every candidate scores 0 (a nonsense intent that shares no
|
|
68
|
+
* term) the result is the alphabetically-first `k` primitives, each with
|
|
69
|
+
* `score: 0`; the caller states "no candidate shares any term" in that case
|
|
70
|
+
* rather than dumping the whole catalog.
|
|
71
|
+
*/
|
|
72
|
+
export function rankReuseSuggestions(primitives, tokens, k) {
|
|
73
|
+
const cap = Math.max(1, Math.floor(k));
|
|
74
|
+
return primitives
|
|
75
|
+
.map((p) => ({ p, detail: scorePrimitive(p, tokens) }))
|
|
76
|
+
.sort((a, b) => b.detail.score - a.detail.score || a.p.symbol.localeCompare(b.p.symbol))
|
|
77
|
+
.slice(0, cap)
|
|
78
|
+
.map(({ p, detail }) => ({
|
|
79
|
+
symbol: p.symbol,
|
|
80
|
+
score: detail.score,
|
|
81
|
+
confidence: tokens.length === 0 ? 0 : detail.matched.length / tokens.length,
|
|
82
|
+
matched: detail.matched,
|
|
83
|
+
roles: p.roles,
|
|
84
|
+
}));
|
|
85
|
+
}
|
|
63
86
|
export const reuseCommand = {
|
|
64
87
|
name: 'reuse',
|
|
65
88
|
description: 'Intent → the canonical primitive to reuse. Matches your intent against configured reusePrimitives[], then resolves the symbol in the code graph to its declaration, public import path, sibling exports, and real consumer files to copy. Deterministic; no AI.',
|
|
66
|
-
usage: 'shrk reuse "<what I want to build>" [--limit N] [--json]',
|
|
89
|
+
usage: 'shrk reuse "<what I want to build>" [--limit N] [--all] [--json]',
|
|
90
|
+
booleanFlags: new Set(['json', 'all']),
|
|
67
91
|
async run(args) {
|
|
68
92
|
const cwd = resolveCwd(args);
|
|
69
93
|
const wantJson = flagBool(args, 'json');
|
|
70
|
-
const
|
|
94
|
+
const wantAll = flagBool(args, 'all');
|
|
95
|
+
// `--limit N` caps both the confident results (historic default 3) and the
|
|
96
|
+
// did-you-mean suggestion list. When omitted, suggestions default to 5 (a
|
|
97
|
+
// couple more than results — the point of a did-you-mean is a short menu).
|
|
98
|
+
const limitFlag = flagNumber(args, 'limit');
|
|
99
|
+
const limit = limitFlag ?? 3;
|
|
100
|
+
const suggestK = limitFlag ?? 5;
|
|
71
101
|
const intent = args.positional.join(' ').trim();
|
|
72
102
|
if (!intent) {
|
|
73
|
-
process.stderr.write('Usage: shrk reuse "<what I want to build>" [--limit N] [--json]\n');
|
|
103
|
+
process.stderr.write('Usage: shrk reuse "<what I want to build>" [--limit N] [--all] [--json]\n');
|
|
74
104
|
return 2;
|
|
75
105
|
}
|
|
76
106
|
const loaded = await resolveProjectConfig(cwd);
|
|
@@ -115,17 +145,39 @@ export const reuseCommand = {
|
|
|
115
145
|
const ranked = confident.slice(0, Math.max(1, limit));
|
|
116
146
|
const store = new GraphStore(cwd);
|
|
117
147
|
const api = store.exists() ? GraphQueryApi.fromStore(cwd) : null;
|
|
118
|
-
// Zero keyword overlap: nothing matched at all
|
|
148
|
+
// Zero keyword overlap: nothing matched at all. Rather than dump the entire
|
|
149
|
+
// declared catalog (dozens of lines an agent must re-read), rank ALL
|
|
150
|
+
// candidates and surface the nearest top-K by name — every score is 0 here,
|
|
151
|
+
// so this is an alphabetized short menu, stated as such. The full catalog is
|
|
152
|
+
// available only behind an explicit `--all`.
|
|
119
153
|
if (scored.length === 0) {
|
|
154
|
+
const suggestions = rankReuseSuggestions(primitives, tokens, suggestK);
|
|
120
155
|
const roles = [...new Set(primitives.flatMap((p) => p.roles))].sort();
|
|
121
156
|
if (wantJson) {
|
|
122
|
-
process.stdout.write(asJson({
|
|
157
|
+
process.stdout.write(asJson({
|
|
158
|
+
schema: 'sharkcraft.reuse/v1',
|
|
159
|
+
intent,
|
|
160
|
+
confident: false,
|
|
161
|
+
results: [],
|
|
162
|
+
suggestions,
|
|
163
|
+
...(wantAll ? { availableRoles: roles } : {}),
|
|
164
|
+
...planeJson,
|
|
165
|
+
}) + '\n');
|
|
123
166
|
return 0;
|
|
124
167
|
}
|
|
125
168
|
process.stdout.write(header(`Reuse: "${intent}"`));
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
169
|
+
if (wantAll) {
|
|
170
|
+
process.stdout.write(' No primitive matched — no candidate shares any term — showing full catalog:\n');
|
|
171
|
+
for (const r of roles.slice(0, 40))
|
|
172
|
+
process.stdout.write(` • ${r}\n`);
|
|
173
|
+
}
|
|
174
|
+
else {
|
|
175
|
+
process.stdout.write(' No strong match — no candidate shares any term with the intent.\n' +
|
|
176
|
+
' Nearest primitives (pass --all for the full catalog):\n');
|
|
177
|
+
for (const s of suggestions) {
|
|
178
|
+
process.stdout.write(` • ${s.symbol} (score ${s.score}; roles: ${s.roles.join(', ') || '—'})\n`);
|
|
179
|
+
}
|
|
180
|
+
}
|
|
129
181
|
writePlaneNotes();
|
|
130
182
|
return 0;
|
|
131
183
|
}
|
|
@@ -133,23 +185,41 @@ export const reuseCommand = {
|
|
|
133
185
|
// entry): below the confidence floor. A miss must look like a miss — never
|
|
134
186
|
// return the nearest collision as a confident answer. Offer did-you-mean.
|
|
135
187
|
if (ranked.length === 0) {
|
|
136
|
-
|
|
188
|
+
// Rank the weakly-overlapping candidates (score > 0) and cap at K — never
|
|
189
|
+
// the whole catalog. `suggestions` and the legacy `didYouMean` alias carry
|
|
190
|
+
// the same scored rows; `--all` additionally dumps every declared role.
|
|
191
|
+
const suggestions = scored.slice(0, Math.max(1, suggestK)).map((x) => ({
|
|
137
192
|
symbol: x.p.symbol,
|
|
138
193
|
score: x.detail.score,
|
|
139
194
|
confidence: confidenceOf(x.detail.matched.length),
|
|
140
195
|
matched: x.detail.matched,
|
|
141
196
|
roles: x.p.roles,
|
|
142
197
|
}));
|
|
198
|
+
const roles = [...new Set(primitives.flatMap((p) => p.roles))].sort();
|
|
143
199
|
if (wantJson) {
|
|
144
|
-
process.stdout.write(asJson({
|
|
200
|
+
process.stdout.write(asJson({
|
|
201
|
+
schema: 'sharkcraft.reuse/v1',
|
|
202
|
+
intent,
|
|
203
|
+
confident: false,
|
|
204
|
+
results: [],
|
|
205
|
+
suggestions,
|
|
206
|
+
didYouMean: suggestions,
|
|
207
|
+
...(wantAll ? { availableRoles: roles } : {}),
|
|
208
|
+
...planeJson,
|
|
209
|
+
}) + '\n');
|
|
145
210
|
return 0;
|
|
146
211
|
}
|
|
147
212
|
process.stdout.write(header(`Reuse: "${intent}"`));
|
|
148
213
|
process.stdout.write(' No confident match — the intent only weakly overlaps existing primitives.\n' +
|
|
149
214
|
' Did you mean (weak, verify before reusing):\n');
|
|
150
|
-
for (const s of
|
|
215
|
+
for (const s of suggestions) {
|
|
151
216
|
process.stdout.write(` • ${s.symbol} (score ${s.score}, ${Math.round(s.confidence * 100)}% of intent; matched: ${s.matched.join(', ') || '—'})\n`);
|
|
152
217
|
}
|
|
218
|
+
if (wantAll) {
|
|
219
|
+
process.stdout.write(' Full catalog (all declared roles):\n');
|
|
220
|
+
for (const r of roles.slice(0, 40))
|
|
221
|
+
process.stdout.write(` • ${r}\n`);
|
|
222
|
+
}
|
|
153
223
|
writePlaneNotes();
|
|
154
224
|
return 0;
|
|
155
225
|
}
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The canonical exit-code contract for every gate / verify / check verb.
|
|
3
|
+
*
|
|
4
|
+
* alpha.24 and alpha.25 made the STDOUT verdicts honest ("not verified",
|
|
5
|
+
* "degraded", "0 rules evaluated", "this is not a pass") but left the exit
|
|
6
|
+
* code returning `0` over those same unverified paths. An agent almost never
|
|
7
|
+
* parses the banner — it chains `shrk <cmd> && <next>` on the *exit code*, so a
|
|
8
|
+
* `0` over a "not verified" result marches straight past the gate. This module
|
|
9
|
+
* is the single source of truth so a chained gate can finally tell apart
|
|
10
|
+
* "passed", "failed", and "never ran".
|
|
11
|
+
*
|
|
12
|
+
* 0 VerifiedPass — checks ran over a NON-EMPTY scope and passed. Never
|
|
13
|
+
* returned when zero units were evaluated.
|
|
14
|
+
* 1 Failure — checks ran and found violations.
|
|
15
|
+
* 2 NotVerified — indeterminate: empty evaluation scope, degraded
|
|
16
|
+
* fallback, short-circuit, timeout, or "refused to run".
|
|
17
|
+
* Distinct from both pass and fail so a chain can branch
|
|
18
|
+
* on it (`|| handle-indeterminate`). This is also the
|
|
19
|
+
* code the CLI already uses for usage errors — both mean
|
|
20
|
+
* "did not produce a verified result".
|
|
21
|
+
*
|
|
22
|
+
* The `gen --typecheck` pre-write gate already refuses-to-nonzero rather than
|
|
23
|
+
* emit an unverified artifact; this generalizes that instinct across the gate
|
|
24
|
+
* surface, adding the third code so "unverified" is distinguishable from
|
|
25
|
+
* "broken".
|
|
26
|
+
*/
|
|
27
|
+
export declare enum ExitCode {
|
|
28
|
+
VerifiedPass = 0,
|
|
29
|
+
Failure = 1,
|
|
30
|
+
NotVerified = 2
|
|
31
|
+
}
|
|
32
|
+
/**
|
|
33
|
+
* Promote a NotVerified (`2`) exit into a Failure-class nonzero (`1`) when the
|
|
34
|
+
* caller opted into `--strict`. This is the one switch an agent flips to make a
|
|
35
|
+
* hard CI gate treat "unverified" as a failure. Any other code passes through
|
|
36
|
+
* unchanged (a real pass stays `0`, a real failure stays `1`). Applied globally
|
|
37
|
+
* in {@link runCli} after the handler returns, so every gate/verify verb honors
|
|
38
|
+
* `--strict` uniformly without threading the flag through each call site.
|
|
39
|
+
*/
|
|
40
|
+
export declare function promoteForStrict(code: number, strict: boolean): number;
|
|
41
|
+
/**
|
|
42
|
+
* True when the argv carries a global `--strict` (bare or `--strict=<level>`).
|
|
43
|
+
* `--strict` is also an established per-command flag (e.g. `check --strict`,
|
|
44
|
+
* `doctor --strict=warnings`) whose local meaning is preserved — this global
|
|
45
|
+
* layer only adds the NotVerified→Failure promotion on top, and only affects a
|
|
46
|
+
* command that actually returned `2`.
|
|
47
|
+
*/
|
|
48
|
+
export declare function argvHasStrict(argv: readonly string[]): boolean;
|
|
49
|
+
//# sourceMappingURL=exit-codes.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"exit-codes.d.ts","sourceRoot":"","sources":["../src/exit-codes.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;GAyBG;AACH,oBAAY,QAAQ;IAClB,YAAY,IAAI;IAChB,OAAO,IAAI;IACX,WAAW,IAAI;CAChB;AAED;;;;;;;GAOG;AACH,wBAAgB,gBAAgB,CAAC,IAAI,EAAE,MAAM,EAAE,MAAM,EAAE,OAAO,GAAG,MAAM,CAGtE;AAED;;;;;;GAMG;AACH,wBAAgB,aAAa,CAAC,IAAI,EAAE,SAAS,MAAM,EAAE,GAAG,OAAO,CAM9D"}
|
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The canonical exit-code contract for every gate / verify / check verb.
|
|
3
|
+
*
|
|
4
|
+
* alpha.24 and alpha.25 made the STDOUT verdicts honest ("not verified",
|
|
5
|
+
* "degraded", "0 rules evaluated", "this is not a pass") but left the exit
|
|
6
|
+
* code returning `0` over those same unverified paths. An agent almost never
|
|
7
|
+
* parses the banner — it chains `shrk <cmd> && <next>` on the *exit code*, so a
|
|
8
|
+
* `0` over a "not verified" result marches straight past the gate. This module
|
|
9
|
+
* is the single source of truth so a chained gate can finally tell apart
|
|
10
|
+
* "passed", "failed", and "never ran".
|
|
11
|
+
*
|
|
12
|
+
* 0 VerifiedPass — checks ran over a NON-EMPTY scope and passed. Never
|
|
13
|
+
* returned when zero units were evaluated.
|
|
14
|
+
* 1 Failure — checks ran and found violations.
|
|
15
|
+
* 2 NotVerified — indeterminate: empty evaluation scope, degraded
|
|
16
|
+
* fallback, short-circuit, timeout, or "refused to run".
|
|
17
|
+
* Distinct from both pass and fail so a chain can branch
|
|
18
|
+
* on it (`|| handle-indeterminate`). This is also the
|
|
19
|
+
* code the CLI already uses for usage errors — both mean
|
|
20
|
+
* "did not produce a verified result".
|
|
21
|
+
*
|
|
22
|
+
* The `gen --typecheck` pre-write gate already refuses-to-nonzero rather than
|
|
23
|
+
* emit an unverified artifact; this generalizes that instinct across the gate
|
|
24
|
+
* surface, adding the third code so "unverified" is distinguishable from
|
|
25
|
+
* "broken".
|
|
26
|
+
*/
|
|
27
|
+
export var ExitCode;
|
|
28
|
+
(function (ExitCode) {
|
|
29
|
+
ExitCode[ExitCode["VerifiedPass"] = 0] = "VerifiedPass";
|
|
30
|
+
ExitCode[ExitCode["Failure"] = 1] = "Failure";
|
|
31
|
+
ExitCode[ExitCode["NotVerified"] = 2] = "NotVerified";
|
|
32
|
+
})(ExitCode || (ExitCode = {}));
|
|
33
|
+
/**
|
|
34
|
+
* Promote a NotVerified (`2`) exit into a Failure-class nonzero (`1`) when the
|
|
35
|
+
* caller opted into `--strict`. This is the one switch an agent flips to make a
|
|
36
|
+
* hard CI gate treat "unverified" as a failure. Any other code passes through
|
|
37
|
+
* unchanged (a real pass stays `0`, a real failure stays `1`). Applied globally
|
|
38
|
+
* in {@link runCli} after the handler returns, so every gate/verify verb honors
|
|
39
|
+
* `--strict` uniformly without threading the flag through each call site.
|
|
40
|
+
*/
|
|
41
|
+
export function promoteForStrict(code, strict) {
|
|
42
|
+
if (strict && code === ExitCode.NotVerified)
|
|
43
|
+
return ExitCode.Failure;
|
|
44
|
+
return code;
|
|
45
|
+
}
|
|
46
|
+
/**
|
|
47
|
+
* True when the argv carries a global `--strict` (bare or `--strict=<level>`).
|
|
48
|
+
* `--strict` is also an established per-command flag (e.g. `check --strict`,
|
|
49
|
+
* `doctor --strict=warnings`) whose local meaning is preserved — this global
|
|
50
|
+
* layer only adds the NotVerified→Failure promotion on top, and only affects a
|
|
51
|
+
* command that actually returned `2`.
|
|
52
|
+
*/
|
|
53
|
+
export function argvHasStrict(argv) {
|
|
54
|
+
for (const t of argv) {
|
|
55
|
+
if (t === '--')
|
|
56
|
+
break;
|
|
57
|
+
if (t === '--strict' || t.startsWith('--strict='))
|
|
58
|
+
return true;
|
|
59
|
+
}
|
|
60
|
+
return false;
|
|
61
|
+
}
|
package/dist/main.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"main.d.ts","sourceRoot":"","sources":["../src/main.ts"],"names":[],"mappings":";AAEA,OAAO,EACL,eAAe,EAKhB,MAAM,uBAAuB,CAAC;
|
|
1
|
+
{"version":3,"file":"main.d.ts","sourceRoot":"","sources":["../src/main.ts"],"names":[],"mappings":";AAEA,OAAO,EACL,eAAe,EAKhB,MAAM,uBAAuB,CAAC;AA8X/B,wBAAgB,aAAa,IAAI,eAAe,CAiY/C;AAED,wBAAsB,MAAM,CAAC,IAAI,EAAE,SAAS,MAAM,EAAE,GAAG,OAAO,CAAC,MAAM,CAAC,CAiCrE;AAqID;;;;;;;;;;;GAWG;AACH,wBAAgB,qBAAqB,CAAC,MAAM,EAAE,SAAS,MAAM,EAAE,GAAG,OAAO,CAoDxE"}
|
package/dist/main.js
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
import { loadDotenv } from "./env/load-dotenv.js";
|
|
3
3
|
import { CommandRegistry, extractGlobalCompress, extractGlobalCwd, parseArgs, } from "./command-registry.js";
|
|
4
|
+
import { argvHasStrict, promoteForStrict } from "./exit-codes.js";
|
|
4
5
|
import { runCommandWithCompression } from "./output/output-compression.js";
|
|
5
6
|
import { initCommand } from "./commands/init.command.js";
|
|
6
7
|
import { inspectCommand } from "./commands/inspect.command.js";
|
|
@@ -509,9 +510,15 @@ export function buildRegistry() {
|
|
|
509
510
|
export async function runCli(argv) {
|
|
510
511
|
const usageStart = performance.now();
|
|
511
512
|
const { cwd: probeCwd, rest: probeArgv } = extractGlobalCwd(argv);
|
|
513
|
+
// Global `--strict` promotes a NotVerified (`2`) verdict to a Failure-class
|
|
514
|
+
// nonzero across every gate/verify verb — one switch to make an "unverified"
|
|
515
|
+
// result fail a hard CI gate. A real pass (`0`) or failure (`1`) is untouched,
|
|
516
|
+
// and each command's own `--strict` semantics (e.g. `check --strict`) still
|
|
517
|
+
// apply beneath this (a25 §1.1).
|
|
518
|
+
const strict = argvHasStrict(argv);
|
|
512
519
|
let exitCode = 0;
|
|
513
520
|
try {
|
|
514
|
-
exitCode = await runCliInner(argv);
|
|
521
|
+
exitCode = promoteForStrict(await runCliInner(argv), strict);
|
|
515
522
|
return exitCode;
|
|
516
523
|
}
|
|
517
524
|
finally {
|
|
@@ -923,6 +930,22 @@ if (isMain ||
|
|
|
923
930
|
// test). Commands that re-exec themselves in an isolated child gate on this
|
|
924
931
|
// so unit tests calling `run()` in-process never spawn a subprocess.
|
|
925
932
|
process.env.SHRK_CLI = '1';
|
|
933
|
+
// Global broken-pipe containment. When a downstream reader closes early
|
|
934
|
+
// (`shrk registry <name> list | head`, `… | grep`), Node raises `write EPIPE`
|
|
935
|
+
// on stdout from the async write/flush path — with no `error` listener that
|
|
936
|
+
// becomes an uncaught exception and a nonzero exit, forging a false failure on
|
|
937
|
+
// a happy-path query whose data was fine (a25 §2.2). Swallowing EPIPE here (a
|
|
938
|
+
// no-op listener) turns it back into a benign early-close: the command keeps
|
|
939
|
+
// its REAL exit code, and nothing is written to the dead pipe. Registered once
|
|
940
|
+
// at startup so every verb that streams a list is covered.
|
|
941
|
+
const swallowPipeError = (err) => {
|
|
942
|
+
if (err && err.code === 'EPIPE')
|
|
943
|
+
return;
|
|
944
|
+
// Any other stdio error (ENOSPC, …) is unrecoverable mid-write; there is
|
|
945
|
+
// nothing safe to print, so contain it rather than crash the shutdown path.
|
|
946
|
+
};
|
|
947
|
+
process.stdout.on('error', swallowPipeError);
|
|
948
|
+
process.stderr.on('error', swallowPipeError);
|
|
926
949
|
loadDotenv(process.cwd());
|
|
927
950
|
const argv = process.argv.slice(2);
|
|
928
951
|
const cleanShutdown = async (code) => {
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@shrkcrft/cli",
|
|
3
|
-
"version": "0.1.0-alpha.
|
|
3
|
+
"version": "0.1.0-alpha.26",
|
|
4
4
|
"description": "SharkCraft CLI (`shrk`): structured project intelligence for AI coding agents.",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"author": "SharkCraft contributors",
|
|
@@ -47,38 +47,38 @@
|
|
|
47
47
|
"typecheck": "tsc --noEmit -p tsconfig.json"
|
|
48
48
|
},
|
|
49
49
|
"dependencies": {
|
|
50
|
-
"@shrkcrft/core": "^0.1.0-alpha.
|
|
51
|
-
"@shrkcrft/compress": "^0.1.0-alpha.
|
|
52
|
-
"@shrkcrft/config": "^0.1.0-alpha.
|
|
53
|
-
"@shrkcrft/workspace": "^0.1.0-alpha.
|
|
54
|
-
"@shrkcrft/knowledge": "^0.1.0-alpha.
|
|
55
|
-
"@shrkcrft/context": "^0.1.0-alpha.
|
|
56
|
-
"@shrkcrft/rules": "^0.1.0-alpha.
|
|
57
|
-
"@shrkcrft/paths": "^0.1.0-alpha.
|
|
58
|
-
"@shrkcrft/templates": "^0.1.0-alpha.
|
|
59
|
-
"@shrkcrft/plugin-api": "^0.1.0-alpha.
|
|
60
|
-
"@shrkcrft/dashboard": "^0.1.0-alpha.
|
|
61
|
-
"@shrkcrft/dashboard-api": "^0.1.0-alpha.
|
|
62
|
-
"@shrkcrft/pipelines": "^0.1.0-alpha.
|
|
63
|
-
"@shrkcrft/presets": "^0.1.0-alpha.
|
|
64
|
-
"@shrkcrft/boundaries": "^0.1.0-alpha.
|
|
65
|
-
"@shrkcrft/graph": "^0.1.0-alpha.
|
|
66
|
-
"@shrkcrft/rule-graph": "^0.1.0-alpha.
|
|
67
|
-
"@shrkcrft/structural-search": "^0.1.0-alpha.
|
|
68
|
-
"@shrkcrft/impact-engine": "^0.1.0-alpha.
|
|
69
|
-
"@shrkcrft/context-planner": "^0.1.0-alpha.
|
|
70
|
-
"@shrkcrft/architecture-guard": "^0.1.0-alpha.
|
|
71
|
-
"@shrkcrft/framework-scanners": "^0.1.0-alpha.
|
|
72
|
-
"@shrkcrft/api-surface-diff": "^0.1.0-alpha.
|
|
73
|
-
"@shrkcrft/quality-gates": "^0.1.0-alpha.
|
|
74
|
-
"@shrkcrft/migrate": "^0.1.0-alpha.
|
|
75
|
-
"@shrkcrft/generator": "^0.1.0-alpha.
|
|
76
|
-
"@shrkcrft/importer": "^0.1.0-alpha.
|
|
77
|
-
"@shrkcrft/inspector": "^0.1.0-alpha.
|
|
78
|
-
"@shrkcrft/ai": "^0.1.0-alpha.
|
|
79
|
-
"@shrkcrft/embeddings": "^0.1.0-alpha.
|
|
80
|
-
"@shrkcrft/shared": "^0.1.0-alpha.
|
|
81
|
-
"@shrkcrft/mcp-server": "^0.1.0-alpha.
|
|
50
|
+
"@shrkcrft/core": "^0.1.0-alpha.26",
|
|
51
|
+
"@shrkcrft/compress": "^0.1.0-alpha.26",
|
|
52
|
+
"@shrkcrft/config": "^0.1.0-alpha.26",
|
|
53
|
+
"@shrkcrft/workspace": "^0.1.0-alpha.26",
|
|
54
|
+
"@shrkcrft/knowledge": "^0.1.0-alpha.26",
|
|
55
|
+
"@shrkcrft/context": "^0.1.0-alpha.26",
|
|
56
|
+
"@shrkcrft/rules": "^0.1.0-alpha.26",
|
|
57
|
+
"@shrkcrft/paths": "^0.1.0-alpha.26",
|
|
58
|
+
"@shrkcrft/templates": "^0.1.0-alpha.26",
|
|
59
|
+
"@shrkcrft/plugin-api": "^0.1.0-alpha.26",
|
|
60
|
+
"@shrkcrft/dashboard": "^0.1.0-alpha.26",
|
|
61
|
+
"@shrkcrft/dashboard-api": "^0.1.0-alpha.26",
|
|
62
|
+
"@shrkcrft/pipelines": "^0.1.0-alpha.26",
|
|
63
|
+
"@shrkcrft/presets": "^0.1.0-alpha.26",
|
|
64
|
+
"@shrkcrft/boundaries": "^0.1.0-alpha.26",
|
|
65
|
+
"@shrkcrft/graph": "^0.1.0-alpha.26",
|
|
66
|
+
"@shrkcrft/rule-graph": "^0.1.0-alpha.26",
|
|
67
|
+
"@shrkcrft/structural-search": "^0.1.0-alpha.26",
|
|
68
|
+
"@shrkcrft/impact-engine": "^0.1.0-alpha.26",
|
|
69
|
+
"@shrkcrft/context-planner": "^0.1.0-alpha.26",
|
|
70
|
+
"@shrkcrft/architecture-guard": "^0.1.0-alpha.26",
|
|
71
|
+
"@shrkcrft/framework-scanners": "^0.1.0-alpha.26",
|
|
72
|
+
"@shrkcrft/api-surface-diff": "^0.1.0-alpha.26",
|
|
73
|
+
"@shrkcrft/quality-gates": "^0.1.0-alpha.26",
|
|
74
|
+
"@shrkcrft/migrate": "^0.1.0-alpha.26",
|
|
75
|
+
"@shrkcrft/generator": "^0.1.0-alpha.26",
|
|
76
|
+
"@shrkcrft/importer": "^0.1.0-alpha.26",
|
|
77
|
+
"@shrkcrft/inspector": "^0.1.0-alpha.26",
|
|
78
|
+
"@shrkcrft/ai": "^0.1.0-alpha.26",
|
|
79
|
+
"@shrkcrft/embeddings": "^0.1.0-alpha.26",
|
|
80
|
+
"@shrkcrft/shared": "^0.1.0-alpha.26",
|
|
81
|
+
"@shrkcrft/mcp-server": "^0.1.0-alpha.26",
|
|
82
82
|
"@huggingface/transformers": "^3.7.5"
|
|
83
83
|
},
|
|
84
84
|
"publishConfig": {
|