@shrkcrft/cli 0.1.0-alpha.20 → 0.1.0-alpha.22
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/check.command.d.ts.map +1 -1
- package/dist/commands/check.command.js +100 -2
- package/dist/commands/command-catalog.d.ts.map +1 -1
- package/dist/commands/command-catalog.js +44 -0
- package/dist/commands/constructs.command.d.ts.map +1 -1
- package/dist/commands/constructs.command.js +40 -9
- package/dist/commands/dev.command.d.ts.map +1 -1
- package/dist/commands/dev.command.js +0 -1
- package/dist/commands/gate.command.d.ts.map +1 -1
- package/dist/commands/gate.command.js +12 -0
- package/dist/commands/graph-code-subverbs.d.ts.map +1 -1
- package/dist/commands/graph-code-subverbs.js +20 -1
- package/dist/commands/policy-lint.command.d.ts +3 -0
- package/dist/commands/policy-lint.command.d.ts.map +1 -0
- package/dist/commands/policy-lint.command.js +122 -0
- package/dist/commands/reuse.command.d.ts +3 -0
- package/dist/commands/reuse.command.d.ts.map +1 -0
- package/dist/commands/reuse.command.js +190 -0
- package/dist/main.d.ts.map +1 -1
- package/dist/main.js +4 -0
- package/dist/surface/profiles.d.ts.map +1 -1
- package/dist/surface/profiles.js +0 -1
- package/package.json +33 -33
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"check.command.d.ts","sourceRoot":"","sources":["../../src/commands/check.command.ts"],"names":[],"mappings":"AAmBA,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":"AAmBA,OAAO,EAML,KAAK,eAAe,EAErB,MAAM,wBAAwB,CAAC;AAuqBhC,eAAO,MAAM,YAAY,EAAE,eA2D1B,CAAC"}
|
|
@@ -6,7 +6,8 @@ import { asJson, header, kv } from "../output/format-output.js";
|
|
|
6
6
|
import { maybeRunInWatchMode } from "../output/watch-loop.js";
|
|
7
7
|
import { validateTemplateVariables } from '@shrkcrft/templates';
|
|
8
8
|
import { FileChangeType, planGeneration } from '@shrkcrft/generator';
|
|
9
|
-
import { evaluateBoundaries, loadTsconfigPaths, scanImports, summarizeImports, } from '@shrkcrft/boundaries';
|
|
9
|
+
import { evaluateBoundaries, loadTsconfigPaths, runWiring, scanImports, summarizeImports, } from '@shrkcrft/boundaries';
|
|
10
|
+
import { loadProjectConfig } from '@shrkcrft/config';
|
|
10
11
|
function knowledgeGroup(inspection) {
|
|
11
12
|
const dup = inspection.validationIssues.filter((i) => i.code === 'duplicate-id');
|
|
12
13
|
const missing = inspection.validationIssues.filter((i) => i.code !== 'duplicate-id');
|
|
@@ -517,12 +518,100 @@ async function checkBoundariesOnce(args) {
|
|
|
517
518
|
return failed ? 1 : 0;
|
|
518
519
|
}
|
|
519
520
|
// ────────────────────────────────────────────────────────────────────────
|
|
521
|
+
// ────────────────────────────────────────────────────────────────────────
|
|
522
|
+
// Subcommand: wiring — "declared but not wired" completeness checks
|
|
523
|
+
// ────────────────────────────────────────────────────────────────────────
|
|
524
|
+
async function checkWiring(args) {
|
|
525
|
+
const cwd = resolveCwd(args);
|
|
526
|
+
const wantJson = flagBool(args, 'json');
|
|
527
|
+
const changedOnly = flagBool(args, 'changed-only');
|
|
528
|
+
const since = flagString(args, 'since');
|
|
529
|
+
const only = flagString(args, 'only');
|
|
530
|
+
// Distinguish "config is invalid" from "config valid with no wiring rules":
|
|
531
|
+
// an invalid config (e.g. a malformed wiringRule) must NOT fail open with a
|
|
532
|
+
// misleading "no rules configured" + exit 0.
|
|
533
|
+
const loaded = await loadProjectConfig(cwd);
|
|
534
|
+
if (!loaded.ok) {
|
|
535
|
+
const msg = loaded.error.message;
|
|
536
|
+
if (wantJson) {
|
|
537
|
+
process.stdout.write(asJson({ schema: 'sharkcraft.wiring/v1', error: msg, rules: [], violations: [], diagnostics: [msg], verdict: 'errors' }) + '\n');
|
|
538
|
+
return 1;
|
|
539
|
+
}
|
|
540
|
+
process.stdout.write(header('Wiring check'));
|
|
541
|
+
process.stdout.write(` ✗ Could not load config: ${msg}\n Run \`shrk doctor\` for details.\n`);
|
|
542
|
+
return 1;
|
|
543
|
+
}
|
|
544
|
+
const rules = loaded.value.config.wiringRules ?? [];
|
|
545
|
+
if (rules.length === 0) {
|
|
546
|
+
if (wantJson) {
|
|
547
|
+
process.stdout.write(asJson({ schema: 'sharkcraft.wiring/v1', rules: [], violations: [], verdict: 'pass' }) + '\n');
|
|
548
|
+
return 0;
|
|
549
|
+
}
|
|
550
|
+
process.stdout.write(header('Wiring check'));
|
|
551
|
+
process.stdout.write(' No wiring rules configured. Declare `wiringRules[]` in sharkcraft.config.ts to enable\n' +
|
|
552
|
+
' cross-file "declared but not wired" checks (see docs/wiring.md).\n');
|
|
553
|
+
return 0;
|
|
554
|
+
}
|
|
555
|
+
let changedFiles;
|
|
556
|
+
if (changedOnly || since) {
|
|
557
|
+
const changed = resolveChangedFiles({
|
|
558
|
+
projectRoot: cwd,
|
|
559
|
+
...(since ? { since } : {}),
|
|
560
|
+
...(changedOnly && !since ? { includeWorktree: true } : {}),
|
|
561
|
+
});
|
|
562
|
+
changedFiles = changed.files;
|
|
563
|
+
}
|
|
564
|
+
const report = runWiring(cwd, rules, {
|
|
565
|
+
...(changedOnly || since ? { changedOnly: true, changedFiles: changedFiles ?? [] } : {}),
|
|
566
|
+
...(only ? { only: only.split(',').map((s) => s.trim()).filter(Boolean) } : {}),
|
|
567
|
+
});
|
|
568
|
+
if (wantJson) {
|
|
569
|
+
process.stdout.write(asJson(report) + '\n');
|
|
570
|
+
return report.verdict === 'errors' ? 1 : 0;
|
|
571
|
+
}
|
|
572
|
+
process.stdout.write(header('Wiring check'));
|
|
573
|
+
process.stdout.write(kv('rules evaluated', String(report.rules.length)) + '\n');
|
|
574
|
+
const errors = report.violations.filter((v) => v.severity === 'error').length;
|
|
575
|
+
const warnings = report.violations.filter((v) => v.severity === 'warning').length;
|
|
576
|
+
process.stdout.write(kv('violations', `${errors} error(s), ${warnings} warning(s)`) + '\n');
|
|
577
|
+
// Misconfigured rules (uncompilable pattern / no capture group) — surface
|
|
578
|
+
// them loudly; a broken rule must never read as a silent green.
|
|
579
|
+
if (report.diagnostics.length > 0) {
|
|
580
|
+
process.stdout.write('\nMisconfigured rules:\n');
|
|
581
|
+
for (const d of report.diagnostics)
|
|
582
|
+
process.stdout.write(` ! ${d}\n`);
|
|
583
|
+
}
|
|
584
|
+
if (report.violations.length === 0 && report.diagnostics.length === 0) {
|
|
585
|
+
process.stdout.write('\nNo wiring violations — every declared token is registered. ✓\n');
|
|
586
|
+
return 0;
|
|
587
|
+
}
|
|
588
|
+
if (report.violations.length === 0) {
|
|
589
|
+
return report.verdict === 'errors' ? 1 : 0;
|
|
590
|
+
}
|
|
591
|
+
// Group by rule for a readable report.
|
|
592
|
+
for (const r of report.rules) {
|
|
593
|
+
if (r.violations.length === 0)
|
|
594
|
+
continue;
|
|
595
|
+
process.stdout.write(`\n[${r.severity}] ${r.ruleId}${r.description ? ' — ' + r.description : ''}\n`);
|
|
596
|
+
process.stdout.write(` declared ${r.declaredCount} / registered ${r.registeredCount} — ${r.violations.length} not wired:\n`);
|
|
597
|
+
for (const v of r.violations.slice(0, 50)) {
|
|
598
|
+
process.stdout.write(` • ${v.token} (${v.file}:${v.line})\n`);
|
|
599
|
+
}
|
|
600
|
+
if (r.violations.length > 50) {
|
|
601
|
+
process.stdout.write(` … (${r.violations.length - 50} more)\n`);
|
|
602
|
+
}
|
|
603
|
+
const hint = r.violations.find((v) => v.hint)?.hint;
|
|
604
|
+
if (hint)
|
|
605
|
+
process.stdout.write(` → ${hint}\n`);
|
|
606
|
+
}
|
|
607
|
+
return report.verdict === 'errors' ? 1 : 0;
|
|
608
|
+
}
|
|
520
609
|
// Main shrk check + subcommands
|
|
521
610
|
// ────────────────────────────────────────────────────────────────────────
|
|
522
611
|
export const checkCommand = {
|
|
523
612
|
name: 'check',
|
|
524
613
|
description: 'Run SharkCraft-level validation across knowledge / rules / templates / pipelines / packs / action hints / doctor. `check boundaries [--watch [--paths a,b] [--debounce N] [--once]]` re-runs the boundary scan on file changes.',
|
|
525
|
-
usage: 'shrk [--cwd <dir>] check [packs|pipelines|knowledge|generation|boundaries|imports] [--strict] [--min-score <0-100>] [--json] [--watch [--paths <list>] [--debounce N] [--once]]',
|
|
614
|
+
usage: 'shrk [--cwd <dir>] check [packs|pipelines|knowledge|generation|boundaries|imports|wiring] [--strict] [--min-score <0-100>] [--changed-only] [--since <ref>] [--only <ids>] [--json] [--watch [--paths <list>] [--debounce N] [--once]]',
|
|
526
615
|
async run(args) {
|
|
527
616
|
const sub = args.positional[0];
|
|
528
617
|
if (sub === 'generation')
|
|
@@ -531,9 +620,18 @@ export const checkCommand = {
|
|
|
531
620
|
return checkBoundaries(args);
|
|
532
621
|
if (sub === 'imports' || sub === 'import-hygiene')
|
|
533
622
|
return checkImports(args);
|
|
623
|
+
if (sub === 'wiring')
|
|
624
|
+
return checkWiring(args);
|
|
534
625
|
if (sub === 'registry-lifecycle') {
|
|
535
626
|
const cwd = resolveCwd(args);
|
|
536
627
|
const { buildRegistryLifecycleReport, renderRegistryLifecycleReportText } = await import('@shrkcrft/inspector');
|
|
628
|
+
// The scan is a single synchronous pass with no streamed output; on a
|
|
629
|
+
// large repo it can run for tens of seconds. Without a heartbeat that
|
|
630
|
+
// silence reads as a hang, so announce the work first (human path only —
|
|
631
|
+
// JSON consumers want a clean stdout).
|
|
632
|
+
if (!flagBool(args, 'json')) {
|
|
633
|
+
process.stderr.write('⏳ Scanning source + registries for lifecycle coverage (can take a while on large repos)…\n');
|
|
634
|
+
}
|
|
537
635
|
const report = buildRegistryLifecycleReport({ projectRoot: cwd });
|
|
538
636
|
if (flagBool(args, 'json')) {
|
|
539
637
|
process.stdout.write(asJson(report) + '\n');
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"command-catalog.d.ts","sourceRoot":"","sources":["../../src/commands/command-catalog.ts"],"names":[],"mappings":"AAAA,oBAAY,WAAW;IACrB,QAAQ,cAAc;IACtB,iBAAiB,mBAAmB;IACpC,gBAAgB,kBAAkB;IAClC,YAAY,kBAAkB;IAC9B,SAAS,eAAe;IACxB,cAAc,oBAAoB;CACnC;AAED;;;;;;GAMG;AACH,oBAAY,cAAc;IACxB,OAAO,YAAY;IACnB,MAAM,WAAW;IACjB,QAAQ,aAAa;IACrB,OAAO,YAAY;IACnB,QAAQ,aAAa;IACrB,MAAM,WAAW;CAClB;AAED,8BAA8B;AAC9B,oBAAY,eAAe;IACzB,KAAK,UAAU;IACf,KAAK,UAAU;IACf,EAAE,OAAO;IACT,UAAU,gBAAgB;IAC1B,UAAU,eAAe;CAC1B;AAED;;;;;;GAMG;AACH,oBAAY,eAAe;IACzB,KAAK,UAAU;IACf,OAAO,YAAY;IACnB,MAAM,WAAW;IACjB,OAAO,YAAY;IACnB,QAAQ,aAAa;IACrB,MAAM,WAAW;IACjB,QAAQ,aAAa;IACrB,OAAO,YAAY;IACnB,QAAQ,aAAa;IACrB,OAAO,YAAY;IACnB,KAAK,UAAU;IACf,MAAM,WAAW;CAClB;AAED;;;;;;GAMG;AACH,oBAAY,gBAAgB;IAC1B,MAAM,WAAW;IACjB,SAAS,cAAc;IACvB,KAAK,UAAU;IACf,UAAU,eAAe;IACzB,OAAO,YAAY;CACpB;AAED;;;;;;;;;;;;;;;;;;;;;;GAsBG;AACH,oBAAY,WAAW;IACrB,IAAI,SAAS;IACb,QAAQ,aAAa;IACrB,YAAY,iBAAiB;CAC9B;AAED,MAAM,WAAW,oBAAoB;IACnC,OAAO,EAAE,MAAM,CAAC;IAChB,WAAW,EAAE,MAAM,CAAC;IACpB,QAAQ,EAAE,MAAM,CAAC;IACjB,WAAW,EAAE,WAAW,CAAC;IACzB,WAAW,EAAE,OAAO,CAAC;IACrB,YAAY,EAAE,OAAO,CAAC;IACtB,SAAS,EAAE,OAAO,CAAC;IACnB,cAAc,EAAE,OAAO,CAAC;IACxB,YAAY,EAAE,OAAO,CAAC;IACtB,OAAO,EAAE,SAAS,MAAM,EAAE,CAAC;IAC3B;;;;OAIG;IACH,OAAO,CAAC,EAAE,cAAc,CAAC;IACzB,8DAA8D;IAC9D,gBAAgB,CAAC,EAAE,SAAS,eAAe,EAAE,CAAC;IAC9C,kCAAkC;IAClC,QAAQ,CAAC,EAAE,eAAe,CAAC;IAC3B;;;;OAIG;IACH,gBAAgB,CAAC,EAAE,MAAM,CAAC;IAC1B;;;;OAIG;IACH,YAAY,CAAC,EAAE,SAAS,MAAM,EAAE,CAAC;IACjC,6DAA6D;IAC7D,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB;;;OAGG;IACH,WAAW,CAAC,EAAE,OAAO,CAAC;IACtB;;;;;;OAMG;IACH,SAAS,CAAC,EAAE,gBAAgB,CAAC;IAC7B,0DAA0D;IAC1D,eAAe,CAAC,EAAE,MAAM,CAAC;IACzB,+DAA+D;IAC/D,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB;;;;OAIG;IACH,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB;;;;OAIG;IACH,iBAAiB,CAAC,EAAE,OAAO,CAAC;IAC5B;;;;;;;;;;;OAWG;IACH,IAAI,CAAC,EAAE,WAAW,CAAC;CACpB;AAED;;;;;GAKG;AACH,eAAO,MAAM,eAAe,EAAE,SAAS,oBAAoB,
|
|
1
|
+
{"version":3,"file":"command-catalog.d.ts","sourceRoot":"","sources":["../../src/commands/command-catalog.ts"],"names":[],"mappings":"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"}
|
|
@@ -382,6 +382,30 @@ export const COMMAND_CATALOG = Object.freeze([
|
|
|
382
382
|
surface: CommandSurface.Common,
|
|
383
383
|
taskRole: CommandTaskRole.Validate,
|
|
384
384
|
}),
|
|
385
|
+
entry({
|
|
386
|
+
command: 'check wiring',
|
|
387
|
+
description: 'Completeness checks: flags config-defined "declared but not wired" tokens (a declared value/identifier set that must be a subset of a registered set). Generic + deterministic; rules from sharkcraft.config.ts wiringRules[]. [--changed-only] [--only <ids>] [--json]',
|
|
388
|
+
category: 'core',
|
|
389
|
+
safetyLevel: SafetyLevel.ReadOnly,
|
|
390
|
+
surface: CommandSurface.Common,
|
|
391
|
+
taskRole: CommandTaskRole.Validate,
|
|
392
|
+
}),
|
|
393
|
+
entry({
|
|
394
|
+
command: 'policy-lint',
|
|
395
|
+
description: 'Lint template/markup, stylesheet, and AOT-invisible TS surfaces against config-defined policyRules[] — sees `.html` files AND inline `template:` strings that tsc/AOT cannot. Deterministic; no AI. [--surface template|style|ts] [--changed-only] [--only <ids>] [--json]',
|
|
396
|
+
category: 'core',
|
|
397
|
+
safetyLevel: SafetyLevel.ReadOnly,
|
|
398
|
+
surface: CommandSurface.Common,
|
|
399
|
+
taskRole: CommandTaskRole.Validate,
|
|
400
|
+
}),
|
|
401
|
+
entry({
|
|
402
|
+
command: 'reuse',
|
|
403
|
+
description: 'Intent → the canonical primitive to reuse: matches your intent against config reusePrimitives[] then resolves the symbol through the code graph (transitive star-barrels) to its import path, sibling exports, and real consumer files to copy. Read-only; no AI.',
|
|
404
|
+
category: 'core',
|
|
405
|
+
safetyLevel: SafetyLevel.ReadOnly,
|
|
406
|
+
surface: CommandSurface.Common,
|
|
407
|
+
taskRole: CommandTaskRole.Search,
|
|
408
|
+
}),
|
|
385
409
|
entry({
|
|
386
410
|
command: 'diff-check',
|
|
387
411
|
description: 'Self-check current git diff against boundary + import-hygiene rules. Single-call composite for agents to validate edits before declaring done. Read-only.',
|
|
@@ -576,6 +600,26 @@ export const COMMAND_CATALOG = Object.freeze([
|
|
|
576
600
|
safetyLevel: SafetyLevel.WritesSessionOnly,
|
|
577
601
|
writesFiles: true,
|
|
578
602
|
}),
|
|
603
|
+
entry({
|
|
604
|
+
command: 'dev status',
|
|
605
|
+
description: 'Show session phase, progress, and next action. Read-only.',
|
|
606
|
+
category: 'dev',
|
|
607
|
+
safetyLevel: SafetyLevel.ReadOnly,
|
|
608
|
+
}),
|
|
609
|
+
entry({
|
|
610
|
+
command: 'dev next',
|
|
611
|
+
description: 'Show (and persist) the next recommended action for a session.',
|
|
612
|
+
category: 'dev',
|
|
613
|
+
safetyLevel: SafetyLevel.WritesSessionOnly,
|
|
614
|
+
writesFiles: true,
|
|
615
|
+
}),
|
|
616
|
+
entry({
|
|
617
|
+
command: 'dev continue',
|
|
618
|
+
description: 'Alias of dev next — advance the session to its next action.',
|
|
619
|
+
category: 'dev',
|
|
620
|
+
safetyLevel: SafetyLevel.WritesSessionOnly,
|
|
621
|
+
writesFiles: true,
|
|
622
|
+
}),
|
|
579
623
|
entry({
|
|
580
624
|
command: 'dev mark-applied',
|
|
581
625
|
description: 'Metadata-only: mark a session plan applied. No source writes.',
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"constructs.command.d.ts","sourceRoot":"","sources":["../../src/commands/constructs.command.ts"],"names":[],"mappings":"AA8BA,OAAO,EAKL,KAAK,eAAe,EAErB,MAAM,wBAAwB,CAAC;
|
|
1
|
+
{"version":3,"file":"constructs.command.d.ts","sourceRoot":"","sources":["../../src/commands/constructs.command.ts"],"names":[],"mappings":"AA8BA,OAAO,EAKL,KAAK,eAAe,EAErB,MAAM,wBAAwB,CAAC;AAkHhC,eAAO,MAAM,qBAAqB,EAAE,eAqBnC,CAAC;AAEF,eAAO,MAAM,oBAAoB,EAAE,eAoDlC,CAAC;AAEF,eAAO,MAAM,sBAAsB,EAAE,eAiGpC,CAAC;AAEF,eAAO,MAAM,uBAAuB,EAAE,eA0ErC,CAAC;AAEF,eAAO,MAAM,wBAAwB,EAAE,eAmCtC,CAAC;AAEF,eAAO,MAAM,sBAAsB,EAAE,eA4BpC,CAAC;AAEF,eAAO,MAAM,oBAAoB,EAAE,eAkClC,CAAC;AAEF,eAAO,MAAM,uBAAuB,EAAE,eAiBrC,CAAC;AAEF,eAAO,MAAM,uBAAuB,EAAE,eAkBrC,CAAC;AAEF,eAAO,MAAM,uBAAuB,EAAE,eA4BrC,CAAC;AAEF,eAAO,MAAM,uBAAuB,EAAE,eA8BrC,CAAC;AAEF,eAAO,MAAM,sBAAsB,EAAE,eA0DpC,CAAC;AAEF,eAAO,MAAM,sBAAsB,EAAE,eA0LpC,CAAC"}
|
|
@@ -68,6 +68,20 @@ function enrichTraceWithGraph(declaredFiles, declaredNames, cwd) {
|
|
|
68
68
|
undeclaredSymbols: [...undeclared].sort(),
|
|
69
69
|
};
|
|
70
70
|
}
|
|
71
|
+
/**
|
|
72
|
+
* The AUTHORITATIVE file set for a construct: declared globs replaced by their
|
|
73
|
+
* graph-resolved matches, declared concrete files kept as-is. This is what the
|
|
74
|
+
* counts, the `files` subverb, and the impact risk heuristic should use — the
|
|
75
|
+
* declared list under-counts because a single `src/**` glob is one entry that
|
|
76
|
+
* really covers N files. Falls back to the raw declared list when the graph is
|
|
77
|
+
* missing, preserving offline/no-index determinism.
|
|
78
|
+
*/
|
|
79
|
+
function effectiveConstructFiles(declaredFiles, graph) {
|
|
80
|
+
if (graph.graphState !== 'fresh')
|
|
81
|
+
return [...declaredFiles];
|
|
82
|
+
const concrete = declaredFiles.filter((f) => !GLOB_MAGIC.test(f));
|
|
83
|
+
return [...new Set([...concrete, ...graph.resolvedFiles])].sort();
|
|
84
|
+
}
|
|
71
85
|
export const constructsListCommand = {
|
|
72
86
|
name: 'list',
|
|
73
87
|
description: 'List registered constructs.',
|
|
@@ -184,14 +198,21 @@ export const constructsTraceCommand = {
|
|
|
184
198
|
registryHints: c.tags?.filter((t) => /(registry|barrel)/i.test(t)) ?? [],
|
|
185
199
|
}
|
|
186
200
|
: undefined;
|
|
201
|
+
const effectiveFiles = effectiveConstructFiles(trace.files, graph);
|
|
187
202
|
if (flagBool(args, 'json')) {
|
|
188
|
-
process.stdout.write(asJson({ ...trace, graph, ...(deepBlock ? { deep: deepBlock } : {}) }) + '\n');
|
|
203
|
+
process.stdout.write(asJson({ ...trace, effectiveFiles, graph, ...(deepBlock ? { deep: deepBlock } : {}) }) + '\n');
|
|
189
204
|
return 0;
|
|
190
205
|
}
|
|
191
206
|
process.stdout.write(header(`Trace: ${id}`));
|
|
192
|
-
|
|
193
|
-
|
|
207
|
+
// Show the graph-resolved file set (globs expanded) as the count, not the
|
|
208
|
+
// raw declared list — otherwise a single `src/**` glob reads as "1 file".
|
|
209
|
+
process.stdout.write(`Files (${effectiveFiles.length}):\n`);
|
|
210
|
+
for (const f of effectiveFiles)
|
|
194
211
|
process.stdout.write(` • ${f}\n`);
|
|
212
|
+
const declaredGlobs = trace.files.filter((f) => GLOB_MAGIC.test(f));
|
|
213
|
+
if (graph.graphState === 'fresh' && declaredGlobs.length > 0) {
|
|
214
|
+
process.stdout.write(` (expanded from declared glob(s): ${declaredGlobs.join(', ')})\n`);
|
|
215
|
+
}
|
|
195
216
|
if (trace.publicApi.length > 0) {
|
|
196
217
|
process.stdout.write(`Public API:\n`);
|
|
197
218
|
for (const a of trace.publicApi)
|
|
@@ -271,13 +292,19 @@ export const constructsImpactCommand = {
|
|
|
271
292
|
const verCfg = inspection.config?.verificationCommands ?? [];
|
|
272
293
|
for (const v of verCfg.slice(0, 3))
|
|
273
294
|
verificationCommands.push(v.command);
|
|
274
|
-
|
|
295
|
+
// Risk must be computed from the graph-resolved file set: a glob-declared
|
|
296
|
+
// construct (`src/**`) is one declared entry but really touches N files, so
|
|
297
|
+
// the old `trace.files.length` under-counted it to risk='low'.
|
|
298
|
+
const declaredNames = new Set([...trace.publicApi, ...trace.tokens, ...trace.events]);
|
|
299
|
+
const graph = enrichTraceWithGraph(trace.files, declaredNames, resolveCwd(args));
|
|
300
|
+
const effectiveFiles = effectiveConstructFiles(trace.files, graph);
|
|
301
|
+
const fileCount = effectiveFiles.length;
|
|
275
302
|
const risk = fileCount > 12 ? 'high' : fileCount > 4 ? 'medium' : 'low';
|
|
276
303
|
const humanReview = risk !== 'low';
|
|
277
304
|
const report = {
|
|
278
305
|
schema: 'sharkcraft.construct-impact/v1',
|
|
279
306
|
id,
|
|
280
|
-
files:
|
|
307
|
+
files: effectiveFiles,
|
|
281
308
|
publicApi: trace.publicApi,
|
|
282
309
|
events: trace.events,
|
|
283
310
|
tokens: trace.tokens,
|
|
@@ -366,18 +393,22 @@ export const constructsFilesCommand = {
|
|
|
366
393
|
return 1;
|
|
367
394
|
}
|
|
368
395
|
const trace = traceConstruct(c);
|
|
396
|
+
// Emit the graph-resolved files (globs expanded), not the raw declared
|
|
397
|
+
// globs — consumers piping `constructs files` expect real paths.
|
|
398
|
+
const graph = enrichTraceWithGraph(trace.files, new Set(), resolveCwd(args));
|
|
399
|
+
const effectiveFiles = effectiveConstructFiles(trace.files, graph);
|
|
369
400
|
if (flagBool(args, 'json')) {
|
|
370
|
-
process.stdout.write(asJson({ id, files:
|
|
401
|
+
process.stdout.write(asJson({ id, files: effectiveFiles }) + '\n');
|
|
371
402
|
return 0;
|
|
372
403
|
}
|
|
373
|
-
for (const f of
|
|
404
|
+
for (const f of effectiveFiles)
|
|
374
405
|
process.stdout.write(`${f}\n`);
|
|
375
406
|
return 0;
|
|
376
407
|
},
|
|
377
408
|
};
|
|
378
409
|
export const constructsApiCommand = {
|
|
379
410
|
name: 'api',
|
|
380
|
-
description: 'Show public-API entries for a construct. --public-only emits the raw list with no header.',
|
|
411
|
+
description: 'Show the DECLARED public-API entries for a construct (the hand-authored list, not an exhaustive scan — run `shrk constructs trace <id>` for graph-verified symbols defined in the files). --public-only emits the raw list with no header.',
|
|
381
412
|
usage: 'shrk constructs api <id> [--public-only] [--json]',
|
|
382
413
|
async run(args) {
|
|
383
414
|
const id = args.positional[0];
|
|
@@ -432,7 +463,7 @@ export const constructsEventsCommand = {
|
|
|
432
463
|
};
|
|
433
464
|
export const constructsTokensCommand = {
|
|
434
465
|
name: 'tokens',
|
|
435
|
-
description: 'List tokens contributed by constructs.',
|
|
466
|
+
description: 'List the DECLARED tokens contributed by constructs (the hand-authored list, not an exhaustive scan).',
|
|
436
467
|
usage: 'shrk constructs tokens [<id>] [--json]',
|
|
437
468
|
async run(args) {
|
|
438
469
|
const id = args.positional[0];
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"dev.command.d.ts","sourceRoot":"","sources":["../../src/commands/dev.command.ts"],"names":[],"mappings":"AA6CA,OAAO,EAML,KAAK,eAAe,EAErB,MAAM,wBAAwB,CAAC;
|
|
1
|
+
{"version":3,"file":"dev.command.d.ts","sourceRoot":"","sources":["../../src/commands/dev.command.ts"],"names":[],"mappings":"AA6CA,OAAO,EAML,KAAK,eAAe,EAErB,MAAM,wBAAwB,CAAC;AAg8ChC,eAAO,MAAM,UAAU,EAAE,eAkExB,CAAC"}
|
|
@@ -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":"AAQA,OAAO,EAIL,KAAK,eAAe,EAErB,MAAM,wBAAwB,CAAC;AAGhC;;;;;;;;;;;GAWG;AACH,eAAO,MAAM,WAAW,EAAE,eA0GzB,CAAC"}
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { QualityGateReportStore, renderGateReportMarkdown, runQualityGates, } from '@shrkcrft/quality-gates';
|
|
2
|
+
import { loadProjectConfig } from '@shrkcrft/config';
|
|
2
3
|
import { chmodSync, existsSync, mkdirSync, writeFileSync } from 'node:fs';
|
|
3
4
|
import * as nodePath from 'node:path';
|
|
4
5
|
import { flagBool, flagString, resolveCwd, } from "../command-registry.js";
|
|
@@ -45,9 +46,20 @@ export const gateCommand = {
|
|
|
45
46
|
// --arch-all: fail on TOTAL architecture errors (ignore the frozen baseline).
|
|
46
47
|
// By default the arch gate is baseline-relative — it fails only on NEW errors.
|
|
47
48
|
const archAll = flagBool(args, 'arch-all');
|
|
49
|
+
// Wiring rules come from the project config; the gate is skipped (never red)
|
|
50
|
+
// when none are declared, so this is inert for projects that don't opt in.
|
|
51
|
+
// An INVALID config is surfaced (warn) rather than silently disabling wiring.
|
|
52
|
+
const loadedConfig = await loadProjectConfig(cwd);
|
|
53
|
+
const wiringRules = loadedConfig.ok ? loadedConfig.value.config.wiringRules ?? [] : [];
|
|
54
|
+
const wiringConfigError = loadedConfig.ok ? undefined : loadedConfig.error.message;
|
|
48
55
|
const report = runQualityGates({
|
|
49
56
|
projectRoot: cwd,
|
|
50
57
|
...(archAll ? { arch: { baselineRelative: false } } : {}),
|
|
58
|
+
...(wiringConfigError
|
|
59
|
+
? { wiring: { configError: wiringConfigError } }
|
|
60
|
+
: wiringRules.length > 0
|
|
61
|
+
? { wiring: { rules: wiringRules } }
|
|
62
|
+
: {}),
|
|
51
63
|
impact: {
|
|
52
64
|
...(sinceRef ? { sinceRef } : {}),
|
|
53
65
|
...(failOn ? { failOn } : {}),
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"graph-code-subverbs.d.ts","sourceRoot":"","sources":["../../src/commands/graph-code-subverbs.ts"],"names":[],"mappings":"AA0BA,OAAO,EAAoC,KAAK,UAAU,EAAE,MAAM,wBAAwB,CAAC;AAiI3F,wBAAsB,aAAa,CAAC,IAAI,EAAE,UAAU,GAAG,OAAO,CAAC,MAAM,CAAC,CAgBrE;AA4FD,wBAAsB,cAAc,CAAC,IAAI,EAAE,UAAU,GAAG,OAAO,CAAC,MAAM,CAAC,CA+DtE;AAiBD,wBAAsB,kBAAkB,CAAC,IAAI,EAAE,UAAU,GAAG,OAAO,CAAC,MAAM,CAAC,CAwF1E;AAID,wBAAsB,YAAY,CAAC,IAAI,EAAE,UAAU,GAAG,OAAO,CAAC,MAAM,CAAC,CA8EpE;AAID,wBAAsB,cAAc,CAAC,IAAI,EAAE,UAAU,GAAG,OAAO,CAAC,MAAM,CAAC,CAmFtE;AAID,wBAAsB,cAAc,CAAC,IAAI,EAAE,UAAU,GAAG,OAAO,CAAC,MAAM,CAAC,CAiDtE;AAID,wBAAsB,eAAe,CAAC,IAAI,EAAE,UAAU,GAAG,OAAO,CAAC,MAAM,CAAC,CAgMvE;AAID,wBAAsB,cAAc,CAAC,IAAI,EAAE,UAAU,GAAG,OAAO,CAAC,MAAM,CAAC,CA8HtE;AAID;;;;;;GAMG;AACH,wBAAsB,YAAY,CAAC,IAAI,EAAE,UAAU,GAAG,OAAO,CAAC,MAAM,CAAC,CA+CpE;AAID,wBAAsB,eAAe,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":"AA0BA,OAAO,EAAoC,KAAK,UAAU,EAAE,MAAM,wBAAwB,CAAC;AAiI3F,wBAAsB,aAAa,CAAC,IAAI,EAAE,UAAU,GAAG,OAAO,CAAC,MAAM,CAAC,CAgBrE;AA4FD,wBAAsB,cAAc,CAAC,IAAI,EAAE,UAAU,GAAG,OAAO,CAAC,MAAM,CAAC,CA+DtE;AAiBD,wBAAsB,kBAAkB,CAAC,IAAI,EAAE,UAAU,GAAG,OAAO,CAAC,MAAM,CAAC,CAwF1E;AAID,wBAAsB,YAAY,CAAC,IAAI,EAAE,UAAU,GAAG,OAAO,CAAC,MAAM,CAAC,CA8EpE;AAID,wBAAsB,cAAc,CAAC,IAAI,EAAE,UAAU,GAAG,OAAO,CAAC,MAAM,CAAC,CAmFtE;AAID,wBAAsB,cAAc,CAAC,IAAI,EAAE,UAAU,GAAG,OAAO,CAAC,MAAM,CAAC,CAiDtE;AAID,wBAAsB,eAAe,CAAC,IAAI,EAAE,UAAU,GAAG,OAAO,CAAC,MAAM,CAAC,CAgMvE;AAID,wBAAsB,cAAc,CAAC,IAAI,EAAE,UAAU,GAAG,OAAO,CAAC,MAAM,CAAC,CA8HtE;AAID;;;;;;GAMG;AACH,wBAAsB,YAAY,CAAC,IAAI,EAAE,UAAU,GAAG,OAAO,CAAC,MAAM,CAAC,CA+CpE;AAID,wBAAsB,eAAe,CAAC,IAAI,EAAE,UAAU,GAAG,OAAO,CAAC,MAAM,CAAC,CAkGvE;AAyBD;;;;;;;;;;;;GAYG;AACH,wBAAsB,YAAY,CAAC,IAAI,EAAE,UAAU,GAAG,OAAO,CAAC,MAAM,CAAC,CAgHpE"}
|
|
@@ -989,7 +989,26 @@ export async function runGraphCallers(args) {
|
|
|
989
989
|
// call/reference sites in one file to a single edge. Say so, otherwise `total`
|
|
990
990
|
// reads as a raw invocation count and under-reports.
|
|
991
991
|
const dedupNote = 'total counts distinct caller files — multiple sites within one file collapse to a single entry.';
|
|
992
|
-
|
|
992
|
+
// A class/type used only via `new`, a type annotation, or DI has ZERO call
|
|
993
|
+
// sites but real references. In the default `call` mode that surfaces as a
|
|
994
|
+
// bare `0`, which reads as "unused" — detect the case and point at
|
|
995
|
+
// `--mode reference` so the result is actionable instead of misleading.
|
|
996
|
+
let referenceHint;
|
|
997
|
+
if (mode === 'call' && liveSites.length === 0) {
|
|
998
|
+
// Filter by the same deleted-file set as liveSites so the hint can never
|
|
999
|
+
// contradict the call-mode result or the `--mode reference` total — without
|
|
1000
|
+
// this, stale Calls/References edges in files deleted since indexing would
|
|
1001
|
+
// fire a false "0 calls but N references" hint. referenceSitesOf dedups by
|
|
1002
|
+
// file, so the count is distinct referencing files (matches --mode reference
|
|
1003
|
+
// total), hence "file(s)" not "site(s)".
|
|
1004
|
+
const refCount = api
|
|
1005
|
+
.referenceSitesOf(sym.id)
|
|
1006
|
+
.filter((s) => !s.node.path || !fresh.deletedSet.has(s.node.path)).length;
|
|
1007
|
+
if (refCount > 0) {
|
|
1008
|
+
referenceHint = `0 call sites, but ${refCount} file(s) reference it (new/type/DI usage) — run \`shrk graph callers ${sym.label} --mode reference\` to see them.`;
|
|
1009
|
+
}
|
|
1010
|
+
}
|
|
1011
|
+
const note = [ambiguityNote, langNote, dedupNote, referenceHint].filter(Boolean).join(' ');
|
|
993
1012
|
const payload = {
|
|
994
1013
|
schema: 'sharkcraft.graph-callers/v1',
|
|
995
1014
|
symbol: nodeSummary(sym),
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"policy-lint.command.d.ts","sourceRoot":"","sources":["../../src/commands/policy-lint.command.ts"],"names":[],"mappings":"AAKA,OAAO,EAIL,KAAK,eAAe,EAErB,MAAM,wBAAwB,CAAC;AAKhC,eAAO,MAAM,iBAAiB,EAAE,eAiI/B,CAAC"}
|
|
@@ -0,0 +1,122 @@
|
|
|
1
|
+
import * as nodePath from 'node:path';
|
|
2
|
+
import { runPolicyLint } from '@shrkcrft/boundaries';
|
|
3
|
+
import { loadProjectConfig } from '@shrkcrft/config';
|
|
4
|
+
import { resolveChangedFiles } from '@shrkcrft/inspector';
|
|
5
|
+
import { flagBool, flagString, resolveCwd, } from "../command-registry.js";
|
|
6
|
+
import { asJson, header, kv } from "../output/format-output.js";
|
|
7
|
+
const VALID_SURFACES = new Set(['template', 'style', 'ts']);
|
|
8
|
+
export const policyLintCommand = {
|
|
9
|
+
name: 'policy-lint',
|
|
10
|
+
description: 'Lint template/markup, stylesheet, and AOT-invisible TS surfaces against data-defined policyRules[] (e.g. flag raw markup when a primitive exists). Sees `.html` files AND inline `template:` strings — surfaces tsc/AOT cannot. Deterministic; no AI.',
|
|
11
|
+
usage: 'shrk [--cwd <dir>] policy-lint [--surface template|style|ts] [--changed-only] [--since <ref>] [--only <ids>] [--json]',
|
|
12
|
+
async run(args) {
|
|
13
|
+
const cwd = resolveCwd(args);
|
|
14
|
+
const wantJson = flagBool(args, 'json');
|
|
15
|
+
const changedOnly = flagBool(args, 'changed-only');
|
|
16
|
+
const since = flagString(args, 'since');
|
|
17
|
+
const only = flagString(args, 'only');
|
|
18
|
+
const surfaceRaw = flagString(args, 'surface');
|
|
19
|
+
let surfaces;
|
|
20
|
+
if (surfaceRaw) {
|
|
21
|
+
const parts = surfaceRaw.split(',').map((s) => s.trim()).filter(Boolean);
|
|
22
|
+
const bad = parts.filter((s) => !VALID_SURFACES.has(s));
|
|
23
|
+
if (bad.length > 0) {
|
|
24
|
+
process.stderr.write(`Unknown --surface "${bad.join(', ')}". Use template | style | ts.\n`);
|
|
25
|
+
return 2;
|
|
26
|
+
}
|
|
27
|
+
surfaces = parts;
|
|
28
|
+
}
|
|
29
|
+
// Distinguish invalid config from valid-with-no-rules (no silent fail-open).
|
|
30
|
+
const loaded = await loadProjectConfig(cwd);
|
|
31
|
+
if (!loaded.ok) {
|
|
32
|
+
const msg = loaded.error.message;
|
|
33
|
+
if (wantJson) {
|
|
34
|
+
process.stdout.write(asJson({ schema: 'sharkcraft.policy-lint/v1', error: msg, rules: [], findings: [], diagnostics: [msg], verdict: 'errors' }) + '\n');
|
|
35
|
+
return 1;
|
|
36
|
+
}
|
|
37
|
+
process.stdout.write(header('Policy lint'));
|
|
38
|
+
process.stdout.write(` ✗ Could not load config: ${msg}\n Run \`shrk doctor\` for details.\n`);
|
|
39
|
+
return 1;
|
|
40
|
+
}
|
|
41
|
+
const rules = loaded.value.config.policyRules ?? [];
|
|
42
|
+
if (rules.length === 0) {
|
|
43
|
+
if (wantJson) {
|
|
44
|
+
process.stdout.write(asJson({ schema: 'sharkcraft.policy-lint/v1', rules: [], findings: [], diagnostics: [], verdict: 'pass' }) + '\n');
|
|
45
|
+
return 0;
|
|
46
|
+
}
|
|
47
|
+
process.stdout.write(header('Policy lint'));
|
|
48
|
+
process.stdout.write(' No policy rules configured. Declare `policyRules[]` in sharkcraft.config.ts to lint\n' +
|
|
49
|
+
' templates / styles / AOT-invisible TS shapes (see docs/policy-lint.md).\n');
|
|
50
|
+
return 0;
|
|
51
|
+
}
|
|
52
|
+
// A typo'd --only id must not silently select nothing and report green.
|
|
53
|
+
if (only) {
|
|
54
|
+
const requested = only.split(',').map((s) => s.trim()).filter(Boolean);
|
|
55
|
+
const known = new Set(rules.map((r) => r.id));
|
|
56
|
+
const unknown = requested.filter((id) => !known.has(id));
|
|
57
|
+
if (unknown.length > 0) {
|
|
58
|
+
process.stderr.write(`Unknown --only rule id(s): ${unknown.join(', ')}. Configured: ${[...known].join(', ') || '(none)'}\n`);
|
|
59
|
+
return 2;
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
let changedFiles;
|
|
63
|
+
if (changedOnly || since) {
|
|
64
|
+
changedFiles = resolveChangedFiles({
|
|
65
|
+
projectRoot: cwd,
|
|
66
|
+
...(since ? { since } : {}),
|
|
67
|
+
...(changedOnly && !since ? { includeWorktree: true } : {}),
|
|
68
|
+
}).files;
|
|
69
|
+
}
|
|
70
|
+
// Don't lint SharkCraft's own asset/config dir by default (its .ts files
|
|
71
|
+
// hold the rule definitions themselves, which can self-match).
|
|
72
|
+
const sharkcraftRel = nodePath.relative(cwd, loaded.value.sharkcraftDir).split(nodePath.sep).join('/');
|
|
73
|
+
const excludeDirs = sharkcraftRel && !sharkcraftRel.startsWith('..') ? [sharkcraftRel] : [];
|
|
74
|
+
const report = runPolicyLint(cwd, rules, {
|
|
75
|
+
...(surfaces ? { surfaces } : {}),
|
|
76
|
+
...(changedOnly || since ? { changedOnly: true, changedFiles: changedFiles ?? [] } : {}),
|
|
77
|
+
...(only ? { only: only.split(',').map((s) => s.trim()).filter(Boolean) } : {}),
|
|
78
|
+
...(excludeDirs.length > 0 ? { excludeDirs } : {}),
|
|
79
|
+
});
|
|
80
|
+
if (wantJson) {
|
|
81
|
+
process.stdout.write(asJson(report) + '\n');
|
|
82
|
+
return report.verdict === 'errors' ? 1 : 0;
|
|
83
|
+
}
|
|
84
|
+
process.stdout.write(header('Policy lint'));
|
|
85
|
+
process.stdout.write(kv('rules evaluated', String(report.rules.length)) + '\n');
|
|
86
|
+
const errors = report.findings.filter((f) => f.severity === 'error').length;
|
|
87
|
+
const warnings = report.findings.filter((f) => f.severity === 'warning').length;
|
|
88
|
+
process.stdout.write(kv('findings', `${errors} error(s), ${warnings} warning(s)`) + '\n');
|
|
89
|
+
if (report.diagnostics.length > 0) {
|
|
90
|
+
process.stdout.write('\nMisconfigured rules:\n');
|
|
91
|
+
for (const d of report.diagnostics)
|
|
92
|
+
process.stdout.write(` ! ${d}\n`);
|
|
93
|
+
}
|
|
94
|
+
if (report.findings.length === 0 && report.diagnostics.length === 0) {
|
|
95
|
+
process.stdout.write('\nNo policy violations on the scanned surfaces. ✓\n');
|
|
96
|
+
return 0;
|
|
97
|
+
}
|
|
98
|
+
// Group findings by rule.
|
|
99
|
+
const byRule = new Map();
|
|
100
|
+
for (const f of report.findings) {
|
|
101
|
+
const arr = byRule.get(f.ruleId) ?? [];
|
|
102
|
+
arr.push(f);
|
|
103
|
+
byRule.set(f.ruleId, arr);
|
|
104
|
+
}
|
|
105
|
+
for (const r of report.rules) {
|
|
106
|
+
const fs = byRule.get(r.ruleId);
|
|
107
|
+
if (!fs || fs.length === 0)
|
|
108
|
+
continue;
|
|
109
|
+
process.stdout.write(`\n[${r.severity}] ${r.ruleId} (${r.surface}) — ${fs[0].message}\n`);
|
|
110
|
+
for (const f of fs.slice(0, 50)) {
|
|
111
|
+
const tag = f.inlineTemplate ? ' [inline template]' : '';
|
|
112
|
+
process.stdout.write(` • ${f.match} (${f.file}:${f.line})${tag}\n`);
|
|
113
|
+
}
|
|
114
|
+
if (fs.length > 50)
|
|
115
|
+
process.stdout.write(` … (${fs.length - 50} more)\n`);
|
|
116
|
+
const suggest = fs.find((f) => f.suggest)?.suggest;
|
|
117
|
+
if (suggest)
|
|
118
|
+
process.stdout.write(` → ${suggest}\n`);
|
|
119
|
+
}
|
|
120
|
+
return report.verdict === 'errors' ? 1 : 0;
|
|
121
|
+
},
|
|
122
|
+
};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"reuse.command.d.ts","sourceRoot":"","sources":["../../src/commands/reuse.command.ts"],"names":[],"mappings":"AAGA,OAAO,EAIL,KAAK,eAAe,EAErB,MAAM,wBAAwB,CAAC;AA4DhC,eAAO,MAAM,YAAY,EAAE,eA0J1B,CAAC"}
|
|
@@ -0,0 +1,190 @@
|
|
|
1
|
+
import { GraphStore, GraphQueryApi } from '@shrkcrft/graph';
|
|
2
|
+
import { loadProjectConfig } from '@shrkcrft/config';
|
|
3
|
+
import { flagBool, flagNumber, resolveCwd, } from "../command-registry.js";
|
|
4
|
+
import { asJson, header } from "../output/format-output.js";
|
|
5
|
+
const STOP = new Set([
|
|
6
|
+
'the', 'a', 'an', 'to', 'for', 'of', 'and', 'or', 'with', 'in', 'on', 'into', 'my',
|
|
7
|
+
'add', 'use', 'using', 'create', 'make', 'new', 'build', 'want', 'need', 'how', 'do',
|
|
8
|
+
]);
|
|
9
|
+
function tokenize(s) {
|
|
10
|
+
// Min length 3: 2-char tokens (`ui`, `id`) substring-match unrelated text
|
|
11
|
+
// (`guidance`, `valid`) and produce false-positive primitive matches.
|
|
12
|
+
return [
|
|
13
|
+
...new Set(s
|
|
14
|
+
.toLowerCase()
|
|
15
|
+
.replace(/[^a-z0-9]+/g, ' ')
|
|
16
|
+
.split(' ')
|
|
17
|
+
.filter((t) => t.length >= 3 && !STOP.has(t))),
|
|
18
|
+
];
|
|
19
|
+
}
|
|
20
|
+
function scorePrimitive(p, tokens) {
|
|
21
|
+
// Substring match (so intent "debounce" matches symbol `useDebounce`); the
|
|
22
|
+
// 3-char minimum above keeps it from over-matching on tiny fragments.
|
|
23
|
+
const hay = [p.symbol, ...(p.roles ?? []), ...(p.keywords ?? []), p.description ?? '']
|
|
24
|
+
.join(' ')
|
|
25
|
+
.toLowerCase();
|
|
26
|
+
let s = 0;
|
|
27
|
+
for (const t of tokens)
|
|
28
|
+
if (hay.includes(t))
|
|
29
|
+
s += 1;
|
|
30
|
+
// A role the intent mentions is a strong signal; re-weight role hits.
|
|
31
|
+
for (const role of p.roles ?? []) {
|
|
32
|
+
const rl = role.toLowerCase();
|
|
33
|
+
if (rl.length >= 3 && tokens.some((t) => rl.includes(t)))
|
|
34
|
+
s += 0.5;
|
|
35
|
+
}
|
|
36
|
+
return s;
|
|
37
|
+
}
|
|
38
|
+
const INDEX_RE = /(^|\/)index\.[cm]?[jt]sx?$/;
|
|
39
|
+
export const reuseCommand = {
|
|
40
|
+
name: 'reuse',
|
|
41
|
+
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.',
|
|
42
|
+
usage: 'shrk reuse "<what I want to build>" [--limit N] [--json]',
|
|
43
|
+
async run(args) {
|
|
44
|
+
const cwd = resolveCwd(args);
|
|
45
|
+
const wantJson = flagBool(args, 'json');
|
|
46
|
+
const limit = flagNumber(args, 'limit') ?? 3;
|
|
47
|
+
const intent = args.positional.join(' ').trim();
|
|
48
|
+
if (!intent) {
|
|
49
|
+
process.stderr.write('Usage: shrk reuse "<what I want to build>" [--limit N] [--json]\n');
|
|
50
|
+
return 2;
|
|
51
|
+
}
|
|
52
|
+
const loaded = await loadProjectConfig(cwd);
|
|
53
|
+
if (!loaded.ok) {
|
|
54
|
+
const msg = loaded.error.message;
|
|
55
|
+
if (wantJson) {
|
|
56
|
+
process.stdout.write(asJson({ schema: 'sharkcraft.reuse/v1', intent, error: msg, results: [] }) + '\n');
|
|
57
|
+
return 1;
|
|
58
|
+
}
|
|
59
|
+
process.stdout.write(header(`Reuse: "${intent}"`));
|
|
60
|
+
process.stdout.write(` ✗ Could not load config: ${msg}\n Run \`shrk doctor\` for details.\n`);
|
|
61
|
+
return 1;
|
|
62
|
+
}
|
|
63
|
+
const primitives = loaded.value.config.reusePrimitives ?? [];
|
|
64
|
+
if (primitives.length === 0) {
|
|
65
|
+
if (wantJson) {
|
|
66
|
+
process.stdout.write(asJson({ schema: 'sharkcraft.reuse/v1', intent, results: [] }) + '\n');
|
|
67
|
+
return 0;
|
|
68
|
+
}
|
|
69
|
+
process.stdout.write(header(`Reuse: "${intent}"`));
|
|
70
|
+
process.stdout.write(' No reuse primitives configured. Declare `reusePrimitives[]` in sharkcraft.config.ts\n' +
|
|
71
|
+
' to map roles/intents to canonical symbols (see docs/reuse.md).\n');
|
|
72
|
+
return 0;
|
|
73
|
+
}
|
|
74
|
+
const tokens = tokenize(intent);
|
|
75
|
+
const ranked = primitives
|
|
76
|
+
.map((p) => ({ p, score: scorePrimitive(p, tokens) }))
|
|
77
|
+
.filter((x) => x.score > 0)
|
|
78
|
+
.sort((a, b) => b.score - a.score || a.p.symbol.localeCompare(b.p.symbol))
|
|
79
|
+
.slice(0, Math.max(1, limit));
|
|
80
|
+
const store = new GraphStore(cwd);
|
|
81
|
+
const api = store.exists() ? GraphQueryApi.fromStore(cwd) : null;
|
|
82
|
+
if (ranked.length === 0) {
|
|
83
|
+
const roles = [...new Set(primitives.flatMap((p) => p.roles))].sort();
|
|
84
|
+
if (wantJson) {
|
|
85
|
+
process.stdout.write(asJson({ schema: 'sharkcraft.reuse/v1', intent, results: [], availableRoles: roles }) + '\n');
|
|
86
|
+
return 0;
|
|
87
|
+
}
|
|
88
|
+
process.stdout.write(header(`Reuse: "${intent}"`));
|
|
89
|
+
process.stdout.write(' No primitive matched. Available roles:\n');
|
|
90
|
+
for (const r of roles.slice(0, 40))
|
|
91
|
+
process.stdout.write(` • ${r}\n`);
|
|
92
|
+
return 0;
|
|
93
|
+
}
|
|
94
|
+
const results = ranked.map(({ p, score }) => {
|
|
95
|
+
const r = { symbol: p.symbol, score, roles: p.roles, siblings: [], consumers: [] };
|
|
96
|
+
if (p.description)
|
|
97
|
+
r.description = p.description;
|
|
98
|
+
if (p.importPath)
|
|
99
|
+
r.importPath = p.importPath;
|
|
100
|
+
if (api) {
|
|
101
|
+
// Disambiguate same-named declarations deterministically: prefer
|
|
102
|
+
// exported symbols, then shallowest path; disclose the alternates.
|
|
103
|
+
const candidates = api
|
|
104
|
+
.findSymbol(p.symbol, { exact: true })
|
|
105
|
+
.slice()
|
|
106
|
+
.sort((a, b) => (a.path ?? '').localeCompare(b.path ?? ''));
|
|
107
|
+
const exported = candidates.filter((c) => c.data?.['isExported'] === true);
|
|
108
|
+
const pool = exported.length > 0 ? exported : candidates;
|
|
109
|
+
const sym = pool[0];
|
|
110
|
+
if (sym) {
|
|
111
|
+
if (sym.path)
|
|
112
|
+
r.declaredIn = sym.path;
|
|
113
|
+
if (sym.line)
|
|
114
|
+
r.declaredLine = sym.line;
|
|
115
|
+
if (sym.path) {
|
|
116
|
+
const fileNode = api.findFile(sym.path);
|
|
117
|
+
if (fileNode) {
|
|
118
|
+
r.siblings = api
|
|
119
|
+
.symbolsIn(fileNode.id)
|
|
120
|
+
.filter((s) => s.data?.['isExported'] === true && s.label && s.label !== p.symbol)
|
|
121
|
+
.map((s) => s.label)
|
|
122
|
+
.slice(0, 8);
|
|
123
|
+
// When no public importPath is configured, surface a re-exporting
|
|
124
|
+
// barrel as a hint (we never fabricate a module specifier from a
|
|
125
|
+
// deep file path — that would be a broken/unusable import).
|
|
126
|
+
if (!r.importPath) {
|
|
127
|
+
const barrel = api.importersOf(fileNode.id).find((n) => n.path && INDEX_RE.test(n.path));
|
|
128
|
+
if (barrel?.path)
|
|
129
|
+
r.reExportedVia = barrel.path;
|
|
130
|
+
}
|
|
131
|
+
}
|
|
132
|
+
}
|
|
133
|
+
r.consumers = api
|
|
134
|
+
.referenceSitesOf(sym.id)
|
|
135
|
+
.slice(0, 5)
|
|
136
|
+
.map((s) => ({ path: s.node.path ?? s.node.id, ...(s.line ? { line: s.line } : {}) }));
|
|
137
|
+
const alts = pool.slice(1).map((c) => c.path).filter((x) => !!x);
|
|
138
|
+
if (alts.length > 0)
|
|
139
|
+
r.alternates = alts;
|
|
140
|
+
}
|
|
141
|
+
else {
|
|
142
|
+
r.notFound = true;
|
|
143
|
+
}
|
|
144
|
+
}
|
|
145
|
+
// The import line is emitted ONLY from a configured importPath (a clean,
|
|
146
|
+
// copy-pasteable specifier). Without it we show declaration + barrel hint.
|
|
147
|
+
if (r.importPath)
|
|
148
|
+
r.importLine = `import { ${p.symbol} } from '${r.importPath}';`;
|
|
149
|
+
return r;
|
|
150
|
+
});
|
|
151
|
+
if (wantJson) {
|
|
152
|
+
process.stdout.write(asJson({ schema: 'sharkcraft.reuse/v1', intent, graphIndexed: !!api, results }) + '\n');
|
|
153
|
+
return 0;
|
|
154
|
+
}
|
|
155
|
+
process.stdout.write(header(`Reuse: "${intent}"`));
|
|
156
|
+
if (!api) {
|
|
157
|
+
process.stdout.write(' (code graph missing — import path/siblings/consumers limited; run `shrk graph index`)\n');
|
|
158
|
+
}
|
|
159
|
+
let i = 0;
|
|
160
|
+
for (const r of results) {
|
|
161
|
+
i += 1;
|
|
162
|
+
process.stdout.write(`\n${i}. ${r.symbol}\n`);
|
|
163
|
+
if (r.description)
|
|
164
|
+
process.stdout.write(` ${r.description}\n`);
|
|
165
|
+
if (r.notFound) {
|
|
166
|
+
process.stdout.write(' ⚠ symbol not found in the code graph — verify reusePrimitives[].symbol (typo/rename?) or run `shrk graph index`\n');
|
|
167
|
+
}
|
|
168
|
+
if (r.importLine) {
|
|
169
|
+
process.stdout.write(` import: ${r.importLine}\n`);
|
|
170
|
+
}
|
|
171
|
+
else if (r.reExportedVia) {
|
|
172
|
+
process.stdout.write(` re-exported via: ${r.reExportedVia} (set reusePrimitives[].importPath for a copy-paste import)\n`);
|
|
173
|
+
}
|
|
174
|
+
if (r.declaredIn) {
|
|
175
|
+
process.stdout.write(` declared in: ${r.declaredIn}${r.declaredLine ? ':' + r.declaredLine : ''}\n`);
|
|
176
|
+
}
|
|
177
|
+
if (r.alternates && r.alternates.length > 0) {
|
|
178
|
+
process.stdout.write(` ⚠ name also declared in: ${r.alternates.join(', ')}\n`);
|
|
179
|
+
}
|
|
180
|
+
if (r.siblings.length > 0)
|
|
181
|
+
process.stdout.write(` sibling exports: ${r.siblings.join(', ')}\n`);
|
|
182
|
+
if (r.consumers.length > 0) {
|
|
183
|
+
process.stdout.write(' consumers to copy:\n');
|
|
184
|
+
for (const c of r.consumers)
|
|
185
|
+
process.stdout.write(` - ${c.path}${c.line ? ':' + c.line : ''}\n`);
|
|
186
|
+
}
|
|
187
|
+
}
|
|
188
|
+
return 0;
|
|
189
|
+
},
|
|
190
|
+
};
|
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;AA0X/B,wBAAgB,aAAa,IAAI,eAAe,CA8X/C;AAED,wBAAsB,MAAM,CAAC,IAAI,EAAE,SAAS,MAAM,EAAE,GAAG,OAAO,CAAC,MAAM,CAAC,CA2BrE;AAsHD;;;;;;;;;;;GAWG;AACH,wBAAgB,qBAAqB,CAAC,MAAM,EAAE,SAAS,MAAM,EAAE,GAAG,OAAO,CAoDxE"}
|
package/dist/main.js
CHANGED
|
@@ -32,6 +32,8 @@ import { archCommand } from "./commands/arch.command.js";
|
|
|
32
32
|
import { frameworkCommand } from "./commands/framework.command.js";
|
|
33
33
|
import { apiDiffCommand } from "./commands/api-diff.command.js";
|
|
34
34
|
import { gateCommand } from "./commands/gate.command.js";
|
|
35
|
+
import { policyLintCommand } from "./commands/policy-lint.command.js";
|
|
36
|
+
import { reuseCommand } from "./commands/reuse.command.js";
|
|
35
37
|
import { migrateCommand } from "./commands/migrate.command.js";
|
|
36
38
|
import { coverageCommand } from "./commands/coverage.command.js";
|
|
37
39
|
import { statsCommand } from "./commands/stats.command.js";
|
|
@@ -198,6 +200,8 @@ export function buildRegistry() {
|
|
|
198
200
|
registry.register(frameworkCommand);
|
|
199
201
|
registry.register(apiDiffCommand);
|
|
200
202
|
registry.register(gateCommand);
|
|
203
|
+
registry.register(policyLintCommand);
|
|
204
|
+
registry.register(reuseCommand);
|
|
201
205
|
registry.register(migrateCommand);
|
|
202
206
|
registry.register(coverageCommand);
|
|
203
207
|
registry.register(statsCommand);
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"profiles.d.ts","sourceRoot":"","sources":["../../src/surface/profiles.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;AAIH,MAAM,WAAW,eAAe;IAC9B,kEAAkE;IAClE,EAAE,EAAE,MAAM,CAAC;IACX,6DAA6D;IAC7D,WAAW,EAAE,MAAM,CAAC;IACpB,0DAA0D;IAC1D,MAAM,CAAC,EAAE,SAAS,MAAM,EAAE,CAAC;IAC3B;;;;OAIG;IACH,OAAO,CAAC,EAAE,SAAS,MAAM,EAAE,CAAC;IAC5B,uEAAuE;IACvE,MAAM,EAAE,SAAS,GAAG,MAAM,GAAG,OAAO,CAAC;IACrC,yCAAyC;IACzC,IAAI,CAAC,EAAE,MAAM,CAAC;CACf;
|
|
1
|
+
{"version":3,"file":"profiles.d.ts","sourceRoot":"","sources":["../../src/surface/profiles.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;AAIH,MAAM,WAAW,eAAe;IAC9B,kEAAkE;IAClE,EAAE,EAAE,MAAM,CAAC;IACX,6DAA6D;IAC7D,WAAW,EAAE,MAAM,CAAC;IACpB,0DAA0D;IAC1D,MAAM,CAAC,EAAE,SAAS,MAAM,EAAE,CAAC;IAC3B;;;;OAIG;IACH,OAAO,CAAC,EAAE,SAAS,MAAM,EAAE,CAAC;IAC5B,uEAAuE;IACvE,MAAM,EAAE,SAAS,GAAG,MAAM,GAAG,OAAO,CAAC;IACrC,yCAAyC;IACzC,IAAI,CAAC,EAAE,MAAM,CAAC;CACf;AAkLD,oCAAoC;AACpC,eAAO,MAAM,gBAAgB,EAAE,SAAS,eAAe,EAOrD,CAAC;AAEH,gEAAgE;AAChE,wBAAgB,aAAa,CAC3B,YAAY,GAAE,SAAS,eAAe,EAAO,GAC5C,GAAG,CAAC,MAAM,EAAE,eAAe,CAAC,CAQ9B;AAED,6DAA6D;AAC7D,wBAAgB,UAAU,CACxB,EAAE,EAAE,MAAM,EACV,YAAY,GAAE,SAAS,eAAe,EAAO,GAC5C,eAAe,GAAG,SAAS,CAE7B"}
|
package/dist/surface/profiles.js
CHANGED
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.22",
|
|
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.22",
|
|
51
|
+
"@shrkcrft/compress": "^0.1.0-alpha.22",
|
|
52
|
+
"@shrkcrft/config": "^0.1.0-alpha.22",
|
|
53
|
+
"@shrkcrft/workspace": "^0.1.0-alpha.22",
|
|
54
|
+
"@shrkcrft/knowledge": "^0.1.0-alpha.22",
|
|
55
|
+
"@shrkcrft/context": "^0.1.0-alpha.22",
|
|
56
|
+
"@shrkcrft/rules": "^0.1.0-alpha.22",
|
|
57
|
+
"@shrkcrft/paths": "^0.1.0-alpha.22",
|
|
58
|
+
"@shrkcrft/templates": "^0.1.0-alpha.22",
|
|
59
|
+
"@shrkcrft/plugin-api": "^0.1.0-alpha.22",
|
|
60
|
+
"@shrkcrft/dashboard": "^0.1.0-alpha.22",
|
|
61
|
+
"@shrkcrft/dashboard-api": "^0.1.0-alpha.22",
|
|
62
|
+
"@shrkcrft/pipelines": "^0.1.0-alpha.22",
|
|
63
|
+
"@shrkcrft/presets": "^0.1.0-alpha.22",
|
|
64
|
+
"@shrkcrft/boundaries": "^0.1.0-alpha.22",
|
|
65
|
+
"@shrkcrft/graph": "^0.1.0-alpha.22",
|
|
66
|
+
"@shrkcrft/rule-graph": "^0.1.0-alpha.22",
|
|
67
|
+
"@shrkcrft/structural-search": "^0.1.0-alpha.22",
|
|
68
|
+
"@shrkcrft/impact-engine": "^0.1.0-alpha.22",
|
|
69
|
+
"@shrkcrft/context-planner": "^0.1.0-alpha.22",
|
|
70
|
+
"@shrkcrft/architecture-guard": "^0.1.0-alpha.22",
|
|
71
|
+
"@shrkcrft/framework-scanners": "^0.1.0-alpha.22",
|
|
72
|
+
"@shrkcrft/api-surface-diff": "^0.1.0-alpha.22",
|
|
73
|
+
"@shrkcrft/quality-gates": "^0.1.0-alpha.22",
|
|
74
|
+
"@shrkcrft/migrate": "^0.1.0-alpha.22",
|
|
75
|
+
"@shrkcrft/generator": "^0.1.0-alpha.22",
|
|
76
|
+
"@shrkcrft/importer": "^0.1.0-alpha.22",
|
|
77
|
+
"@shrkcrft/inspector": "^0.1.0-alpha.22",
|
|
78
|
+
"@shrkcrft/ai": "^0.1.0-alpha.22",
|
|
79
|
+
"@shrkcrft/embeddings": "^0.1.0-alpha.22",
|
|
80
|
+
"@shrkcrft/shared": "^0.1.0-alpha.22",
|
|
81
|
+
"@shrkcrft/mcp-server": "^0.1.0-alpha.22",
|
|
82
82
|
"@huggingface/transformers": "^3.7.5"
|
|
83
83
|
},
|
|
84
84
|
"publishConfig": {
|