@shrkcrft/cli 0.1.0-alpha.1 → 0.1.0-alpha.11

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.
Files changed (120) hide show
  1. package/README.md +1 -1
  2. package/dist/commands/api-diff.command.d.ts +11 -0
  3. package/dist/commands/api-diff.command.d.ts.map +1 -0
  4. package/dist/commands/api-diff.command.js +116 -0
  5. package/dist/commands/arch.command.d.ts +9 -0
  6. package/dist/commands/arch.command.d.ts.map +1 -0
  7. package/dist/commands/arch.command.js +186 -0
  8. package/dist/commands/boundaries.command.d.ts.map +1 -1
  9. package/dist/commands/boundaries.command.js +0 -12
  10. package/dist/commands/check.command.d.ts.map +1 -1
  11. package/dist/commands/check.command.js +20 -30
  12. package/dist/commands/code-intel.command.d.ts +18 -0
  13. package/dist/commands/code-intel.command.d.ts.map +1 -0
  14. package/dist/commands/code-intel.command.js +146 -0
  15. package/dist/commands/command-catalog.d.ts +7 -3
  16. package/dist/commands/command-catalog.d.ts.map +1 -1
  17. package/dist/commands/command-catalog.js +201 -47
  18. package/dist/commands/commands.command.d.ts.map +1 -1
  19. package/dist/commands/commands.command.js +4 -4
  20. package/dist/commands/completion.command.d.ts +10 -0
  21. package/dist/commands/completion.command.d.ts.map +1 -0
  22. package/dist/commands/completion.command.js +121 -0
  23. package/dist/commands/constructs.command.d.ts.map +1 -1
  24. package/dist/commands/constructs.command.js +5 -22
  25. package/dist/commands/context.command.d.ts.map +1 -1
  26. package/dist/commands/context.command.js +89 -0
  27. package/dist/commands/diff-check.command.d.ts +30 -0
  28. package/dist/commands/diff-check.command.d.ts.map +1 -0
  29. package/dist/commands/diff-check.command.js +210 -0
  30. package/dist/commands/doctor.command.d.ts.map +1 -1
  31. package/dist/commands/doctor.command.js +42 -9
  32. package/dist/commands/export.command.d.ts.map +1 -1
  33. package/dist/commands/export.command.js +76 -3
  34. package/dist/commands/framework.command.d.ts +12 -0
  35. package/dist/commands/framework.command.d.ts.map +1 -0
  36. package/dist/commands/framework.command.js +180 -0
  37. package/dist/commands/gate.command.d.ts +15 -0
  38. package/dist/commands/gate.command.d.ts.map +1 -0
  39. package/dist/commands/gate.command.js +296 -0
  40. package/dist/commands/graph-code-subverbs.d.ts +11 -0
  41. package/dist/commands/graph-code-subverbs.d.ts.map +1 -0
  42. package/dist/commands/graph-code-subverbs.js +818 -0
  43. package/dist/commands/graph.command.d.ts.map +1 -1
  44. package/dist/commands/graph.command.js +22 -0
  45. package/dist/commands/help.command.d.ts +4 -3
  46. package/dist/commands/help.command.d.ts.map +1 -1
  47. package/dist/commands/help.command.js +77 -21
  48. package/dist/commands/helper.command.js +1 -1
  49. package/dist/commands/impact.command.d.ts.map +1 -1
  50. package/dist/commands/impact.command.js +170 -1
  51. package/dist/commands/import.command.d.ts.map +1 -1
  52. package/dist/commands/import.command.js +121 -5
  53. package/dist/commands/init.command.d.ts.map +1 -1
  54. package/dist/commands/init.command.js +184 -16
  55. package/dist/commands/mcp.command.d.ts.map +1 -1
  56. package/dist/commands/mcp.command.js +2 -131
  57. package/dist/commands/migrate.command.d.ts +13 -0
  58. package/dist/commands/migrate.command.d.ts.map +1 -0
  59. package/dist/commands/migrate.command.js +152 -0
  60. package/dist/commands/onboard.command.d.ts.map +1 -1
  61. package/dist/commands/onboard.command.js +3 -15
  62. package/dist/commands/packs-new.d.ts +1 -1
  63. package/dist/commands/packs-new.d.ts.map +1 -1
  64. package/dist/commands/packs-new.js +5 -36
  65. package/dist/commands/packs.command.d.ts.map +1 -1
  66. package/dist/commands/packs.command.js +3 -17
  67. package/dist/commands/plan-context.command.d.ts +11 -0
  68. package/dist/commands/plan-context.command.d.ts.map +1 -0
  69. package/dist/commands/plan-context.command.js +77 -0
  70. package/dist/commands/profiles.command.js +4 -4
  71. package/dist/commands/release.command.js +13 -13
  72. package/dist/commands/review.command.d.ts.map +1 -1
  73. package/dist/commands/review.command.js +2 -28
  74. package/dist/commands/rule-graph-subverbs.d.ts +3 -0
  75. package/dist/commands/rule-graph-subverbs.d.ts.map +1 -0
  76. package/dist/commands/rule-graph-subverbs.js +132 -0
  77. package/dist/commands/search-structural.command.d.ts +18 -0
  78. package/dist/commands/search-structural.command.d.ts.map +1 -0
  79. package/dist/commands/search-structural.command.js +376 -0
  80. package/dist/commands/search.command.js +1 -1
  81. package/dist/commands/task-context.command.js +0 -16
  82. package/dist/commands/task.command.d.ts.map +1 -1
  83. package/dist/commands/task.command.js +8 -2
  84. package/dist/dashboard/code-intelligence-data.d.ts +33 -0
  85. package/dist/dashboard/code-intelligence-data.d.ts.map +1 -0
  86. package/dist/dashboard/code-intelligence-data.js +307 -0
  87. package/dist/dashboard/dashboard-api-server.d.ts.map +1 -1
  88. package/dist/dashboard/dashboard-api-server.js +162 -1
  89. package/dist/export/claude-commands-export.d.ts +60 -0
  90. package/dist/export/claude-commands-export.d.ts.map +1 -0
  91. package/dist/export/claude-commands-export.js +276 -0
  92. package/dist/export/export-formats.d.ts +1 -1
  93. package/dist/export/export-formats.d.ts.map +1 -1
  94. package/dist/export/export-formats.js +139 -12
  95. package/dist/init/init-templates.d.ts.map +1 -1
  96. package/dist/init/init-templates.js +133 -113
  97. package/dist/init/paths-advisory.d.ts +20 -0
  98. package/dist/init/paths-advisory.d.ts.map +1 -0
  99. package/dist/init/paths-advisory.js +88 -0
  100. package/dist/main.d.ts +1 -1
  101. package/dist/main.d.ts.map +1 -1
  102. package/dist/main.js +137 -46
  103. package/dist/output/failure-hints.d.ts +1 -9
  104. package/dist/output/failure-hints.d.ts.map +1 -1
  105. package/dist/output/failure-hints.js +2 -8
  106. package/dist/output/watch-loop.d.ts +9 -1
  107. package/dist/output/watch-loop.d.ts.map +1 -1
  108. package/dist/output/watch-loop.js +13 -3
  109. package/dist/schemas/json-schemas.d.ts +36 -36
  110. package/dist/schemas/json-schemas.js +36 -36
  111. package/dist/surface/about.d.ts.map +1 -1
  112. package/dist/surface/about.js +37 -15
  113. package/dist/surface/no-args-landing.d.ts.map +1 -1
  114. package/dist/surface/no-args-landing.js +9 -13
  115. package/dist/surface/surface-config-writer.d.ts.map +1 -1
  116. package/dist/surface/surface-config-writer.js +23 -11
  117. package/package.json +37 -25
  118. package/dist/commands/plugin.command.d.ts +0 -11
  119. package/dist/commands/plugin.command.d.ts.map +0 -1
  120. package/dist/commands/plugin.command.js +0 -394
