@shrkcrft/cli 0.1.0-alpha.28 → 0.1.0-alpha.30
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/commands/baseline.command.d.ts +25 -0
- package/dist/commands/baseline.command.d.ts.map +1 -1
- package/dist/commands/baseline.command.js +64 -17
- package/dist/commands/changelog-data.d.ts.map +1 -1
- package/dist/commands/changelog-data.js +46 -0
- package/dist/commands/check.command.d.ts.map +1 -1
- package/dist/commands/check.command.js +137 -12
- package/dist/commands/code-intel.command.d.ts.map +1 -1
- package/dist/commands/code-intel.command.js +5 -1
- package/dist/commands/command-catalog.d.ts.map +1 -1
- package/dist/commands/command-catalog.js +8 -0
- package/dist/commands/daily.commands.d.ts.map +1 -1
- package/dist/commands/daily.commands.js +11 -1
- package/dist/commands/docs-references.command.d.ts +7 -0
- package/dist/commands/docs-references.command.d.ts.map +1 -0
- package/dist/commands/docs-references.command.js +323 -0
- package/dist/commands/doctor.command.d.ts.map +1 -1
- package/dist/commands/doctor.command.js +3 -2
- package/dist/commands/gates.command.d.ts +13 -1
- package/dist/commands/gates.command.d.ts.map +1 -1
- package/dist/commands/gates.command.js +693 -26
- package/dist/commands/generated.command.d.ts +32 -0
- package/dist/commands/generated.command.d.ts.map +1 -1
- package/dist/commands/generated.command.js +214 -53
- package/dist/commands/graph-code-subverbs.d.ts.map +1 -1
- package/dist/commands/graph-code-subverbs.js +5 -1
- package/dist/commands/help.command.d.ts.map +1 -1
- package/dist/commands/help.command.js +64 -2
- package/dist/commands/policy-lint.command.d.ts.map +1 -1
- package/dist/commands/policy-lint.command.js +52 -10
- package/dist/commands/registry.command.d.ts.map +1 -1
- package/dist/commands/registry.command.js +34 -9
- package/dist/commands/wiring.command.d.ts.map +1 -1
- package/dist/commands/wiring.command.js +4 -3
- package/dist/exit-codes.d.ts +27 -7
- package/dist/exit-codes.d.ts.map +1 -1
- package/dist/exit-codes.js +47 -8
- package/dist/gates/gate-envelope.d.ts +64 -0
- package/dist/gates/gate-envelope.d.ts.map +1 -0
- package/dist/gates/gate-envelope.js +26 -0
- package/dist/gates/gate-rule-globs.d.ts +33 -0
- package/dist/gates/gate-rule-globs.d.ts.map +1 -0
- package/dist/gates/gate-rule-globs.js +101 -0
- package/dist/gates/gate-rule-view.d.ts +9 -3
- package/dist/gates/gate-rule-view.d.ts.map +1 -1
- package/dist/gates/gate-rule-view.js +18 -4
- package/dist/gates/rule-coverage.d.ts +39 -1
- package/dist/gates/rule-coverage.d.ts.map +1 -1
- package/dist/gates/rule-coverage.js +123 -8
- package/dist/gates/run-gate-planes.d.ts +44 -0
- package/dist/gates/run-gate-planes.d.ts.map +1 -0
- package/dist/gates/run-gate-planes.js +261 -0
- package/dist/main.d.ts.map +1 -1
- package/dist/main.js +7 -2
- package/package.json +33 -33
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
import { type ICommandHandler } from '../command-registry.js';
|
|
2
|
+
export declare const docsReferencesCheckCommand: ICommandHandler;
|
|
3
|
+
export declare const docsReferencesExplainCommand: ICommandHandler;
|
|
4
|
+
export declare const docsReferencesListCommand: ICommandHandler;
|
|
5
|
+
/** `shrk docs references <verb>` — dispatches to check / explain / list. */
|
|
6
|
+
export declare const docsReferencesCommand: ICommandHandler;
|
|
7
|
+
//# sourceMappingURL=docs-references.command.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"docs-references.command.d.ts","sourceRoot":"","sources":["../../src/commands/docs-references.command.ts"],"names":[],"mappings":"AAyBA,OAAO,EAIL,KAAK,eAAe,EAErB,MAAM,wBAAwB,CAAC;AAsGhC,eAAO,MAAM,0BAA0B,EAAE,eAuIxC,CAAC;AAEF,eAAO,MAAM,4BAA4B,EAAE,eA4D1C,CAAC;AAEF,eAAO,MAAM,yBAAyB,EAAE,eAyBvC,CAAC;AAEF,4EAA4E;AAC5E,eAAO,MAAM,qBAAqB,EAAE,eAkBnC,CAAC"}
|
|
@@ -0,0 +1,323 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* `shrk docs references {check,explain,list}` — the prose-reference linter.
|
|
3
|
+
*
|
|
4
|
+
* shrk docs references check [--id X] [--json] # unresolved id → finding
|
|
5
|
+
* shrk docs references explain --id X # every token + where it resolved
|
|
6
|
+
* shrk docs references list # the declared rules
|
|
7
|
+
*
|
|
8
|
+
* shrk validates the STRUCTURED `references[]` on knowledge entries. The same
|
|
9
|
+
* ids written as prose — a README, an architecture doc, an agent skill file
|
|
10
|
+
* saying `shrk gen nge.foo` — had no gate at all, and markdown has no build
|
|
11
|
+
* behind it. This points the existing reference resolver at that surface.
|
|
12
|
+
*
|
|
13
|
+
* Read-only: it scans documents and consults registries. Nothing is written and
|
|
14
|
+
* nothing is spawned.
|
|
15
|
+
*/
|
|
16
|
+
import * as nodePath from 'node:path';
|
|
17
|
+
import { checkDocReferences, inspectSharkcraft, warmReferenceRegistries, resolveProjectConfig, } from '@shrkcrft/inspector';
|
|
18
|
+
import { flagBool, flagString, resolveCwd, } from "../command-registry.js";
|
|
19
|
+
import { ExitCode } from "../exit-codes.js";
|
|
20
|
+
import { asJson, header, kv } from "../output/format-output.js";
|
|
21
|
+
import { buildGateEnvelope } from "../gates/gate-envelope.js";
|
|
22
|
+
const SCHEMA = 'sharkcraft.doc-references/v1';
|
|
23
|
+
async function prepare(args) {
|
|
24
|
+
const cwd = resolveCwd(args);
|
|
25
|
+
const json = flagBool(args, 'json');
|
|
26
|
+
const loaded = await resolveProjectConfig(cwd);
|
|
27
|
+
if (!loaded.ok) {
|
|
28
|
+
const msg = loaded.error.message;
|
|
29
|
+
if (json)
|
|
30
|
+
process.stdout.write(asJson({ schema: SCHEMA, error: msg }) + '\n');
|
|
31
|
+
else
|
|
32
|
+
process.stderr.write(`Could not load config: ${msg}\n Run \`shrk doctor\` for details.\n`);
|
|
33
|
+
return { ok: false, code: ExitCode.UsageError };
|
|
34
|
+
}
|
|
35
|
+
const all = loaded.value.config.docReferences ?? [];
|
|
36
|
+
const rel = nodePath.relative(cwd, loaded.value.sharkcraftDir).split(nodePath.sep).join('/');
|
|
37
|
+
let rules = all;
|
|
38
|
+
const id = flagString(args, 'id');
|
|
39
|
+
if (id) {
|
|
40
|
+
const wanted = id.split(',').map((s) => s.trim()).filter(Boolean);
|
|
41
|
+
const known = new Set(all.map((r) => r.id));
|
|
42
|
+
const unknown = wanted.filter((w) => !known.has(w));
|
|
43
|
+
if (unknown.length > 0) {
|
|
44
|
+
process.stderr.write(`Unknown doc-reference rule id(s): ${unknown.join(', ')}. Declared: ${[...known].join(', ') || '(none)'}\n`);
|
|
45
|
+
return { ok: false, code: ExitCode.UsageError };
|
|
46
|
+
}
|
|
47
|
+
rules = all.filter((r) => wanted.includes(r.id));
|
|
48
|
+
}
|
|
49
|
+
return {
|
|
50
|
+
ok: true,
|
|
51
|
+
value: {
|
|
52
|
+
cwd,
|
|
53
|
+
rules,
|
|
54
|
+
all,
|
|
55
|
+
excludeDirs: rel && !rel.startsWith('..') ? [rel] : [],
|
|
56
|
+
planeDiagnostics: loaded.value.planeDiagnostics,
|
|
57
|
+
},
|
|
58
|
+
};
|
|
59
|
+
}
|
|
60
|
+
/**
|
|
61
|
+
* Build the inspection the resolver needs.
|
|
62
|
+
*
|
|
63
|
+
* Deliberately lazy — it is only paid for when a `docReferences` rule exists,
|
|
64
|
+
* so a repo without the plane never loads the registries just to be told it has
|
|
65
|
+
* no rules.
|
|
66
|
+
*/
|
|
67
|
+
async function inspectionFor(cwd) {
|
|
68
|
+
// Playbook / construct ids come from a cache an ASYNC load populates; the
|
|
69
|
+
// resolver is sync. Warming here is what makes a correct pack playbook cited
|
|
70
|
+
// in prose actually resolve.
|
|
71
|
+
const inspection = await inspectSharkcraft({ cwd });
|
|
72
|
+
await warmReferenceRegistries(inspection);
|
|
73
|
+
return inspection;
|
|
74
|
+
}
|
|
75
|
+
function writeNoRules(json) {
|
|
76
|
+
if (json) {
|
|
77
|
+
process.stdout.write(asJson({ schema: SCHEMA, results: [], evaluated: 0, verdict: 'not-verified' }) + '\n');
|
|
78
|
+
return ExitCode.NotVerified;
|
|
79
|
+
}
|
|
80
|
+
process.stdout.write(header('Doc references'));
|
|
81
|
+
process.stdout.write(' No doc-reference rules declared. Add `docReferences[]` to sharkcraft.config.ts to\n' +
|
|
82
|
+
' catch ids cited in prose (READMEs, docs, agent skill files) that no longer resolve\n' +
|
|
83
|
+
' (see docs/doc-references.md).\n');
|
|
84
|
+
return ExitCode.NotVerified;
|
|
85
|
+
}
|
|
86
|
+
function resultJson(r) {
|
|
87
|
+
return {
|
|
88
|
+
id: r.ruleId,
|
|
89
|
+
...(r.description ? { description: r.description } : {}),
|
|
90
|
+
status: r.status,
|
|
91
|
+
severity: r.severity,
|
|
92
|
+
filesScanned: r.filesScanned,
|
|
93
|
+
tokensChecked: r.tokensChecked,
|
|
94
|
+
tokensSkipped: r.tokensSkipped,
|
|
95
|
+
findings: r.findings,
|
|
96
|
+
...(r.skipReason ? { skipReason: r.skipReason } : {}),
|
|
97
|
+
...(r.error ? { error: r.error } : {}),
|
|
98
|
+
};
|
|
99
|
+
}
|
|
100
|
+
export const docsReferencesCheckCommand = {
|
|
101
|
+
name: 'check',
|
|
102
|
+
description: 'Scan configured docs for id-shaped tokens and assert each resolves to a registered id. Catches a README or skill file citing a template that no longer exists.',
|
|
103
|
+
usage: 'shrk docs references check [--id <ids>] [--json]',
|
|
104
|
+
booleanFlags: new Set(['json']),
|
|
105
|
+
async run(args) {
|
|
106
|
+
const prep = await prepare(args);
|
|
107
|
+
if (!prep.ok)
|
|
108
|
+
return prep.code;
|
|
109
|
+
const json = flagBool(args, 'json');
|
|
110
|
+
if (prep.value.rules.length === 0)
|
|
111
|
+
return writeNoRules(json);
|
|
112
|
+
const inspection = await inspectionFor(prep.value.cwd);
|
|
113
|
+
const results = prep.value.rules.map((r) => checkDocReferences(prep.value.cwd, r, inspection, prep.value.excludeDirs));
|
|
114
|
+
// A rule that ERRORED proved nothing — it never got as far as checking an
|
|
115
|
+
// id. So it is not `evaluated`, whatever its severity: a warning-severity
|
|
116
|
+
// rule that could not run must not leave the banner saying "not blocking"
|
|
117
|
+
// over an exit code of 0, which is the same half-truth as a green banner
|
|
118
|
+
// above a list of findings.
|
|
119
|
+
const errored = results.filter((r) => r.status === 'error');
|
|
120
|
+
const failed = results.filter((r) => r.status === 'failed');
|
|
121
|
+
const blocking = [...failed, ...errored].filter((r) => r.severity === 'error');
|
|
122
|
+
const evaluated = results.filter((r) => r.status !== 'skipped' && r.status !== 'error').length;
|
|
123
|
+
const skipped = results.length - evaluated;
|
|
124
|
+
const exit = blocking.length > 0
|
|
125
|
+
? ExitCode.Failure
|
|
126
|
+
: evaluated === 0 || skipped > 0
|
|
127
|
+
? ExitCode.NotVerified
|
|
128
|
+
: ExitCode.VerifiedPass;
|
|
129
|
+
if (json) {
|
|
130
|
+
process.stdout.write(asJson({
|
|
131
|
+
schema: SCHEMA,
|
|
132
|
+
results: results.map(resultJson),
|
|
133
|
+
evaluated,
|
|
134
|
+
skipped,
|
|
135
|
+
verdict: blocking.length > 0 ? 'errors' : evaluated === 0 ? 'not-verified' : 'pass',
|
|
136
|
+
diagnostics: prep.value.planeDiagnostics,
|
|
137
|
+
exitCode: exit,
|
|
138
|
+
gate: buildGateEnvelope('docs references check', exit, results.map((r) => ({
|
|
139
|
+
id: r.ruleId,
|
|
140
|
+
type: 'doc-reference',
|
|
141
|
+
status: r.status,
|
|
142
|
+
severity: r.severity,
|
|
143
|
+
counts: { files: r.filesScanned, tokens: r.tokensChecked, skipped: r.tokensSkipped },
|
|
144
|
+
violations: r.findings.map((f) => ({
|
|
145
|
+
id: f.token,
|
|
146
|
+
file: f.file,
|
|
147
|
+
line: f.line,
|
|
148
|
+
message: f.message,
|
|
149
|
+
...(f.didYouMean.length > 0 ? { hint: `did you mean: ${f.didYouMean.join(', ')}` } : {}),
|
|
150
|
+
})),
|
|
151
|
+
...(r.skipReason ? { skipReason: r.skipReason } : {}),
|
|
152
|
+
...(r.error ? { error: r.error } : {}),
|
|
153
|
+
}))),
|
|
154
|
+
}) + '\n');
|
|
155
|
+
return exit;
|
|
156
|
+
}
|
|
157
|
+
process.stdout.write(header('Doc references'));
|
|
158
|
+
process.stdout.write(kv('evaluated', `${evaluated} of ${prep.value.rules.length}`) + '\n');
|
|
159
|
+
for (const r of results) {
|
|
160
|
+
if (r.status === 'skipped') {
|
|
161
|
+
process.stdout.write(` – ${r.ruleId} SKIPPED — ${r.skipReason}\n`);
|
|
162
|
+
continue;
|
|
163
|
+
}
|
|
164
|
+
if (r.status === 'error') {
|
|
165
|
+
process.stdout.write(` ! ${r.ruleId} ${r.error}\n`);
|
|
166
|
+
continue;
|
|
167
|
+
}
|
|
168
|
+
if (r.status === 'passed') {
|
|
169
|
+
process.stdout.write(` ✓ ${r.ruleId} (${r.tokensChecked} reference(s) across ${r.filesScanned} doc(s) all resolve)\n`);
|
|
170
|
+
continue;
|
|
171
|
+
}
|
|
172
|
+
// A rule that CHECKED nothing failed for a different reason than one with
|
|
173
|
+
// findings, and the loud-skip contract is worthless if it does not say
|
|
174
|
+
// which. `0 unresolved of 0 checked` would send the reader hunting for a
|
|
175
|
+
// bad id when the real problem is a moved directory.
|
|
176
|
+
if (r.skipReason) {
|
|
177
|
+
process.stdout.write(` ✗ ${r.ruleId} FAILED — ${r.skipReason}\n`);
|
|
178
|
+
process.stdout.write(' Nothing was checked, so nothing was enforced. Fix the glob, or set\n' +
|
|
179
|
+
' `failOnEmpty: false` if this rule may legitimately cover no docs.\n');
|
|
180
|
+
continue;
|
|
181
|
+
}
|
|
182
|
+
process.stdout.write(` ✗ ${r.ruleId} ${r.findings.length} unresolved reference(s) of ${r.tokensChecked} checked\n`);
|
|
183
|
+
for (const f of r.findings.slice(0, 25)) {
|
|
184
|
+
process.stdout.write(` • ${f.token} (${f.file}:${f.line})\n`);
|
|
185
|
+
if (f.didYouMean.length > 0) {
|
|
186
|
+
process.stdout.write(` did you mean: ${f.didYouMean.join(', ')}\n`);
|
|
187
|
+
}
|
|
188
|
+
}
|
|
189
|
+
if (r.findings.length > 25) {
|
|
190
|
+
process.stdout.write(` … (${r.findings.length - 25} more)\n`);
|
|
191
|
+
}
|
|
192
|
+
const hint = r.findings.find((f) => f.hint)?.hint;
|
|
193
|
+
if (hint)
|
|
194
|
+
process.stdout.write(` → ${hint}\n`);
|
|
195
|
+
}
|
|
196
|
+
for (const d of prep.value.planeDiagnostics)
|
|
197
|
+
process.stdout.write(` ! ${d}\n`);
|
|
198
|
+
// A warning-severity rule reports without blocking, but the banner must
|
|
199
|
+
// still say it FIRED. "Every id resolves ✓" printed under a list of
|
|
200
|
+
// unresolved ids is the kind of half-truth that trains people to stop
|
|
201
|
+
// reading the output.
|
|
202
|
+
const warned = failed.filter((r) => r.severity !== 'error');
|
|
203
|
+
if (exit === ExitCode.VerifiedPass && warned.length > 0) {
|
|
204
|
+
const count = warned.reduce((n, r) => n + r.findings.length, 0);
|
|
205
|
+
process.stdout.write(`\n${count} unresolved reference(s) reported by ${warned.length} warning rule(s) — not blocking.\n`);
|
|
206
|
+
}
|
|
207
|
+
else if (exit === ExitCode.VerifiedPass) {
|
|
208
|
+
process.stdout.write('\nEvery id cited in prose resolves. ✓\n');
|
|
209
|
+
}
|
|
210
|
+
else if (exit === ExitCode.NotVerified) {
|
|
211
|
+
process.stdout.write(errored.length > 0
|
|
212
|
+
? `\n${errored.length} rule(s) could not run — nothing was proved. This is NOT a pass.\n`
|
|
213
|
+
: '\nNothing was checked — this is NOT a pass.\n');
|
|
214
|
+
}
|
|
215
|
+
return exit;
|
|
216
|
+
},
|
|
217
|
+
};
|
|
218
|
+
export const docsReferencesExplainCommand = {
|
|
219
|
+
name: 'explain',
|
|
220
|
+
description: 'Show every id-shaped token ONE rule considered: where it was found, whether it resolved, and why a token was skipped.',
|
|
221
|
+
usage: 'shrk docs references explain --id <id> [--json]',
|
|
222
|
+
booleanFlags: new Set(['json']),
|
|
223
|
+
async run(args) {
|
|
224
|
+
const id = flagString(args, 'id') ?? args.positional[0];
|
|
225
|
+
if (!id) {
|
|
226
|
+
process.stderr.write('Usage: shrk docs references explain --id <id>\n');
|
|
227
|
+
return ExitCode.UsageError;
|
|
228
|
+
}
|
|
229
|
+
const forwarded = { ...args, flags: new Map(args.flags) };
|
|
230
|
+
forwarded.flags.set('id', id);
|
|
231
|
+
const prep = await prepare(forwarded);
|
|
232
|
+
if (!prep.ok)
|
|
233
|
+
return prep.code;
|
|
234
|
+
const rule = prep.value.rules[0];
|
|
235
|
+
if (!rule)
|
|
236
|
+
return writeNoRules(flagBool(args, 'json'));
|
|
237
|
+
const inspection = await inspectionFor(prep.value.cwd);
|
|
238
|
+
const result = checkDocReferences(prep.value.cwd, rule, inspection, prep.value.excludeDirs);
|
|
239
|
+
if (flagBool(args, 'json')) {
|
|
240
|
+
process.stdout.write(asJson({
|
|
241
|
+
schema: 'sharkcraft.doc-references-explain/v1',
|
|
242
|
+
...resultJson(result),
|
|
243
|
+
tokens: result.tokens,
|
|
244
|
+
resolvesAs: rule.resolvesAs,
|
|
245
|
+
requireContext: rule.requireContext ?? 'backtick',
|
|
246
|
+
}) + '\n');
|
|
247
|
+
return ExitCode.VerifiedPass;
|
|
248
|
+
}
|
|
249
|
+
process.stdout.write(header(`Doc references: ${rule.id}`));
|
|
250
|
+
if (rule.description)
|
|
251
|
+
process.stdout.write(` ${rule.description}\n`);
|
|
252
|
+
process.stdout.write(kv('files', rule.files.join(', ')) + '\n');
|
|
253
|
+
process.stdout.write(kv('token pattern', `/${rule.tokenPattern}/`) + '\n');
|
|
254
|
+
process.stdout.write(kv('resolves as', rule.resolvesAs.join(', ')) + '\n');
|
|
255
|
+
process.stdout.write(kv('context gate', rule.requireContext ?? 'backtick') + '\n');
|
|
256
|
+
process.stdout.write(kv('docs scanned', String(result.filesScanned)) + '\n');
|
|
257
|
+
process.stdout.write(kv('tokens', `${result.tokensChecked} checked, ${result.tokensSkipped} skipped`) + '\n');
|
|
258
|
+
if (result.error)
|
|
259
|
+
process.stdout.write(` ! ${result.error}\n`);
|
|
260
|
+
process.stdout.write('\n');
|
|
261
|
+
for (const t of result.tokens.slice(0, 100)) {
|
|
262
|
+
const verdict = t.skipped
|
|
263
|
+
? `skipped (${t.skipped})`
|
|
264
|
+
: t.resolvedAs
|
|
265
|
+
? `✓ ${t.resolvedAs}`
|
|
266
|
+
: '✗ UNRESOLVED';
|
|
267
|
+
process.stdout.write(` ${t.token} (${t.file}:${t.line}) — ${verdict}\n`);
|
|
268
|
+
}
|
|
269
|
+
if (result.tokens.length > 100) {
|
|
270
|
+
process.stdout.write(` … (${result.tokens.length - 100} more)\n`);
|
|
271
|
+
}
|
|
272
|
+
return ExitCode.VerifiedPass;
|
|
273
|
+
},
|
|
274
|
+
};
|
|
275
|
+
export const docsReferencesListCommand = {
|
|
276
|
+
name: 'list',
|
|
277
|
+
description: 'List every declared doc-reference rule: its globs, token shape, and target registries.',
|
|
278
|
+
usage: 'shrk docs references list [--json]',
|
|
279
|
+
booleanFlags: new Set(['json']),
|
|
280
|
+
async run(args) {
|
|
281
|
+
const prep = await prepare(args);
|
|
282
|
+
if (!prep.ok)
|
|
283
|
+
return prep.code;
|
|
284
|
+
const json = flagBool(args, 'json');
|
|
285
|
+
if (prep.value.all.length === 0)
|
|
286
|
+
return writeNoRules(json);
|
|
287
|
+
if (json) {
|
|
288
|
+
process.stdout.write(asJson({ schema: SCHEMA, rules: prep.value.all }) + '\n');
|
|
289
|
+
return ExitCode.VerifiedPass;
|
|
290
|
+
}
|
|
291
|
+
process.stdout.write(header(`Doc-reference rules (${prep.value.all.length})`));
|
|
292
|
+
for (const r of prep.value.all) {
|
|
293
|
+
process.stdout.write(` • ${r.id}\n`);
|
|
294
|
+
process.stdout.write(` files ${r.files.join(', ')}\n`);
|
|
295
|
+
process.stdout.write(` token /${r.tokenPattern}/\n`);
|
|
296
|
+
process.stdout.write(` resolves ${r.resolvesAs.join(', ')}\n`);
|
|
297
|
+
process.stdout.write(` context ${r.requireContext ?? 'backtick'}\n`);
|
|
298
|
+
if (r.description)
|
|
299
|
+
process.stdout.write(` ${r.description}\n`);
|
|
300
|
+
}
|
|
301
|
+
return ExitCode.VerifiedPass;
|
|
302
|
+
},
|
|
303
|
+
};
|
|
304
|
+
/** `shrk docs references <verb>` — dispatches to check / explain / list. */
|
|
305
|
+
export const docsReferencesCommand = {
|
|
306
|
+
name: 'references',
|
|
307
|
+
description: 'Prose-reference linter: assert every id cited in free text (READMEs, docs, agent skill files) still resolves to a registered id.',
|
|
308
|
+
usage: 'shrk docs references check | explain --id <id> | list',
|
|
309
|
+
booleanFlags: new Set(['json']),
|
|
310
|
+
async run(args) {
|
|
311
|
+
const sub = args.positional[0];
|
|
312
|
+
const rest = { ...args, positional: args.positional.slice(1) };
|
|
313
|
+
if (sub === 'check')
|
|
314
|
+
return docsReferencesCheckCommand.run(rest);
|
|
315
|
+
if (sub === 'explain')
|
|
316
|
+
return docsReferencesExplainCommand.run(rest);
|
|
317
|
+
if (sub === 'list')
|
|
318
|
+
return docsReferencesListCommand.run(rest);
|
|
319
|
+
process.stderr.write((sub ? `Unknown subcommand "${sub}". ` : '') +
|
|
320
|
+
'Usage: shrk docs references check | explain --id <id> | list\n');
|
|
321
|
+
return ExitCode.UsageError;
|
|
322
|
+
},
|
|
323
|
+
};
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"doctor.command.d.ts","sourceRoot":"","sources":["../../src/commands/doctor.command.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"doctor.command.d.ts","sourceRoot":"","sources":["../../src/commands/doctor.command.ts"],"names":[],"mappings":"AAsBA,OAAO,EAML,KAAK,eAAe,EAErB,MAAM,wBAAwB,CAAC;AA6PhC,eAAO,MAAM,aAAa,EAAE,eAW3B,CAAC;AA2fF,eAAO,MAAM,qBAAqB,EAAE,eAmCnC,CAAC;AAuDF,eAAO,MAAM,yBAAyB,EAAE,eAavC,CAAC;AAIF,eAAO,MAAM,wBAAwB,EAAE,eA2CtC,CAAC;AAgCF,eAAO,MAAM,6BAA6B,EAAE,eAa3C,CAAC"}
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { detectGraphFreshness } from '@shrkcrft/graph';
|
|
1
2
|
import { buildAcknowledgement, buildAiReadinessReport, buildSuppressionEntry, doctorSuppressionsFile, DoctorSeverity, filterDoctorResult, inspectSharkcraft, loadDoctorSuppressions, renderAcknowledgementsText, runDoctor, saveDoctorSuppressions, summarizeAcknowledgements, } from '@shrkcrft/inspector';
|
|
2
3
|
import { detectProjectShape } from '@shrkcrft/workspace';
|
|
3
4
|
import { loadSurfaceContext } from "../surface/load-surface-context.js";
|
|
@@ -236,7 +237,7 @@ async function doctorCommandImpl(args) {
|
|
|
236
237
|
inspectOpts.loaderTimeoutMs = loaderTimeout;
|
|
237
238
|
}
|
|
238
239
|
const inspection = await inspectSharkcraft(inspectOpts);
|
|
239
|
-
const result = augmentWithSemanticIndexCheck(runDoctor(inspection), cwd);
|
|
240
|
+
const result = augmentWithSemanticIndexCheck(runDoctor(inspection, { graphDivergence: detectGraphFreshness(cwd) }), cwd);
|
|
240
241
|
const report = buildAiReadinessReport(inspection);
|
|
241
242
|
if (debug) {
|
|
242
243
|
process.stderr.write(`[debug] inspection elapsed ${inspection.inspectionElapsedMs}ms cache=${inspection.cacheEnabled ? 'on' : 'off'} loaders=${inspection.loaderDiagnostics.length}\n`);
|
|
@@ -707,7 +708,7 @@ async function suppressionsListRun(args) {
|
|
|
707
708
|
async function suppressionsCheckRun(args) {
|
|
708
709
|
const cwd = resolveCwd(args);
|
|
709
710
|
const inspection = await inspectSharkcraft({ cwd });
|
|
710
|
-
const result = runDoctor(inspection);
|
|
711
|
+
const result = runDoctor(inspection, { graphDivergence: detectGraphFreshness(cwd) });
|
|
711
712
|
const cfg = loadDoctorSuppressions(cwd);
|
|
712
713
|
const filtered = filterDoctorResult(result, { suppressions: cfg.doctorSuppressions });
|
|
713
714
|
const unused = filtered.appliedSuppressions.filter((a) => a.matched === 0);
|
|
@@ -1,6 +1,18 @@
|
|
|
1
|
-
import { type ICommandHandler } from '../command-registry.js';
|
|
1
|
+
import { type ICommandHandler, type ParsedArgs } from '../command-registry.js';
|
|
2
2
|
export declare const gatesListCommand: ICommandHandler;
|
|
3
3
|
export declare const gatesCoverageCommand: ICommandHandler;
|
|
4
|
+
export declare const gatesCheckCommand: ICommandHandler;
|
|
5
|
+
export declare const gatesTryCommand: ICommandHandler;
|
|
4
6
|
export declare const gatesExplainCommand: ICommandHandler;
|
|
7
|
+
/**
|
|
8
|
+
* Try to explain `id` as a data-defined rule on ANY plane.
|
|
9
|
+
*
|
|
10
|
+
* Returns the exit code when the id resolves to exactly one declared rule, or
|
|
11
|
+
* `undefined` when it is not a rule id at all — which lets `shrk explain` keep
|
|
12
|
+
* its original topic-search behaviour for everything else. This is the D2
|
|
13
|
+
* unification: a user holding a rule id no longer has to know which plane owns
|
|
14
|
+
* it, and no existing invocation changes meaning.
|
|
15
|
+
*/
|
|
16
|
+
export declare function tryExplainGateRule(args: ParsedArgs, id: string): Promise<number | undefined>;
|
|
5
17
|
export declare const gatesCommand: ICommandHandler;
|
|
6
18
|
//# sourceMappingURL=gates.command.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"gates.command.d.ts","sourceRoot":"","sources":["../../src/commands/gates.command.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"gates.command.d.ts","sourceRoot":"","sources":["../../src/commands/gates.command.ts"],"names":[],"mappings":"AA6CA,OAAO,EAKL,KAAK,eAAe,EACpB,KAAK,UAAU,EAChB,MAAM,wBAAwB,CAAC;AAgOhC,eAAO,MAAM,gBAAgB,EAAE,eAsD9B,CAAC;AAEF,eAAO,MAAM,oBAAoB,EAAE,eA+KlC,CAAC;AAGF,eAAO,MAAM,iBAAiB,EAAE,eAwK/B,CAAC;AAkCF,eAAO,MAAM,eAAe,EAAE,eAgN7B,CAAC;AA+FF,eAAO,MAAM,mBAAmB,EAAE,eAmGjC,CAAC;AAEF;;;;;;;;GAQG;AACH,wBAAsB,kBAAkB,CACtC,IAAI,EAAE,UAAU,EAChB,EAAE,EAAE,MAAM,GACT,OAAO,CAAC,MAAM,GAAG,SAAS,CAAC,CAQ7B;AAED,eAAO,MAAM,YAAY,EAAE,eAuB1B,CAAC"}
|