@shrkcrft/cli 0.1.0-alpha.1 → 0.1.0-alpha.10
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/README.md +1 -1
- package/dist/commands/api-diff.command.d.ts +11 -0
- package/dist/commands/api-diff.command.d.ts.map +1 -0
- package/dist/commands/api-diff.command.js +116 -0
- package/dist/commands/arch.command.d.ts +9 -0
- package/dist/commands/arch.command.d.ts.map +1 -0
- package/dist/commands/arch.command.js +186 -0
- package/dist/commands/boundaries.command.d.ts.map +1 -1
- package/dist/commands/boundaries.command.js +0 -12
- package/dist/commands/check.command.d.ts.map +1 -1
- package/dist/commands/check.command.js +20 -30
- package/dist/commands/code-intel.command.d.ts +18 -0
- package/dist/commands/code-intel.command.d.ts.map +1 -0
- package/dist/commands/code-intel.command.js +146 -0
- package/dist/commands/command-catalog.d.ts +7 -3
- package/dist/commands/command-catalog.d.ts.map +1 -1
- package/dist/commands/command-catalog.js +201 -47
- package/dist/commands/commands.command.d.ts.map +1 -1
- package/dist/commands/commands.command.js +4 -4
- package/dist/commands/completion.command.d.ts +10 -0
- package/dist/commands/completion.command.d.ts.map +1 -0
- package/dist/commands/completion.command.js +121 -0
- package/dist/commands/constructs.command.d.ts.map +1 -1
- package/dist/commands/constructs.command.js +5 -22
- package/dist/commands/context.command.d.ts.map +1 -1
- package/dist/commands/context.command.js +89 -0
- package/dist/commands/diff-check.command.d.ts +30 -0
- package/dist/commands/diff-check.command.d.ts.map +1 -0
- package/dist/commands/diff-check.command.js +210 -0
- package/dist/commands/doctor.command.d.ts.map +1 -1
- package/dist/commands/doctor.command.js +42 -9
- package/dist/commands/export.command.d.ts.map +1 -1
- package/dist/commands/export.command.js +76 -3
- package/dist/commands/framework.command.d.ts +12 -0
- package/dist/commands/framework.command.d.ts.map +1 -0
- package/dist/commands/framework.command.js +180 -0
- package/dist/commands/gate.command.d.ts +15 -0
- package/dist/commands/gate.command.d.ts.map +1 -0
- package/dist/commands/gate.command.js +296 -0
- package/dist/commands/graph-code-subverbs.d.ts +11 -0
- package/dist/commands/graph-code-subverbs.d.ts.map +1 -0
- package/dist/commands/graph-code-subverbs.js +818 -0
- package/dist/commands/graph.command.d.ts.map +1 -1
- package/dist/commands/graph.command.js +22 -0
- package/dist/commands/help.command.d.ts +4 -3
- package/dist/commands/help.command.d.ts.map +1 -1
- package/dist/commands/help.command.js +77 -21
- package/dist/commands/helper.command.js +1 -1
- package/dist/commands/impact.command.d.ts.map +1 -1
- package/dist/commands/impact.command.js +170 -1
- package/dist/commands/import.command.d.ts.map +1 -1
- package/dist/commands/import.command.js +121 -5
- package/dist/commands/init.command.d.ts.map +1 -1
- package/dist/commands/init.command.js +184 -16
- package/dist/commands/mcp.command.d.ts.map +1 -1
- package/dist/commands/mcp.command.js +2 -131
- package/dist/commands/migrate.command.d.ts +13 -0
- package/dist/commands/migrate.command.d.ts.map +1 -0
- package/dist/commands/migrate.command.js +152 -0
- package/dist/commands/onboard.command.d.ts.map +1 -1
- package/dist/commands/onboard.command.js +3 -15
- package/dist/commands/packs-new.d.ts +1 -1
- package/dist/commands/packs-new.d.ts.map +1 -1
- package/dist/commands/packs-new.js +5 -36
- package/dist/commands/packs.command.d.ts.map +1 -1
- package/dist/commands/packs.command.js +3 -17
- package/dist/commands/plan-context.command.d.ts +11 -0
- package/dist/commands/plan-context.command.d.ts.map +1 -0
- package/dist/commands/plan-context.command.js +77 -0
- package/dist/commands/profiles.command.js +4 -4
- package/dist/commands/release.command.js +13 -13
- package/dist/commands/review.command.d.ts.map +1 -1
- package/dist/commands/review.command.js +2 -28
- package/dist/commands/rule-graph-subverbs.d.ts +3 -0
- package/dist/commands/rule-graph-subverbs.d.ts.map +1 -0
- package/dist/commands/rule-graph-subverbs.js +132 -0
- package/dist/commands/search-structural.command.d.ts +18 -0
- package/dist/commands/search-structural.command.d.ts.map +1 -0
- package/dist/commands/search-structural.command.js +376 -0
- package/dist/commands/search.command.js +1 -1
- package/dist/commands/task-context.command.js +0 -16
- package/dist/commands/task.command.d.ts.map +1 -1
- package/dist/commands/task.command.js +8 -2
- package/dist/dashboard/code-intelligence-data.d.ts +33 -0
- package/dist/dashboard/code-intelligence-data.d.ts.map +1 -0
- package/dist/dashboard/code-intelligence-data.js +307 -0
- package/dist/dashboard/dashboard-api-server.d.ts.map +1 -1
- package/dist/dashboard/dashboard-api-server.js +137 -1
- package/dist/export/claude-commands-export.d.ts +60 -0
- package/dist/export/claude-commands-export.d.ts.map +1 -0
- package/dist/export/claude-commands-export.js +276 -0
- package/dist/export/export-formats.d.ts +1 -1
- package/dist/export/export-formats.d.ts.map +1 -1
- package/dist/export/export-formats.js +139 -12
- package/dist/init/init-templates.d.ts.map +1 -1
- package/dist/init/init-templates.js +133 -113
- package/dist/init/paths-advisory.d.ts +20 -0
- package/dist/init/paths-advisory.d.ts.map +1 -0
- package/dist/init/paths-advisory.js +88 -0
- package/dist/main.d.ts +1 -1
- package/dist/main.d.ts.map +1 -1
- package/dist/main.js +137 -46
- package/dist/output/failure-hints.d.ts +1 -9
- package/dist/output/failure-hints.d.ts.map +1 -1
- package/dist/output/failure-hints.js +2 -8
- package/dist/output/watch-loop.d.ts +9 -1
- package/dist/output/watch-loop.d.ts.map +1 -1
- package/dist/output/watch-loop.js +13 -3
- package/dist/schemas/json-schemas.d.ts +36 -36
- package/dist/schemas/json-schemas.js +36 -36
- package/dist/surface/about.d.ts.map +1 -1
- package/dist/surface/about.js +37 -15
- package/dist/surface/no-args-landing.d.ts.map +1 -1
- package/dist/surface/no-args-landing.js +9 -13
- package/dist/surface/surface-config-writer.d.ts.map +1 -1
- package/dist/surface/surface-config-writer.js +23 -11
- package/package.json +36 -25
- package/dist/commands/plugin.command.d.ts +0 -11
- package/dist/commands/plugin.command.d.ts.map +0 -1
- 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/
|
|
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,
|
|
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":"
|
|
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,
|
|
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
|
-
*
|
|
240
|
-
*
|
|
241
|
-
*
|
|
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
|
/**
|