package/README.md CHANGED
@@ -2,7 +2,7 @@
2
2
 
3
3
  SharkCraft CLI (`shrk`): structured project intelligence for AI coding agents.
4
4
 
5
- Part of [SharkCraft](https://github.com/sharkcraft/sharkcraft) — a deterministic, local-first toolkit that gives AI coding agents durable project context. See the main repo for documentation, examples, and the `shrk` CLI.
5
+ Part of [SharkCraft](https://github.com/shrkcrft/sharkcraft) — a deterministic, local-first toolkit that gives AI coding agents durable project context. See the main repo for documentation, examples, and the `shrk` CLI.
6
6
 
7
7
  ## Install
8
8
 
@@ -0,0 +1,11 @@
1
+ import { type ICommandHandler } from '../command-registry.js';
2
+ /**
3
+ * `shrk api-diff` — compare the current code-graph's public-API
4
+ * surface to a saved baseline (or another snapshot file).
5
+ *
6
+ * Sub-verbs:
7
+ * - shrk api-diff capture --output <path> write the current surface to disk
8
+ * - shrk api-diff <baseline.json> diff current vs baseline
9
+ */
10
+ export declare const apiDiffCommand: ICommandHandler;
11
+ //# sourceMappingURL=api-diff.command.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"api-diff.command.d.ts","sourceRoot":"","sources":["../../src/commands/api-diff.command.ts"],"names":[],"mappings":"AASA,OAAO,EAKL,KAAK,eAAe,EAErB,MAAM,wBAAwB,CAAC;AAGhC;;;;;;;GAOG;AACH,eAAO,MAAM,cAAc,EAAE,eAoB5B,CAAC"}
@@ -0,0 +1,116 @@
1
+ import { readFileSync, writeFileSync, mkdirSync } from 'node:fs';
2
+ import * as nodePath from 'node:path';
3
+ import { diffApiSurfaces, extractApiSurface, extractApiSurfaceWithProgram, } from '@shrkcrft/api-surface-diff';
4
+ import { GraphStore } from '@shrkcrft/graph';
5
+ import { flagBool, flagList, flagString, resolveCwd, } from "../command-registry.js";
6
+ import { asJson, header, kv } from "../output/format-output.js";
7
+ /**
8
+ * `shrk api-diff` — compare the current code-graph's public-API
9
+ * surface to a saved baseline (or another snapshot file).
10
+ *
11
+ * Sub-verbs:
12
+ * - shrk api-diff capture --output <path> write the current surface to disk
13
+ * - shrk api-diff <baseline.json> diff current vs baseline
14
+ */
15
+ export const apiDiffCommand = {
16
+ name: 'api-diff',
17
+ description: 'Compare the current public API surface to a saved baseline. Reports added / removed / kind-changed / moved symbols, with breaking-change severity.',
18
+ usage: 'shrk api-diff capture --output <path> [--packages a,b] [--with-signatures] | shrk api-diff <baseline.json> [--packages a,b] [--with-signatures] [--json] [--fail-on-breaking]',
19
+ async run(args) {
20
+ const cwd = resolveCwd(args);
21
+ const wantJson = flagBool(args, 'json');
22
+ const sub = args.positional[0];
23
+ if (!sub) {
24
+ process.stderr.write(this.usage + '\n');
25
+ return 2;
26
+ }
27
+ if (sub === 'capture') {
28
+ return runCapture(args, cwd, wantJson);
29
+ }
30
+ return runDiff(args, cwd, wantJson, sub);
31
+ },
32
+ };
33
+ async function runCapture(args, cwd, wantJson) {
34
+ const outputFlag = flagString(args, 'output');
35
+ if (!outputFlag) {
36
+ process.stderr.write('shrk api-diff capture requires --output <path>\n');
37
+ return 2;
38
+ }
39
+ const surface = readSurfaceFromCwd(cwd, args);
40
+ if (!surface)
41
+ return 1;
42
+ const abs = nodePath.isAbsolute(outputFlag) ? outputFlag : nodePath.resolve(cwd, outputFlag);
43
+ mkdirSync(nodePath.dirname(abs), { recursive: true });
44
+ writeFileSync(abs, JSON.stringify(surface, null, 2), 'utf8');
45
+ if (wantJson) {
46
+ process.stdout.write(asJson({ ok: true, wrote: abs, total: surface.total }) + '\n');
47
+ return 0;
48
+ }
49
+ process.stdout.write(header('API surface capture'));
50
+ process.stdout.write(kv('wrote', abs) + '\n');
51
+ process.stdout.write(kv('symbols', String(surface.total)) + '\n');
52
+ return 0;
53
+ }
54
+ async function runDiff(args, cwd, wantJson, baselinePath) {
55
+ const baselineAbs = nodePath.isAbsolute(baselinePath)
56
+ ? baselinePath
57
+ : nodePath.resolve(cwd, baselinePath);
58
+ let baseline;
59
+ try {
60
+ baseline = JSON.parse(readFileSync(baselineAbs, 'utf8'));
61
+ }
62
+ catch (e) {
63
+ process.stderr.write(`Baseline read error: ${e.message}\n`);
64
+ return 2;
65
+ }
66
+ const current = readSurfaceFromCwd(cwd, args);
67
+ if (!current)
68
+ return 1;
69
+ const diff = diffApiSurfaces(baseline, current);
70
+ const failOnBreaking = flagBool(args, 'fail-on-breaking');
71
+ if (wantJson) {
72
+ process.stdout.write(asJson(diff) + '\n');
73
+ return failOnBreaking && diff.breakingCount > 0 ? 1 : 0;
74
+ }
75
+ process.stdout.write(header('API surface diff'));
76
+ process.stdout.write(kv('schema', diff.schema) + '\n');
77
+ process.stdout.write(kv('baseline symbols', String(diff.baselineTotal)) + '\n');
78
+ process.stdout.write(kv('current symbols', String(diff.currentTotal)) + '\n');
79
+ process.stdout.write(kv('added', String(diff.added)) + '\n');
80
+ process.stdout.write(kv('removed', String(diff.removed)) + '\n');
81
+ process.stdout.write(kv('changed', String(diff.changed)) + '\n');
82
+ process.stdout.write(kv('breaking', String(diff.breakingCount)) + '\n');
83
+ if (diff.entries.length === 0) {
84
+ process.stdout.write('\nNo changes.\n');
85
+ return 0;
86
+ }
87
+ process.stdout.write('\nEntries:\n');
88
+ for (const e of diff.entries.slice(0, 80)) {
89
+ process.stdout.write(` [${e.severity}] [${e.kind}] ${e.message}\n`);
90
+ }
91
+ if (diff.entries.length > 80) {
92
+ process.stdout.write(` … (${diff.entries.length - 80} more)\n`);
93
+ }
94
+ return failOnBreaking && diff.breakingCount > 0 ? 1 : 0;
95
+ }
96
+ function readSurfaceFromCwd(cwd, args) {
97
+ const packages = flagList(args, 'packages');
98
+ const withSignatures = flagBool(args, 'with-signatures');
99
+ if (withSignatures) {
100
+ const result = extractApiSurfaceWithProgram({
101
+ projectRoot: cwd,
102
+ ...(packages.length > 0 ? { packageFilter: packages } : {}),
103
+ });
104
+ for (const d of result.diagnostics.slice(0, 5)) {
105
+ process.stderr.write(`! ${d}\n`);
106
+ }
107
+ return result.surface;
108
+ }
109
+ const store = new GraphStore(cwd);
110
+ if (!store.exists()) {
111
+ process.stderr.write("Code-graph store missing. Run 'shrk graph index' first.\n");
112
+ return undefined;
113
+ }
114
+ const snap = store.loadSnapshot();
115
+ return extractApiSurface(snap, { ...(packages.length > 0 ? { packageFilter: packages } : {}) });
116
+ }
@@ -0,0 +1,9 @@
1
+ import { type ICommandHandler } from '../command-registry.js';
2
+ /**
3
+ * `shrk arch` — semantic architecture checks on top of the code graph.
4
+ * Sub-verbs:
5
+ * - shrk arch check run all enabled checks (auto-loads sharkcraft/arch.ts)
6
+ * - shrk arch check --contract X point at an explicit contract file
7
+ */
8
+ export declare const archCommand: ICommandHandler;
9
+ //# sourceMappingURL=arch.command.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"arch.command.d.ts","sourceRoot":"","sources":["../../src/commands/arch.command.ts"],"names":[],"mappings":"AASA,OAAO,EAIL,KAAK,eAAe,EAErB,MAAM,wBAAwB,CAAC;AAIhC;;;;;GAKG;AACH,eAAO,MAAM,WAAW,EAAE,eAoBzB,CAAC"}
@@ -0,0 +1,186 @@
1
+ import { existsSync } from 'node:fs';
2
+ import * as nodePath from 'node:path';
3
+ import { ArchReportStore, diffSnapshots, runArchCheck, } from '@shrkcrft/architecture-guard';
4
+ import { flagBool, flagString, resolveCwd, } from "../command-registry.js";
5
+ import { safeImport } from '@shrkcrft/core';
6
+ import { asJson, header, kv } from "../output/format-output.js";
7
+ /**
8
+ * `shrk arch` — semantic architecture checks on top of the code graph.
9
+ * Sub-verbs:
10
+ * - shrk arch check run all enabled checks (auto-loads sharkcraft/arch.ts)
11
+ * - shrk arch check --contract X point at an explicit contract file
12
+ */
13
+ export const archCommand = {
14
+ name: 'arch',
15
+ description: 'Architecture-guard checks: public-API misuse, barrel risks, cycle severity, project-specific contracts (sharkcraft/arch.ts auto-loaded). `shrk arch baseline <write|show|clear>` to gate doctor on a frozen baseline.',
16
+ usage: 'shrk arch check [--contract <path>] [--no-cycles] [--no-barrels] [--no-public-api] [--no-persist] [--json]\n shrk arch baseline <write|show|clear> [--contract <path>] [--json]',
17
+ async run(args) {
18
+ const sub = args.positional[0];
19
+ if (sub === 'baseline') {
20
+ return runArchBaseline({
21
+ ...args,
22
+ positional: args.positional.slice(1),
23
+ });
24
+ }
25
+ if (sub !== 'check') {
26
+ process.stderr.write(this.usage + '\n');
27
+ return 2;
28
+ }
29
+ return runArchCheckCommand(args);
30
+ },
31
+ };
32
+ async function runArchCheckCommand(args) {
33
+ const cwd = resolveCwd(args);
34
+ const wantJson = flagBool(args, 'json');
35
+ const noCycles = flagBool(args, 'no-cycles');
36
+ const noBarrels = flagBool(args, 'no-barrels');
37
+ const noPublicApi = flagBool(args, 'no-public-api');
38
+ const noPersist = flagBool(args, 'no-persist');
39
+ const contractPath = flagString(args, 'contract');
40
+ const contract = await loadContract(cwd, contractPath);
41
+ const report = runArchCheck({
42
+ projectRoot: cwd,
43
+ ...(contract ? { contract } : {}),
44
+ enable: {
45
+ publicApi: !noPublicApi,
46
+ barrels: !noBarrels,
47
+ cycles: !noCycles,
48
+ contract: !!contract,
49
+ },
50
+ });
51
+ // Persist a compact snapshot so `shrk doctor` can compare against
52
+ // baseline without re-running the full check. `--no-persist` opts out
53
+ // (useful when scripting against many trees).
54
+ if (!noPersist) {
55
+ try {
56
+ new ArchReportStore(cwd).writeLast(report);
57
+ }
58
+ catch {
59
+ // best-effort
60
+ }
61
+ }
62
+ if (wantJson) {
63
+ process.stdout.write(asJson(report) + '\n');
64
+ return report.countsBySeverity.error > 0 ? 1 : 0;
65
+ }
66
+ printArchReport(report);
67
+ return report.countsBySeverity.error > 0 ? 1 : 0;
68
+ }
69
+ async function runArchBaseline(args) {
70
+ const cwd = resolveCwd(args);
71
+ const verb = args.positional[0] ?? 'show';
72
+ const store = new ArchReportStore(cwd);
73
+ const wantJson = flagBool(args, 'json');
74
+ if (verb === 'write') {
75
+ const contractPath = flagString(args, 'contract');
76
+ const contract = await loadContract(cwd, contractPath);
77
+ const report = runArchCheck({
78
+ projectRoot: cwd,
79
+ ...(contract ? { contract } : {}),
80
+ });
81
+ const snap = store.writeBaseline(report);
82
+ // Update last.json too so doctor's first delta read is meaningful.
83
+ store.writeLast(report);
84
+ if (wantJson) {
85
+ process.stdout.write(asJson({ wrote: store.baselinePath, baseline: snap }) + '\n');
86
+ return 0;
87
+ }
88
+ process.stdout.write(`Architecture baseline written → ${store.baselinePath}\n`);
89
+ process.stdout.write(` ${snap.violationIds.length} violations (` +
90
+ `${snap.countsBySeverity.error} error, ` +
91
+ `${snap.countsBySeverity.warning} warning, ` +
92
+ `${snap.countsBySeverity.info} info) ` +
93
+ `across ${snap.filesAnalyzed} files.\n`);
94
+ return 0;
95
+ }
96
+ if (verb === 'show') {
97
+ const baseline = store.readBaseline();
98
+ if (!baseline) {
99
+ const msg = `No baseline at ${store.baselinePath}. Run \`shrk arch baseline write\` to freeze one.\n`;
100
+ if (wantJson) {
101
+ process.stdout.write(asJson({ baseline: null, path: store.baselinePath }) + '\n');
102
+ return 1;
103
+ }
104
+ process.stdout.write(msg);
105
+ return 1;
106
+ }
107
+ if (wantJson) {
108
+ process.stdout.write(asJson({ path: store.baselinePath, baseline }) + '\n');
109
+ return 0;
110
+ }
111
+ process.stdout.write(header('Architecture baseline'));
112
+ process.stdout.write(kv('path', store.baselinePath) + '\n');
113
+ process.stdout.write(kv('generated at', baseline.generatedAt) + '\n');
114
+ process.stdout.write(kv('files analyzed', String(baseline.filesAnalyzed)) + '\n');
115
+ process.stdout.write(kv('counts', `${baseline.countsBySeverity.error} error, ${baseline.countsBySeverity.warning} warning, ${baseline.countsBySeverity.info} info`) + '\n');
116
+ const last = store.readLast();
117
+ if (last) {
118
+ const delta = diffSnapshots(baseline, last);
119
+ process.stdout.write('\nDelta (last − baseline): ' +
120
+ `${delta.newViolationIds.length} new, ${delta.fixedViolationIds.length} fixed ` +
121
+ `(error ${delta.errorDelta >= 0 ? '+' : ''}${delta.errorDelta}, warning ${delta.warningDelta >= 0 ? '+' : ''}${delta.warningDelta})\n`);
122
+ }
123
+ else {
124
+ process.stdout.write('\n(no `last.json` yet — run `shrk arch check`.)\n');
125
+ }
126
+ return 0;
127
+ }
128
+ if (verb === 'clear') {
129
+ const removed = store.clearBaseline();
130
+ if (wantJson) {
131
+ process.stdout.write(asJson({ removed, path: store.baselinePath }) + '\n');
132
+ return 0;
133
+ }
134
+ process.stdout.write(removed ? `Baseline removed: ${store.baselinePath}\n` : 'No baseline to remove.\n');
135
+ return 0;
136
+ }
137
+ process.stderr.write('Usage: shrk arch baseline <write|show|clear> [--json]\n');
138
+ return 2;
139
+ }
140
+ function printArchReport(report) {
141
+ process.stdout.write(header('Architecture guard'));
142
+ process.stdout.write(kv('schema', report.schema) + '\n');
143
+ process.stdout.write(kv('files analyzed', String(report.filesAnalyzed)) + '\n');
144
+ process.stdout.write(kv('errors', String(report.countsBySeverity.error)) + '\n');
145
+ process.stdout.write(kv('warnings', String(report.countsBySeverity.warning)) + '\n');
146
+ if (report.violations.length === 0) {
147
+ process.stdout.write('\nNo violations.\n');
148
+ }
149
+ else {
150
+ process.stdout.write('\nViolations:\n');
151
+ for (const v of report.violations.slice(0, 80)) {
152
+ const lineSuffix = v.line ? `:${v.line}` : '';
153
+ process.stdout.write(` [${v.severity}] [${v.kind}] ${v.file}${lineSuffix}\n ${v.message}\n`);
154
+ if (v.suggestedFix)
155
+ process.stdout.write(` → ${v.suggestedFix}\n`);
156
+ }
157
+ if (report.violations.length > 80) {
158
+ process.stdout.write(` … (${report.violations.length - 80} more)\n`);
159
+ }
160
+ }
161
+ for (const d of report.diagnostics.slice(0, 5))
162
+ process.stdout.write(`! ${d}\n`);
163
+ }
164
+ async function loadContract(cwd, explicit) {
165
+ const candidate = explicit
166
+ ? nodePath.isAbsolute(explicit) ? explicit : nodePath.resolve(cwd, explicit)
167
+ : nodePath.join(cwd, 'sharkcraft', 'arch.ts');
168
+ if (!existsSync(candidate)) {
169
+ if (explicit)
170
+ process.stderr.write(`! contract file not found: ${candidate}\n`);
171
+ return undefined;
172
+ }
173
+ const result = await safeImport(candidate);
174
+ if (!result.ok) {
175
+ process.stderr.write(`! failed to load arch contract: ${result.error.message}\n`);
176
+ return undefined;
177
+ }
178
+ const mod = result.module;
179
+ const exported = mod.default ??
180
+ mod.contract;
181
+ if (!exported) {
182
+ process.stderr.write(`! arch contract module ${candidate} does not export a contract\n`);
183
+ return undefined;
184
+ }
185
+ return exported;
186
+ }
@@ -1 +1 @@
1
- {"version":3,"file":"boundaries.command.d.ts","sourceRoot":"","sources":["../../src/commands/boundaries.command.ts"],"names":[],"mappings":"AAkBA,OAAO,EAAwB,KAAK,eAAe,EAA+B,MAAM,wBAAwB,CAAC;AAGjH,eAAO,MAAM,qBAAqB,EAAE,eAuBnC,CAAC;AAEF,eAAO,MAAM,oBAAoB,EAAE,eAqClC,CAAC;AAEF,eAAO,MAAM,wBAAwB,EAAE,eAmDtC,CAAC;AAEF,eAAO,MAAM,sBAAsB,EAAE,eAyEpC,CAAC;AAsCF,uCAAuC;AACvC,eAAO,MAAM,wBAAwB,EAAE,eAmFtC,CAAC;AAEF,eAAO,MAAM,wBAAwB,EAAE,eA0CtC,CAAC"}
1
+ {"version":3,"file":"boundaries.command.d.ts","sourceRoot":"","sources":["../../src/commands/boundaries.command.ts"],"names":[],"mappings":"AAkBA,OAAO,EAAwB,KAAK,eAAe,EAA+B,MAAM,wBAAwB,CAAC;AAGjH,eAAO,MAAM,qBAAqB,EAAE,eAuBnC,CAAC;AAEF,eAAO,MAAM,oBAAoB,EAAE,eAqClC,CAAC;AAEF,eAAO,MAAM,wBAAwB,EAAE,eAmDtC,CAAC;AAEF,eAAO,MAAM,sBAAsB,EAAE,eAyEpC,CAAC;AAsCF,uCAAuC;AACvC,eAAO,MAAM,wBAAwB,EAAE,eAqEtC,CAAC;AAEF,eAAO,MAAM,wBAAwB,EAAE,eA0CtC,CAAC"}
@@ -218,18 +218,6 @@ export const boundariesEnforceCommand = {
218
218
  const fileList = filesRaw
219
219
  ? filesRaw.split(',').map((s) => s.trim()).filter(Boolean)
220
220
  : [];
221
- if (since) {
222
- const { verifyGitRef } = await import('@shrkcrft/inspector');
223
- const verify = verifyGitRef(cwd, since);
224
- if (!verify.valid) {
225
- process.stderr.write(`error: --since ref "${since}" does not resolve to a commit in this repository.\n` +
226
- (verify.suggestions && verify.suggestions.length > 0
227
- ? `\nDid you mean:\n${verify.suggestions.map((s) => ` --since ${s}`).join('\n')}\n`
228
- : '') +
229
- '\nUse `git branch -a` to list available refs.\n');
230
- return 2;
231
- }
232
- }
233
221
  const wantChangedScope = changedOnly || staged || Boolean(since) || fileList.length > 0;
234
222
  const { filterViolationsToChangedScope } = await import('@shrkcrft/inspector');
235
223
  const filtered = wantChangedScope
@@ -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;AA0kBhC,eAAO,MAAM,YAAY,EAAE,eAmD1B,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;AAikBhC,eAAO,MAAM,YAAY,EAAE,eAmD1B,CAAC"}
@@ -1,8 +1,9 @@
1
- import { buildAiReadinessReport, buildImportHygieneReport, buildPackDoctorReport, ChangedScopeMode, diagnoseActionHints, emitImportHygieneAllowlistDraft, filterViolationsToChangedScope, ImportHygieneFindingKind, inspectSharkcraft, isTodoReason, renderImportHygieneText, resolveChangedFiles, runDoctor, suggestBoundaryFixes, verifyGitRef, } from '@shrkcrft/inspector';
1
+ import { buildAiReadinessReport, buildImportHygieneReport, buildPackDoctorReport, ChangedScopeMode, diagnoseActionHints, emitImportHygieneAllowlistDraft, filterViolationsToChangedScope, ImportHygieneFindingKind, inspectSharkcraft, isTodoReason, renderImportHygieneText, resolveChangedFiles, runDoctor, suggestBoundaryFixes, } from '@shrkcrft/inspector';
2
2
  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 { maybeRunInWatchMode } from "../output/watch-loop.js";
6
7
  import { validateTemplateVariables } from '@shrkcrft/templates';
7
8
  import { FileChangeType, planGeneration } from '@shrkcrft/generator';
8
9
  import { evaluateBoundaries, loadTsconfigPaths, scanImports, summarizeImports, } from '@shrkcrft/boundaries';
@@ -152,13 +153,6 @@ async function checkImports(args) {
152
153
  const cwd = resolveCwd(args);
153
154
  const changedOnly = flagBool(args, 'changed-only');
154
155
  const since = flagString(args, 'since');
155
- if (since) {
156
- const verify = verifyGitRef(cwd, since);
157
- if (!verify.valid) {
158
- process.stderr.write(renderSinceRefError(since, verify.suggestions ?? []));
159
- return 2;
160
- }
161
- }
162
156
  let files;
163
157
  if (changedOnly || since) {
164
158
  const changed = resolveChangedFiles({
@@ -300,13 +294,6 @@ function readChangedScopeOptions(args, cwd) {
300
294
  : [];
301
295
  if (!changedOnly && !staged && !since && files.length === 0)
302
296
  return null;
303
- if (since) {
304
- const verify = verifyGitRef(cwd, since);
305
- if (!verify.valid) {
306
- process.stderr.write(renderSinceRefError(since, verify.suggestions ?? []));
307
- process.exit(2);
308
- }
309
- }
310
297
  const out = { projectRoot: cwd };
311
298
  if (files.length > 0)
312
299
  out.files = files;
@@ -318,20 +305,23 @@ function readChangedScopeOptions(args, cwd) {
318
305
  out.includeWorktree = true;
319
306
  return out;
320
307
  }
321
- function renderSinceRefError(ref, suggestions) {
322
- const lines = [];
323
- lines.push(`error: --since ref "${ref}" does not resolve to a commit in this repository.`);
324
- if (suggestions.length > 0) {
325
- lines.push('');
326
- lines.push('Did you mean:');
327
- for (const s of suggestions)
328
- lines.push(` --since ${s}`);
329
- }
330
- lines.push('');
331
- lines.push('Use `git branch -a` to list available refs, or skip --since to use the working tree.');
332
- return lines.join('\n') + '\n';
333
- }
334
308
  async function checkBoundaries(args) {
309
+ const watchExit = await maybeRunInWatchMode(args, checkBoundariesOnce, {
310
+ defaultPaths: BOUNDARIES_DEFAULT_WATCH_PATHS,
311
+ });
312
+ if (watchExit !== null)
313
+ return watchExit;
314
+ return checkBoundariesOnce(args);
315
+ }
316
+ const BOUNDARIES_DEFAULT_WATCH_PATHS = [
317
+ 'sharkcraft',
318
+ 'packages',
319
+ 'apps',
320
+ 'libs',
321
+ 'src',
322
+ 'tools',
323
+ ];
324
+ async function checkBoundariesOnce(args) {
335
325
  const cwd = resolveCwd(args);
336
326
  const inspection = await inspectSharkcraft({ cwd });
337
327
  const rules = inspection.boundaryRegistry.list();
@@ -531,8 +521,8 @@ async function checkBoundaries(args) {
531
521
  // ────────────────────────────────────────────────────────────────────────
532
522
  export const checkCommand = {
533
523
  name: 'check',
534
- description: 'Run SharkCraft-level validation across knowledge / rules / templates / pipelines / packs / action hints / doctor.',
535
- usage: 'shrk [--cwd <dir>] check [packs|pipelines|knowledge|generation] [--strict] [--min-score <0-100>] [--json]',
524
+ 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]]',
536
526
  async run(args) {
537
527
  const sub = args.positional[0];
538
528
  if (sub === 'generation')
@@ -0,0 +1,18 @@
1
+ import { type ICommandHandler } from '../command-registry.js';
2
+ /**
3
+ * `shrk code-intel` — one-shot view of the 14 code-intelligence
4
+ * doctor checks. Independent of `shrk doctor` so callers (agents,
5
+ * inner-loop scripts, the dashboard) can pull just this section
6
+ * without parsing through unrelated config / knowledge findings.
7
+ *
8
+ * Output modes:
9
+ * - text (default): grouped by severity, one line per finding.
10
+ * - --json: machine-readable, including the full check list.
11
+ * - --markdown: PR-comment-ready rendering.
12
+ *
13
+ * Filters:
14
+ * - --only ok,warning,error,info — restrict severities.
15
+ * - --check <id> — show only one check id.
16
+ */
17
+ export declare const codeIntelCommand: ICommandHandler;
18
+ //# sourceMappingURL=code-intel.command.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"code-intel.command.d.ts","sourceRoot":"","sources":["../../src/commands/code-intel.command.ts"],"names":[],"mappings":"AAKA,OAAO,EAIL,KAAK,eAAe,EAErB,MAAM,wBAAwB,CAAC;AAGhC;;;;;;;;;;;;;;GAcG;AACH,eAAO,MAAM,gBAAgB,EAAE,eAuE9B,CAAC"}
@@ -0,0 +1,146 @@
1
+ import { buildCodeIntelligenceChecks, DoctorSeverity, } from '@shrkcrft/inspector';
2
+ import { flagBool, flagString, resolveCwd, } from "../command-registry.js";
3
+ import { asJson, header, kv } from "../output/format-output.js";
4
+ /**
5
+ * `shrk code-intel` — one-shot view of the 14 code-intelligence
6
+ * doctor checks. Independent of `shrk doctor` so callers (agents,
7
+ * inner-loop scripts, the dashboard) can pull just this section
8
+ * without parsing through unrelated config / knowledge findings.
9
+ *
10
+ * Output modes:
11
+ * - text (default): grouped by severity, one line per finding.
12
+ * - --json: machine-readable, including the full check list.
13
+ * - --markdown: PR-comment-ready rendering.
14
+ *
15
+ * Filters:
16
+ * - --only ok,warning,error,info — restrict severities.
17
+ * - --check <id> — show only one check id.
18
+ */
19
+ export const codeIntelCommand = {
20
+ name: 'code-intel',
21
+ description: 'One-shot view of code-intelligence doctor checks (graph, rule-graph, api-surface, quality-gate, migrations, architecture, impact, framework, structural-search, context-planner). Read-only.',
22
+ usage: 'shrk [--cwd <dir>] code-intel [--json] [--markdown] [--only ok,warning,error,info] [--check <id>] [--stale-days N]',
23
+ async run(args) {
24
+ const cwd = resolveCwd(args);
25
+ const wantJson = flagBool(args, 'json');
26
+ const wantMarkdown = flagBool(args, 'markdown');
27
+ const onlyRaw = flagString(args, 'only');
28
+ const checkId = flagString(args, 'check');
29
+ const staleDaysRaw = flagString(args, 'stale-days');
30
+ const staleDays = staleDaysRaw ? Number.parseInt(staleDaysRaw, 10) : undefined;
31
+ const options = {};
32
+ if (typeof staleDays === 'number' && Number.isFinite(staleDays) && staleDays > 0) {
33
+ options.staleThresholdDays = staleDays;
34
+ }
35
+ let checks = buildCodeIntelligenceChecks(cwd, options);
36
+ if (checkId) {
37
+ checks = checks.filter((c) => c.id === checkId);
38
+ }
39
+ if (onlyRaw) {
40
+ const allowed = new Set(onlyRaw
41
+ .split(',')
42
+ .map((s) => s.trim().toLowerCase())
43
+ .filter((s) => s.length > 0));
44
+ checks = checks.filter((c) => allowed.has(severityKey(c.severity)));
45
+ }
46
+ const summary = summarize(checks);
47
+ if (wantJson) {
48
+ process.stdout.write(asJson({
49
+ schema: 'sharkcraft.code-intelligence-state/v1',
50
+ totalChecks: checks.length,
51
+ summary,
52
+ checks,
53
+ }) + '\n');
54
+ return exitCode(summary);
55
+ }
56
+ if (wantMarkdown) {
57
+ process.stdout.write(renderMarkdown(checks, summary));
58
+ return exitCode(summary);
59
+ }
60
+ process.stdout.write(header('Code-intelligence state'));
61
+ process.stdout.write(kv('summary', `ok=${summary.ok} info=${summary.info} warnings=${summary.warnings} errors=${summary.errors}`) + '\n');
62
+ if (checks.length === 0) {
63
+ process.stdout.write('\nNo code-intelligence state on disk yet — opt in by running `shrk graph index`.\n');
64
+ return 0;
65
+ }
66
+ process.stdout.write('\n');
67
+ for (const c of checks) {
68
+ const icon = severityIcon(c.severity);
69
+ const advisory = c.advisory ? ' (advisory)' : '';
70
+ process.stdout.write(`${icon} ${c.id}${advisory}\n`);
71
+ process.stdout.write(` ${c.title}\n`);
72
+ process.stdout.write(` ${c.message}\n`);
73
+ if (c.fix)
74
+ process.stdout.write(` → ${c.fix}\n`);
75
+ if (c.whyThisMatters)
76
+ process.stdout.write(` why: ${c.whyThisMatters}\n`);
77
+ process.stdout.write('\n');
78
+ }
79
+ return exitCode(summary);
80
+ },
81
+ };
82
+ function severityKey(severity) {
83
+ return severity;
84
+ }
85
+ function severityIcon(severity) {
86
+ switch (severity) {
87
+ case DoctorSeverity.Ok:
88
+ return '✓';
89
+ case DoctorSeverity.Info:
90
+ return 'ℹ';
91
+ case DoctorSeverity.Warning:
92
+ return '⚠';
93
+ case DoctorSeverity.Error:
94
+ return '✗';
95
+ }
96
+ }
97
+ function summarize(checks) {
98
+ const s = { ok: 0, info: 0, warnings: 0, errors: 0 };
99
+ for (const c of checks) {
100
+ if (c.severity === DoctorSeverity.Ok)
101
+ s.ok += 1;
102
+ else if (c.severity === DoctorSeverity.Info)
103
+ s.info += 1;
104
+ else if (c.severity === DoctorSeverity.Warning)
105
+ s.warnings += 1;
106
+ else if (c.severity === DoctorSeverity.Error)
107
+ s.errors += 1;
108
+ }
109
+ return s;
110
+ }
111
+ function exitCode(summary) {
112
+ // Exit 1 if any non-advisory warning or error remains. Advisory
113
+ // warnings are reported but never fail the command — they're hints,
114
+ // not blockers (same contract as `shrk doctor`).
115
+ return summary.errors > 0 ? 1 : 0;
116
+ }
117
+ function renderMarkdown(checks, summary) {
118
+ const lines = [];
119
+ lines.push('# SharkCraft code-intelligence state');
120
+ lines.push('');
121
+ lines.push('| ok | info | warnings | errors |');
122
+ lines.push('|---|---|---|---|');
123
+ lines.push(`| ${summary.ok} | ${summary.info} | ${summary.warnings} | ${summary.errors} |`);
124
+ lines.push('');
125
+ if (checks.length === 0) {
126
+ lines.push('_(no code-intelligence state on disk yet)_');
127
+ return lines.join('\n') + '\n';
128
+ }
129
+ for (const c of checks) {
130
+ const icon = severityIcon(c.severity);
131
+ const advisory = c.advisory ? ' _(advisory)_' : '';
132
+ lines.push(`### ${icon} \`${c.id}\` — ${c.title}${advisory}`);
133
+ lines.push('');
134
+ lines.push(c.message);
135
+ if (c.fix) {
136
+ lines.push('');
137
+ lines.push(`**Fix:** ${c.fix}`);
138
+ }
139
+ if (c.whyThisMatters) {
140
+ lines.push('');
141
+ lines.push(`**Why:** ${c.whyThisMatters}`);
142
+ }
143
+ lines.push('');
144
+ }
145
+ return lines.join('\n') + '\n';
146
+ }
@@ -236,9 +236,13 @@ export declare function commandLifecycle(e: ICommandCatalogEntry): CommandLifecy
236
236
  /**
237
237
  * Default-help visibility rule. Honors an explicit
238
238
  * {@link ICommandCatalogEntry.showInDefaultHelp} when set; otherwise
239
- * primary + common are visible and advanced / machine / internal / legacy
240
- * are hidden. Deprecated and retired commands are always hidden by
241
- * default regardless of surface.
239
+ * the {@link PRIMARY_VERBS_ALLOWLIST} gates membership in the visible
240
+ * surface (primary + common entries whose top-level verb pays rent
241
+ * make the cut; everything else is hidden from `--full-help`).
242
+ *
243
+ * Deprecated, retired, aliased commands and anything in the
244
+ * {@link R46_OVERLAY} are always hidden regardless of allowlist
245
+ * membership.
242
246
  */
243
247
  export declare function defaultShowInHelp(e: ICommandCatalogEntry): boolean;
244
248
  /**