@shrkcrft/inspector 0.1.0-alpha.19 → 0.1.0-alpha.20
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/changes-summary.d.ts.map +1 -1
- package/dist/changes-summary.js +10 -1
- package/dist/contradictions.d.ts +8 -1
- package/dist/contradictions.d.ts.map +1 -1
- package/dist/contradictions.js +37 -35
- package/dist/git-helpers.d.ts.map +1 -1
- package/dist/git-helpers.js +10 -4
- package/dist/plan-review.d.ts.map +1 -1
- package/dist/plan-review.js +5 -10
- package/dist/registry-lifecycle.d.ts +6 -0
- package/dist/registry-lifecycle.d.ts.map +1 -1
- package/dist/registry-lifecycle.js +137 -10
- package/dist/review-packet.d.ts.map +1 -1
- package/dist/review-packet.js +14 -17
- package/dist/why-file.js +66 -22
- package/package.json +18 -18
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"changes-summary.d.ts","sourceRoot":"","sources":["../src/changes-summary.ts"],"names":[],"mappings":"AAcA,OAAO,KAAK,EAAE,qBAAqB,EAAE,MAAM,2BAA2B,CAAC;AAEvE,eAAO,MAAM,sBAAsB,kCAAkC,CAAC;AAEtE,oBAAY,UAAU;IACpB,GAAG,QAAQ;IACX,SAAS,eAAe;IACxB,SAAS,cAAc;IACvB,SAAS,cAAc;IACvB,SAAS,cAAc;IACvB,KAAK,UAAU;IACf,SAAS,cAAc;IACvB,OAAO,YAAY;IACnB,UAAU,eAAe;IACzB,KAAK,UAAU;IACf,IAAI,SAAS;IACb,SAAS,cAAc;IACvB,MAAM,WAAW;IACjB,SAAS,eAAe;IACxB,QAAQ,aAAa;IACrB,SAAS,cAAc;IACvB,WAAW,uBAAuB;IAClC,YAAY,kBAAkB;IAC9B,IAAI,SAAS;IACb,KAAK,UAAU;IACf,QAAQ,aAAa;IACrB,OAAO,YAAY;IACnB,GAAG,QAAQ;IACX,UAAU,2BAA2B;IACrC,OAAO,YAAY;IACnB,OAAO,YAAY;CACpB;AAED,MAAM,WAAW,mBAAmB;IAClC,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,UAAU,CAAC;IACjB,MAAM,EAAE,OAAO,CAAC;IAChB,KAAK,EAAE,OAAO,CAAC;IACf,SAAS,EAAE,OAAO,CAAC;IACnB,YAAY,EAAE,OAAO,CAAC;IACtB,QAAQ,EAAE,OAAO,CAAC;IAClB,WAAW,EAAE,OAAO,CAAC;IACrB,gBAAgB,EAAE,OAAO,CAAC;CAC3B;AAED,MAAM,WAAW,qBAAqB;IACpC,MAAM,EAAE,OAAO,sBAAsB,CAAC;IACtC,WAAW,EAAE,MAAM,CAAC;IACpB,MAAM,EAAE,OAAO,GAAG,QAAQ,GAAG,OAAO,GAAG,cAAc,CAAC;IACtD,GAAG,CAAC,EAAE,MAAM,CAAC;IACb,wDAAwD;IACxD,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,UAAU,EAAE,MAAM,CAAC;IACnB,WAAW,EAAE,MAAM,CAAC,MAAM,EAAE,SAAS,MAAM,EAAE,CAAC,CAAC;IAC/C,KAAK,EAAE,SAAS,mBAAmB,EAAE,CAAC;IACtC,4CAA4C;IAC5C,eAAe,EAAE,SAAS,MAAM,EAAE,CAAC;IACnC,8BAA8B;IAC9B,eAAe,EAAE,SAAS,MAAM,EAAE,CAAC;IACnC,gDAAgD;IAChD,cAAc,EAAE,SAAS,MAAM,EAAE,CAAC;IAClC,0BAA0B;IAC1B,WAAW,EAAE,SAAS,MAAM,EAAE,CAAC;IAC/B,0BAA0B;IAC1B,YAAY,EAAE,SAAS,MAAM,EAAE,CAAC;IAChC,2CAA2C;IAC3C,iBAAiB,EAAE,SAAS,MAAM,EAAE,CAAC;IACrC,qCAAqC;IACrC,mBAAmB,EAAE,SAAS,MAAM,EAAE,CAAC;IACvC,0CAA0C;IAC1C,IAAI,EAAE,KAAK,GAAG,QAAQ,GAAG,MAAM,CAAC;IAChC,wCAAwC;IACxC,WAAW,EAAE,SAAS,MAAM,EAAE,CAAC;IAC/B,qCAAqC;IACrC,2BAA2B,EAAE,SAAS,MAAM,EAAE,CAAC;IAC/C,qCAAqC;IACrC,eAAe,EAAE,MAAM,CAAC;CACzB;AAED,MAAM,WAAW,sBAAsB;IACrC,qCAAqC;IACrC,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,6BAA6B;IAC7B,MAAM,CAAC,EAAE,OAAO,CAAC;IACjB,wCAAwC;IACxC,KAAK,CAAC,EAAE,SAAS,MAAM,EAAE,CAAC;IAC1B,+EAA+E;IAC/E,UAAU,CAAC,EAAE,MAAM,CAAC;CACrB;
|
|
1
|
+
{"version":3,"file":"changes-summary.d.ts","sourceRoot":"","sources":["../src/changes-summary.ts"],"names":[],"mappings":"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"}
|
package/dist/changes-summary.js
CHANGED
|
@@ -90,6 +90,11 @@ function classifyArea(file) {
|
|
|
90
90
|
if (/(?:^|\/)[\w-]*sharkcraft-pack\//.test(file)) {
|
|
91
91
|
return ChangeArea.PackContrib;
|
|
92
92
|
}
|
|
93
|
+
// Extension fallback so the summary stays useful in non-SharkCraft repos
|
|
94
|
+
// (e.g. a foreign monorepo's `architecture/*.md`) instead of bucketing every
|
|
95
|
+
// doc as `unknown`.
|
|
96
|
+
if (/\.mdx?$/i.test(file))
|
|
97
|
+
return ChangeArea.Docs;
|
|
93
98
|
return ChangeArea.Unknown;
|
|
94
99
|
}
|
|
95
100
|
function classifyFile(file) {
|
|
@@ -229,7 +234,11 @@ export async function buildChangesSummary(inspection, options = {}) {
|
|
|
229
234
|
ref = options.since;
|
|
230
235
|
}
|
|
231
236
|
else {
|
|
232
|
-
|
|
237
|
+
// Default working-tree view must include untracked files — otherwise a
|
|
238
|
+
// brand-new (never-staged) file is invisible to the summary, which made
|
|
239
|
+
// `totalFiles` undercount whole untracked directories. Mirrors every other
|
|
240
|
+
// working-tree caller (boundaries / propose-knowledge / architecture).
|
|
241
|
+
changedFiles = getChangedFiles(cwd, { includeWorktree: true });
|
|
233
242
|
source = 'working-tree';
|
|
234
243
|
}
|
|
235
244
|
const classified = changedFiles.map(classifyFile);
|
package/dist/contradictions.d.ts
CHANGED
|
@@ -39,10 +39,17 @@ export interface IContradictionReport {
|
|
|
39
39
|
}
|
|
40
40
|
export interface IBuildContradictionReportOptions {
|
|
41
41
|
inspection: ISharkcraftInspection;
|
|
42
|
-
/** Max doc files to scan. Default
|
|
42
|
+
/** Max doc files to scan. Default 5000 (effectively the whole docs tree). */
|
|
43
43
|
docScanLimit?: number;
|
|
44
44
|
/** Max bytes per doc. Default 200_000. */
|
|
45
45
|
bytesPerDoc?: number;
|
|
46
|
+
/**
|
|
47
|
+
* Authoritative set of CLI command names (top-level verbs) used to flag
|
|
48
|
+
* `shrk <verb>` references to non-existent commands. Injected by the CLI from
|
|
49
|
+
* its own command catalogue (inspector must not import cli). When omitted,
|
|
50
|
+
* missing-command findings are suppressed — the safe failure mode.
|
|
51
|
+
*/
|
|
52
|
+
cliCommandNames?: ReadonlySet<string>;
|
|
46
53
|
}
|
|
47
54
|
export declare function buildContradictionReport(options: IBuildContradictionReportOptions): IContradictionReport;
|
|
48
55
|
export declare function renderContradictionReportText(report: IContradictionReport): string;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"contradictions.d.ts","sourceRoot":"","sources":["../src/contradictions.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,qBAAqB,EAAE,MAAM,2BAA2B,CAAC;AAEvE,eAAO,MAAM,qBAAqB,iCAAiC,CAAC;AAEpE,oBAAY,iBAAiB;IAC3B,WAAW,iBAAiB;IAC5B,cAAc,oBAAoB;IAClC,SAAS,eAAe;IACxB,UAAU,iBAAiB;IAC3B,aAAa,mBAAmB;IAChC,mBAAmB,2BAA2B;IAC9C,wBAAwB,8BAA8B;CACvD;AAED,oBAAY,qBAAqB;IAC/B,KAAK,UAAU;IACf,OAAO,YAAY;IACnB,IAAI,SAAS;CACd;AAED,MAAM,WAAW,qBAAqB;IACpC,EAAE,EAAE,MAAM,CAAC;IACX,IAAI,EAAE,iBAAiB,CAAC;IACxB,QAAQ,EAAE,qBAAqB,CAAC;IAChC,OAAO,EAAE,MAAM,CAAC;IAChB,6CAA6C;IAC7C,MAAM,EAAE,MAAM,CAAC;IACf,kDAAkD;IAClD,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,8CAA8C;IAC9C,SAAS,EAAE,MAAM,CAAC;IAClB,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,MAAM,EAAE,MAAM,CAAC;CAChB;AAED,MAAM,WAAW,oBAAoB;IACnC,MAAM,EAAE,OAAO,qBAAqB,CAAC;IACrC,WAAW,EAAE,MAAM,CAAC;IACpB,QAAQ,EAAE,SAAS,qBAAqB,EAAE,CAAC;IAC3C,qBAAqB;IACrB,YAAY,EAAE,MAAM,CAAC;IACrB,oCAAoC;IACpC,WAAW,EAAE,SAAS,MAAM,EAAE,CAAC;CAChC;AAED,MAAM,WAAW,gCAAgC;IAC/C,UAAU,EAAE,qBAAqB,CAAC;IAClC,
|
|
1
|
+
{"version":3,"file":"contradictions.d.ts","sourceRoot":"","sources":["../src/contradictions.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,qBAAqB,EAAE,MAAM,2BAA2B,CAAC;AAEvE,eAAO,MAAM,qBAAqB,iCAAiC,CAAC;AAEpE,oBAAY,iBAAiB;IAC3B,WAAW,iBAAiB;IAC5B,cAAc,oBAAoB;IAClC,SAAS,eAAe;IACxB,UAAU,iBAAiB;IAC3B,aAAa,mBAAmB;IAChC,mBAAmB,2BAA2B;IAC9C,wBAAwB,8BAA8B;CACvD;AAED,oBAAY,qBAAqB;IAC/B,KAAK,UAAU;IACf,OAAO,YAAY;IACnB,IAAI,SAAS;CACd;AAED,MAAM,WAAW,qBAAqB;IACpC,EAAE,EAAE,MAAM,CAAC;IACX,IAAI,EAAE,iBAAiB,CAAC;IACxB,QAAQ,EAAE,qBAAqB,CAAC;IAChC,OAAO,EAAE,MAAM,CAAC;IAChB,6CAA6C;IAC7C,MAAM,EAAE,MAAM,CAAC;IACf,kDAAkD;IAClD,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,8CAA8C;IAC9C,SAAS,EAAE,MAAM,CAAC;IAClB,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,MAAM,EAAE,MAAM,CAAC;CAChB;AAED,MAAM,WAAW,oBAAoB;IACnC,MAAM,EAAE,OAAO,qBAAqB,CAAC;IACrC,WAAW,EAAE,MAAM,CAAC;IACpB,QAAQ,EAAE,SAAS,qBAAqB,EAAE,CAAC;IAC3C,qBAAqB;IACrB,YAAY,EAAE,MAAM,CAAC;IACrB,oCAAoC;IACpC,WAAW,EAAE,SAAS,MAAM,EAAE,CAAC;CAChC;AAED,MAAM,WAAW,gCAAgC;IAC/C,UAAU,EAAE,qBAAqB,CAAC;IAClC,6EAA6E;IAC7E,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,0CAA0C;IAC1C,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB;;;;;OAKG;IACH,eAAe,CAAC,EAAE,WAAW,CAAC,MAAM,CAAC,CAAC;CACvC;AA8BD,wBAAgB,wBAAwB,CACtC,OAAO,EAAE,gCAAgC,GACxC,oBAAoB,CA8LtB;AAmFD,wBAAgB,6BAA6B,CAAC,MAAM,EAAE,oBAAoB,GAAG,MAAM,CAgClF;AAED,wBAAgB,iCAAiC,CAAC,MAAM,EAAE,oBAAoB,GAAG,MAAM,CA2BtF;AAED,wBAAgB,6BAA6B,CAAC,MAAM,EAAE,oBAAoB,GAAG,MAAM,CAOlF;AAMD,wBAAgB,6BAA6B,CAAC,MAAM,EAAE,oBAAoB,GAAG,MAAM,CAElF"}
|
package/dist/contradictions.js
CHANGED
|
@@ -17,7 +17,10 @@ export var ContradictionSeverity;
|
|
|
17
17
|
ContradictionSeverity["Warning"] = "warning";
|
|
18
18
|
ContradictionSeverity["Info"] = "info";
|
|
19
19
|
})(ContradictionSeverity || (ContradictionSeverity = {}));
|
|
20
|
-
|
|
20
|
+
// High ceiling, not a sampling cap: docs are byte-bounded already, so scanning
|
|
21
|
+
// the whole tree is cheap and avoids the silent "scanned an arbitrary 80-file
|
|
22
|
+
// prefix" failure mode.
|
|
23
|
+
const DEFAULT_DOC_SCAN_LIMIT = 5000;
|
|
21
24
|
const DEFAULT_BYTES_PER_DOC = 200_000;
|
|
22
25
|
const DOC_EXTS = new Set(['.md', '.mdx', '.rst', '.txt']);
|
|
23
26
|
const DOC_DIR_NAMES = new Set(['docs', 'documentation', 'doc']);
|
|
@@ -50,7 +53,7 @@ export function buildContradictionReport(options) {
|
|
|
50
53
|
const knownScripts = new Set();
|
|
51
54
|
for (const script of Object.keys(inspection.workspace.scripts ?? {}))
|
|
52
55
|
knownScripts.add(script);
|
|
53
|
-
const cliCommandNames =
|
|
56
|
+
const cliCommandNames = options.cliCommandNames ?? new Set();
|
|
54
57
|
for (const doc of docs) {
|
|
55
58
|
let body = '';
|
|
56
59
|
try {
|
|
@@ -91,20 +94,30 @@ export function buildContradictionReport(options) {
|
|
|
91
94
|
continue;
|
|
92
95
|
if (cleaned.startsWith('http://') || cleaned.startsWith('https://'))
|
|
93
96
|
continue;
|
|
94
|
-
|
|
95
|
-
|
|
97
|
+
// Strip a trailing source-location suffix (`:91`, `:91-125`, `#L91`,
|
|
98
|
+
// `#L91-L99`) — a `file.ts:91` reference is about file.ts, not a path
|
|
99
|
+
// literally named "file.ts:91".
|
|
100
|
+
const bare = (cleaned.startsWith('./') ? cleaned.slice(2) : cleaned).replace(/[:#]L?\d+(?:[-:]L?\d+)?$/i, '');
|
|
101
|
+
if (!bare)
|
|
96
102
|
continue;
|
|
97
|
-
seenOnLine.
|
|
98
|
-
|
|
99
|
-
|
|
103
|
+
if (seenOnLine.has(bare))
|
|
104
|
+
continue;
|
|
105
|
+
seenOnLine.add(bare);
|
|
106
|
+
// Resolve against the project root OR — for bare sibling links that
|
|
107
|
+
// aren't source-tree-prefixed (e.g. a `./a.md` link inside docs/) —
|
|
108
|
+
// relative to the referencing doc's directory.
|
|
109
|
+
const resolvesAtRoot = existsSync(nodePath.join(projectRoot, bare));
|
|
110
|
+
const resolvesDocRelative = !SOURCE_PREFIX_RE.test(bare) &&
|
|
111
|
+
existsSync(nodePath.resolve(nodePath.dirname(doc.abs), bare));
|
|
112
|
+
if (!resolvesAtRoot && !resolvesDocRelative) {
|
|
100
113
|
findings.push({
|
|
101
|
-
id: `missing-path:${doc.rel}:${i + 1}:${
|
|
114
|
+
id: `missing-path:${doc.rel}:${i + 1}:${bare}`,
|
|
102
115
|
kind: ContradictionKind.MissingPath,
|
|
103
116
|
severity: ContradictionSeverity.Warning,
|
|
104
|
-
message: `Doc references missing path \`${
|
|
117
|
+
message: `Doc references missing path \`${bare}\`.`,
|
|
105
118
|
source: doc.rel,
|
|
106
119
|
line: i + 1,
|
|
107
|
-
reference:
|
|
120
|
+
reference: bare,
|
|
108
121
|
suggestion: 'Update the doc or restore the file.',
|
|
109
122
|
reason: 'Doc-vs-tree consistency.',
|
|
110
123
|
});
|
|
@@ -153,7 +166,16 @@ export function buildContradictionReport(options) {
|
|
|
153
166
|
// npm/bun script references.
|
|
154
167
|
if ((head === 'bun' || head === 'npm' || head === 'pnpm' || head === 'yarn') && (next === 'run' || next === 'x')) {
|
|
155
168
|
const script = tokens[2];
|
|
156
|
-
|
|
169
|
+
// A real `bun run <script>` target is a bare script id, never a path.
|
|
170
|
+
// Skip path-shaped candidates (`bun run ../scripts/x.ts`) to avoid the
|
|
171
|
+
// false positive of treating a script-path as a missing package script.
|
|
172
|
+
const scriptLooksLikePath = !!script && (script.includes('/') || script.startsWith('.') || script.includes('.'));
|
|
173
|
+
if (script &&
|
|
174
|
+
!script.startsWith('-') &&
|
|
175
|
+
!scriptLooksLikePath &&
|
|
176
|
+
next === 'run' &&
|
|
177
|
+
knownScripts.size > 0 &&
|
|
178
|
+
!knownScripts.has(script)) {
|
|
157
179
|
findings.push({
|
|
158
180
|
id: `missing-command:${doc.rel}:${i + 1}:${script}`,
|
|
159
181
|
kind: ContradictionKind.MissingCommand,
|
|
@@ -264,6 +286,10 @@ function looksLikePath(s) {
|
|
|
264
286
|
return false;
|
|
265
287
|
if (s.startsWith('http'))
|
|
266
288
|
return false;
|
|
289
|
+
if (/^[a-z][\w.+-]*:/i.test(s))
|
|
290
|
+
return false; // URI scheme (file:, mailto:, …), not a tree path
|
|
291
|
+
if (/\/:[A-Za-z]/.test(s))
|
|
292
|
+
return false; // URL route param (`/api/:id/…`)
|
|
267
293
|
if (s.includes(' '))
|
|
268
294
|
return false;
|
|
269
295
|
if (/[<>{}]/.test(s))
|
|
@@ -288,30 +314,6 @@ function looksLikePath(s) {
|
|
|
288
314
|
return false;
|
|
289
315
|
return true;
|
|
290
316
|
}
|
|
291
|
-
function collectShrkCommandNames() {
|
|
292
|
-
// Hard-coded list of well-known top-level commands. Importing the CLI here
|
|
293
|
-
// would create a layering violation (inspector → cli) — instead we mirror
|
|
294
|
-
// the catalogue that `shrk commands` would print. Missing entries simply
|
|
295
|
-
// suppress contradiction findings for those commands, which is the safe
|
|
296
|
-
// failure mode.
|
|
297
|
-
return new Set([
|
|
298
|
-
'init', 'inspect', 'doctor', 'context', 'gen', 'apply', 'export', 'import',
|
|
299
|
-
'task', 'next', 'find', 'explain', 'check', 'watch', 'drift', 'graph',
|
|
300
|
-
'coverage', 'review', 'onboard', 'test', 'plan', 'session', 'dev', 'ask',
|
|
301
|
-
'mcp', 'version', 'quality', 'ci', 'commands', 'safety', 'infer', 'report',
|
|
302
|
-
'dashboard', 'bundle', 'impact', 'search', 'brief', 'demo', 'release',
|
|
303
|
-
'start-here', 'handoff', 'map', 'intent', 'orchestrate', 'simulate', 'view',
|
|
304
|
-
'recommend', 'risk', 'migration', 'contract', 'languages', 'help',
|
|
305
|
-
'memory', 'heal', 'agent', 'docs', 'examples', 'self', 'install',
|
|
306
|
-
'diagnostics', 'intelligence', 'architecture', 'decisions', 'compliance',
|
|
307
|
-
'policy', 'product', 'reposet', 'packs', 'upgrade', 'api', 'boundaries',
|
|
308
|
-
'repo', 'owners', 'ownership', 'runtime', 'constructs', 'playbooks',
|
|
309
|
-
'presets', 'pipelines', 'paths', 'rules', 'templates', 'knowledge',
|
|
310
|
-
'schemas', 'scaffolds', 'tests',
|
|
311
|
-
// Additions
|
|
312
|
-
'ingest', 'understand-task', 'validate-change', 'contradictions', 'generated', 'stability',
|
|
313
|
-
]);
|
|
314
|
-
}
|
|
315
317
|
export function renderContradictionReportText(report) {
|
|
316
318
|
const lines = [];
|
|
317
319
|
lines.push('=== Contradictions report ===');
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"git-helpers.d.ts","sourceRoot":"","sources":["../src/git-helpers.ts"],"names":[],"mappings":"AAIA,MAAM,WAAW,kBAAkB;IACjC,mEAAmE;IACnE,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,8CAA8C;IAC9C,MAAM,CAAC,EAAE,OAAO,CAAC;IACjB,gEAAgE;IAChE,eAAe,CAAC,EAAE,OAAO,CAAC;CAC3B;AAED,MAAM,WAAW,iBAAiB;IAChC,MAAM,EAAE,MAAM,GAAG,IAAI,CAAC;IACtB,IAAI,EAAE,MAAM,GAAG,IAAI,CAAC;IACpB,KAAK,EAAE,MAAM,CAAC;IACd,MAAM,EAAE,MAAM,CAAC;IACf,MAAM,EAAE,MAAM,CAAC;IACf,QAAQ,EAAE,MAAM,CAAC;IACjB,SAAS,EAAE,MAAM,CAAC;IAClB,SAAS,EAAE,MAAM,CAAC;IAClB,KAAK,EAAE,OAAO,CAAC;CAChB;AAWD,wBAAgB,SAAS,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAI9C;AAED,wBAAgB,UAAU,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI,CAKrD;AAED,wBAAgB,YAAY,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI,CAKvD;AAED,wBAAgB,eAAe,CAAC,GAAG,EAAE,MAAM,EAAE,IAAI,GAAE,kBAAuB,GAAG,MAAM,EAAE,
|
|
1
|
+
{"version":3,"file":"git-helpers.d.ts","sourceRoot":"","sources":["../src/git-helpers.ts"],"names":[],"mappings":"AAIA,MAAM,WAAW,kBAAkB;IACjC,mEAAmE;IACnE,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,8CAA8C;IAC9C,MAAM,CAAC,EAAE,OAAO,CAAC;IACjB,gEAAgE;IAChE,eAAe,CAAC,EAAE,OAAO,CAAC;CAC3B;AAED,MAAM,WAAW,iBAAiB;IAChC,MAAM,EAAE,MAAM,GAAG,IAAI,CAAC;IACtB,IAAI,EAAE,MAAM,GAAG,IAAI,CAAC;IACpB,KAAK,EAAE,MAAM,CAAC;IACd,MAAM,EAAE,MAAM,CAAC;IACf,MAAM,EAAE,MAAM,CAAC;IACf,QAAQ,EAAE,MAAM,CAAC;IACjB,SAAS,EAAE,MAAM,CAAC;IAClB,SAAS,EAAE,MAAM,CAAC;IAClB,KAAK,EAAE,OAAO,CAAC;CAChB;AAWD,wBAAgB,SAAS,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAI9C;AAED,wBAAgB,UAAU,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI,CAKrD;AAED,wBAAgB,YAAY,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI,CAKvD;AAED,wBAAgB,eAAe,CAAC,GAAG,EAAE,MAAM,EAAE,IAAI,GAAE,kBAAuB,GAAG,MAAM,EAAE,CAwBpF;AAED,wBAAgB,gBAAgB,CAAC,GAAG,EAAE,MAAM,GAAG,iBAAiB,CAyC/D;AAED,MAAM,WAAW,WAAW;IAC1B,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,QAAQ,CAAC,SAAS,EAAE,MAAM,CAAC;IAC3B,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAC;IACzB,QAAQ,CAAC,KAAK,EAAE,SAAS,MAAM,EAAE,CAAC;CACnC;AAED;;;;;GAKG;AACH,wBAAgB,iBAAiB,CAAC,GAAG,EAAE,MAAM,EAAE,IAAI,EAAE;IAAE,KAAK,EAAE,MAAM,CAAA;CAAE,GAAG,WAAW,EAAE,CA6BrF;AAED,wBAAgB,UAAU,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,EAAE,CAKjD"}
|
package/dist/git-helpers.js
CHANGED
|
@@ -41,12 +41,18 @@ export function getChangedFiles(cwd, opts = {}) {
|
|
|
41
41
|
const set = new Set(parseLines(a.stdout));
|
|
42
42
|
if (opts.includeWorktree && !opts.staged && !opts.since) {
|
|
43
43
|
// Include untracked + working-tree changes via `git status --porcelain`.
|
|
44
|
-
|
|
44
|
+
// `-uall` expands untracked directories to individual files (default
|
|
45
|
+
// `--porcelain` collapses them to a single `dir/` entry, which undercounts);
|
|
46
|
+
// `.gitignore` is still honored.
|
|
47
|
+
const s = runGit(cwd, ['status', '--porcelain', '-uall']);
|
|
45
48
|
if (s.ok) {
|
|
46
49
|
for (const line of s.stdout.split('\n')) {
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
+
// Strip the two-char XY status + leading space, then take the new path
|
|
51
|
+
// for rename/copy entries (`R old -> new`).
|
|
52
|
+
const raw = line.slice(3).trim();
|
|
53
|
+
const path = raw.includes(' -> ') ? raw.slice(raw.indexOf(' -> ') + 4).trim() : raw;
|
|
54
|
+
if (path)
|
|
55
|
+
set.add(path);
|
|
50
56
|
}
|
|
51
57
|
}
|
|
52
58
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"plan-review.d.ts","sourceRoot":"","sources":["../src/plan-review.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"plan-review.d.ts","sourceRoot":"","sources":["../src/plan-review.ts"],"names":[],"mappings":"AAeA,OAAO,KAAK,EAAE,qBAAqB,EAAE,MAAM,2BAA2B,CAAC;AAEvE,MAAM,WAAW,eAAe;IAC9B,8FAA8F;IAC9F,IAAI,EACA,QAAQ,GACR,QAAQ,GACR,QAAQ,GACR,cAAc,GACd,eAAe,GACf,SAAS,GACT,QAAQ,GACR,MAAM,GACN,UAAU,GACV,SAAS,CAAC;IACd,YAAY,EAAE,MAAM,CAAC;IACrB,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,4FAA4F;IAC5F,gBAAgB,CAAC,EAAE,OAAO,CAAC;CAC5B;AAED,MAAM,WAAW,8BAA8B;IAC7C,oDAAoD;IACpD,IAAI,EAAE,MAAM,CAAC;IACb,MAAM,EAAE,MAAM,CAAC;IACf,SAAS,EAAE,MAAM,CAAC;IAClB,eAAe,EAAE,MAAM,CAAC;IACxB,IAAI,EAAE,MAAM,CAAC;IACb,QAAQ,EAAE,MAAM,CAAC;IACjB,OAAO,EAAE,MAAM,CAAC;IAChB,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,WAAW,CAAC,EAAE,MAAM,CAAC;CACtB;AAED,MAAM,WAAW,mBAAmB;IAClC,IAAI,EAAE,eAAe,GAAG,eAAe,CAAC;IACxC,UAAU,EAAE,MAAM,CAAC;IACnB,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,MAAM,EAAE,MAAM,GAAG,QAAQ,CAAC;IAC1B,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,mFAAmF;IACnF,iBAAiB,EAAE,kBAAkB,GAAG,sCAAsC,CAAC;CAChF;AAED,MAAM,WAAW,iBAAiB;IAChC,MAAM,EAAE,MAAM,CAAC;IACf,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,gCAAgC;IAChC,KAAK,EAAE,eAAe,EAAE,CAAC;IACzB,6CAA6C;IAC7C,SAAS,EAAE,SAAS,mBAAmB,EAAE,CAAC;IAC1C,oDAAoD;IACpD,SAAS,EAAE,QAAQ,GAAG,SAAS,GAAG,SAAS,CAAC;IAC5C,gBAAgB,CAAC,EAAE,MAAM,CAAC;IAC1B,+DAA+D;IAC/D,aAAa,EAAE,SAAS,MAAM,EAAE,CAAC;IACjC,iEAAiE;IACjE,qBAAqB,EAAE,SAAS,MAAM,EAAE,CAAC;IACzC,8EAA8E;IAC9E,yBAAyB,EAAE,SAAS;QAClC,IAAI,EAAE,MAAM,CAAC;QACb,MAAM,EAAE,MAAM,CAAC;QACf,eAAe,EAAE,MAAM,CAAC;QACxB,IAAI,EAAE,MAAM,CAAC;QACb,QAAQ,EAAE,MAAM,CAAC;KAClB,EAAE,CAAC;IACJ;;;;OAIG;IACH,8BAA8B,EAAE,SAAS,8BAA8B,EAAE,CAAC;IAC1E,4DAA4D;IAC5D,oBAAoB,EAAE,SAAS,MAAM,EAAE,CAAC;IACxC,qBAAqB,EAAE,MAAM,CAAC;CAC/B;AAED,wBAAgB,eAAe,CAC7B,UAAU,EAAE,qBAAqB,EACjC,QAAQ,EAAE,MAAM,GACf,iBAAiB,CAkLnB"}
|
package/dist/plan-review.js
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { readFileSync } from 'node:fs';
|
|
2
2
|
import { evaluateBoundaries, loadTsconfigPaths, scanImports, } from '@shrkcrft/boundaries';
|
|
3
3
|
import { checkFolderOpSafety, FolderOpSafety, planGeneration, verifyPlan, } from '@shrkcrft/generator';
|
|
4
|
+
import { matchAffectedConventions } from '@shrkcrft/paths';
|
|
4
5
|
export function reviewSavedPlan(inspection, planPath) {
|
|
5
6
|
const raw = readFileSync(planPath, 'utf8');
|
|
6
7
|
const plan = JSON.parse(raw);
|
|
@@ -64,16 +65,10 @@ export function reviewSavedPlan(inspection, planPath) {
|
|
|
64
65
|
signatureMessage = 'verified';
|
|
65
66
|
}
|
|
66
67
|
}
|
|
67
|
-
// Affected paths
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
segments.add(seg.toLowerCase());
|
|
72
|
-
}
|
|
73
|
-
const affectedPaths = inspection.pathService
|
|
74
|
-
.list()
|
|
75
|
-
.filter((p) => [...segments].some((s) => (p.title + ' ' + p.content).toLowerCase().includes(s)))
|
|
76
|
-
.map((p) => p.id);
|
|
68
|
+
// Affected paths: conventions the plan's files structurally fall under
|
|
69
|
+
// (directory-prefix match against each convention's metadata.path), not a
|
|
70
|
+
// free-text substring of the description (which matched nearly the whole set).
|
|
71
|
+
const affectedPaths = matchAffectedConventions(inspection.pathService.list(), files.map((f) => f.relativePath)).map((p) => p.id);
|
|
77
72
|
// Missing-tests heuristic.
|
|
78
73
|
const missingTestsHeuristic = [];
|
|
79
74
|
const allPaths = new Set(files.map((f) => f.relativePath));
|
|
@@ -36,6 +36,12 @@ export interface IRegistryLifecycleReport {
|
|
|
36
36
|
registersFound: number;
|
|
37
37
|
matchedPairs: ReadonlyArray<IRegistryPair>;
|
|
38
38
|
missingRemovers: ReadonlyArray<IRegistryMissingRemover>;
|
|
39
|
+
/**
|
|
40
|
+
* `register*` declarations in a file with NO teardown-shaped API — treated as
|
|
41
|
+
* one-shot / bootstrap registrations that legitimately need no remover. Kept
|
|
42
|
+
* out of `missingRemovers` so the check isn't a wall of false positives.
|
|
43
|
+
*/
|
|
44
|
+
oneShotBootstrap: ReadonlyArray<IRegistryIgnored>;
|
|
39
45
|
ignored: ReadonlyArray<IRegistryIgnored>;
|
|
40
46
|
recommendations: ReadonlyArray<string>;
|
|
41
47
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"registry-lifecycle.d.ts","sourceRoot":"","sources":["../src/registry-lifecycle.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AAKH,MAAM,WAAW,aAAa;IAC5B,YAAY,EAAE,MAAM,CAAC;IACrB,WAAW,EAAE,MAAM,CAAC;IACpB,IAAI,EAAE,MAAM,CAAC;IACb,YAAY,EAAE,MAAM,CAAC;IACrB,WAAW,EAAE,MAAM,CAAC;CACrB;AAED,MAAM,WAAW,uBAAuB;IACtC,YAAY,EAAE,MAAM,CAAC;IACrB,oBAAoB,EAAE,aAAa,CAAC,MAAM,CAAC,CAAC;IAC5C,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,MAAM,CAAC;IACb,UAAU,EAAE,MAAM,CAAC;CACpB;AAED,MAAM,WAAW,gBAAgB;IAC/B,YAAY,EAAE,MAAM,CAAC;IACrB,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,MAAM,CAAC;IACb,MAAM,EAAE,MAAM,CAAC;IACf,SAAS,CAAC,EAAE,MAAM,CAAC;CACpB;AAED,MAAM,WAAW,wBAAwB;IACvC,MAAM,EAAE,kCAAkC,CAAC;IAC3C,YAAY,EAAE,MAAM,CAAC;IACrB,cAAc,EAAE,MAAM,CAAC;IACvB,YAAY,EAAE,aAAa,CAAC,aAAa,CAAC,CAAC;IAC3C,eAAe,EAAE,aAAa,CAAC,uBAAuB,CAAC,CAAC;IACxD,OAAO,EAAE,aAAa,CAAC,gBAAgB,CAAC,CAAC;IACzC,eAAe,EAAE,aAAa,CAAC,MAAM,CAAC,CAAC;CACxC;
|
|
1
|
+
{"version":3,"file":"registry-lifecycle.d.ts","sourceRoot":"","sources":["../src/registry-lifecycle.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AAKH,MAAM,WAAW,aAAa;IAC5B,YAAY,EAAE,MAAM,CAAC;IACrB,WAAW,EAAE,MAAM,CAAC;IACpB,IAAI,EAAE,MAAM,CAAC;IACb,YAAY,EAAE,MAAM,CAAC;IACrB,WAAW,EAAE,MAAM,CAAC;CACrB;AAED,MAAM,WAAW,uBAAuB;IACtC,YAAY,EAAE,MAAM,CAAC;IACrB,oBAAoB,EAAE,aAAa,CAAC,MAAM,CAAC,CAAC;IAC5C,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,MAAM,CAAC;IACb,UAAU,EAAE,MAAM,CAAC;CACpB;AAED,MAAM,WAAW,gBAAgB;IAC/B,YAAY,EAAE,MAAM,CAAC;IACrB,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,MAAM,CAAC;IACb,MAAM,EAAE,MAAM,CAAC;IACf,SAAS,CAAC,EAAE,MAAM,CAAC;CACpB;AAED,MAAM,WAAW,wBAAwB;IACvC,MAAM,EAAE,kCAAkC,CAAC;IAC3C,YAAY,EAAE,MAAM,CAAC;IACrB,cAAc,EAAE,MAAM,CAAC;IACvB,YAAY,EAAE,aAAa,CAAC,aAAa,CAAC,CAAC;IAC3C,eAAe,EAAE,aAAa,CAAC,uBAAuB,CAAC,CAAC;IACxD;;;;OAIG;IACH,gBAAgB,EAAE,aAAa,CAAC,gBAAgB,CAAC,CAAC;IAClD,OAAO,EAAE,aAAa,CAAC,gBAAgB,CAAC,CAAC;IACzC,eAAe,EAAE,aAAa,CAAC,MAAM,CAAC,CAAC;CACxC;AAuLD,wBAAgB,4BAA4B,CAAC,KAAK,EAAE;IAClD,WAAW,EAAE,MAAM,CAAC;IACpB,KAAK,CAAC,EAAE,MAAM,CAAC;CAChB,GAAG,wBAAwB,CAsF3B;AAED,wBAAgB,iCAAiC,CAAC,MAAM,EAAE,wBAAwB,GAAG,MAAM,CA8B1F"}
|
|
@@ -59,11 +59,111 @@ function walk(dir, projectRoot, out) {
|
|
|
59
59
|
const REGISTER_PATTERNS = Object.freeze([
|
|
60
60
|
// export function registerX(
|
|
61
61
|
/(?:export\s+)?(?:async\s+)?function\s+(register[A-Z]\w*)\s*\(/g,
|
|
62
|
-
//
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
62
|
+
// class method DECLARATION: requires a body `{` or return-type `:` after the
|
|
63
|
+
// params, which a bare call site (`registry.registerX(...)`) never has.
|
|
64
|
+
/(?:^|\n)[\t ]*(?:public|private|protected)?\s*(?:static\s+)?(?:async\s+)?(register[A-Z]\w*)\s*\([^;]*?\)\s*[:{]/g,
|
|
65
|
+
// assigned arrow / function expression: `registerX = (…) =>` / `registerX = function`
|
|
66
|
+
/\b(register[A-Z]\w*)\s*=\s*(?:async\s+)?(?:function\b|\([^)]*\)\s*(?::[^=]*)?=>)/g,
|
|
66
67
|
]);
|
|
68
|
+
// Accumulation of removable per-entry state — a registry that ADDS entries one
|
|
69
|
+
// at a time plausibly needs a way to remove them.
|
|
70
|
+
const ACCUMULATION_RE = /\.(?:set|add|push)\s*\(|\[[^\]]+\]\s*=[^=]/;
|
|
71
|
+
// A teardown-shaped API somewhere in the file — evidence the file is in the
|
|
72
|
+
// business of removing things, so a missing per-register remover is suspicious.
|
|
73
|
+
const TEARDOWN_RE = /\b(?:remove|unregister|clear|dispose|unsubscribe)\w*\s*\(|\boff\s*\(/i;
|
|
74
|
+
/**
|
|
75
|
+
* Blank out comments and string / template-literal bodies (preserving newlines
|
|
76
|
+
* so line numbers stay accurate) before scanning for `register*` declarations.
|
|
77
|
+
* Deterministic char-scan — no TS parser, consistent with this module's no-AST
|
|
78
|
+
* posture. Stops `register*` mentions inside comments / strings / docs from
|
|
79
|
+
* being counted as code.
|
|
80
|
+
*/
|
|
81
|
+
function stripCommentsAndLiterals(content) {
|
|
82
|
+
const out = [];
|
|
83
|
+
const n = content.length;
|
|
84
|
+
let state = 'code';
|
|
85
|
+
const blank = (ch) => (ch === '\n' ? '\n' : ' ');
|
|
86
|
+
let i = 0;
|
|
87
|
+
while (i < n) {
|
|
88
|
+
const ch = content[i];
|
|
89
|
+
const next = content[i + 1];
|
|
90
|
+
if (state === 'code') {
|
|
91
|
+
if (ch === '/' && next === '/') {
|
|
92
|
+
state = 'line';
|
|
93
|
+
out.push(' ');
|
|
94
|
+
i += 2;
|
|
95
|
+
continue;
|
|
96
|
+
}
|
|
97
|
+
if (ch === '/' && next === '*') {
|
|
98
|
+
state = 'block';
|
|
99
|
+
out.push(' ');
|
|
100
|
+
i += 2;
|
|
101
|
+
continue;
|
|
102
|
+
}
|
|
103
|
+
if (ch === "'") {
|
|
104
|
+
state = 'sq';
|
|
105
|
+
out.push(' ');
|
|
106
|
+
i += 1;
|
|
107
|
+
continue;
|
|
108
|
+
}
|
|
109
|
+
if (ch === '"') {
|
|
110
|
+
state = 'dq';
|
|
111
|
+
out.push(' ');
|
|
112
|
+
i += 1;
|
|
113
|
+
continue;
|
|
114
|
+
}
|
|
115
|
+
if (ch === '`') {
|
|
116
|
+
state = 'tpl';
|
|
117
|
+
out.push(' ');
|
|
118
|
+
i += 1;
|
|
119
|
+
continue;
|
|
120
|
+
}
|
|
121
|
+
out.push(ch);
|
|
122
|
+
i += 1;
|
|
123
|
+
continue;
|
|
124
|
+
}
|
|
125
|
+
if (state === 'line') {
|
|
126
|
+
if (ch === '\n') {
|
|
127
|
+
state = 'code';
|
|
128
|
+
out.push('\n');
|
|
129
|
+
i += 1;
|
|
130
|
+
continue;
|
|
131
|
+
}
|
|
132
|
+
out.push(blank(ch));
|
|
133
|
+
i += 1;
|
|
134
|
+
continue;
|
|
135
|
+
}
|
|
136
|
+
if (state === 'block') {
|
|
137
|
+
if (ch === '*' && next === '/') {
|
|
138
|
+
state = 'code';
|
|
139
|
+
out.push(' ');
|
|
140
|
+
i += 2;
|
|
141
|
+
continue;
|
|
142
|
+
}
|
|
143
|
+
out.push(blank(ch));
|
|
144
|
+
i += 1;
|
|
145
|
+
continue;
|
|
146
|
+
}
|
|
147
|
+
// string / template literal body
|
|
148
|
+
const quote = state === 'sq' ? "'" : state === 'dq' ? '"' : '`';
|
|
149
|
+
if (ch === '\\') {
|
|
150
|
+
out.push(' ');
|
|
151
|
+
out.push(next === undefined ? '' : blank(next));
|
|
152
|
+
i += 2;
|
|
153
|
+
continue;
|
|
154
|
+
}
|
|
155
|
+
if (ch === quote) {
|
|
156
|
+
state = 'code';
|
|
157
|
+
out.push(' ');
|
|
158
|
+
i += 1;
|
|
159
|
+
continue;
|
|
160
|
+
}
|
|
161
|
+
out.push(blank(ch));
|
|
162
|
+
i += 1;
|
|
163
|
+
continue;
|
|
164
|
+
}
|
|
165
|
+
return out.join('');
|
|
166
|
+
}
|
|
67
167
|
function findRegistersInFile(content) {
|
|
68
168
|
const out = [];
|
|
69
169
|
const seen = new Set();
|
|
@@ -95,10 +195,17 @@ function findIgnoreAnnotations(content, registerName) {
|
|
|
95
195
|
return { ignore: false };
|
|
96
196
|
}
|
|
97
197
|
function expectedRemoverNames(registerName) {
|
|
98
|
-
// registerX → removeX / unregisterX / clearX
|
|
99
|
-
// registerXByScope → removeXByScope /
|
|
198
|
+
// registerX → removeX / unregisterX / clearX / disposeX / unsubscribeX / Xoff
|
|
199
|
+
// registerXByScope → removeXByScope / … (stem carries the scope suffix)
|
|
100
200
|
const stem = registerName.slice('register'.length);
|
|
101
|
-
return [
|
|
201
|
+
return [
|
|
202
|
+
`remove${stem}`,
|
|
203
|
+
`unregister${stem}`,
|
|
204
|
+
`clear${stem}`,
|
|
205
|
+
`dispose${stem}`,
|
|
206
|
+
`unsubscribe${stem}`,
|
|
207
|
+
`${stem}Off`,
|
|
208
|
+
];
|
|
102
209
|
}
|
|
103
210
|
function findRemoverInContent(content, candidates) {
|
|
104
211
|
for (const name of candidates) {
|
|
@@ -119,6 +226,7 @@ export function buildRegistryLifecycleReport(input) {
|
|
|
119
226
|
const scanFiles = files.slice(0, limit);
|
|
120
227
|
const matchedPairs = [];
|
|
121
228
|
const missingRemovers = [];
|
|
229
|
+
const oneShotBootstrap = [];
|
|
122
230
|
const ignored = [];
|
|
123
231
|
let registersFound = 0;
|
|
124
232
|
for (const file of scanFiles) {
|
|
@@ -131,7 +239,15 @@ export function buildRegistryLifecycleReport(input) {
|
|
|
131
239
|
}
|
|
132
240
|
if (isGeneratedFile(file, content))
|
|
133
241
|
continue;
|
|
134
|
-
|
|
242
|
+
// Scan declarations on code with comments/strings blanked out; keep the raw
|
|
243
|
+
// content only for the comment-based @shrkcrft annotations.
|
|
244
|
+
const code = stripCommentsAndLiterals(content);
|
|
245
|
+
const registers = findRegistersInFile(code);
|
|
246
|
+
// Per-file lifecycle evidence: only a file that BOTH accumulates removable
|
|
247
|
+
// state AND has a teardown-shaped API plausibly owes a per-register remover.
|
|
248
|
+
const hasAccumulation = ACCUMULATION_RE.test(code);
|
|
249
|
+
const hasTeardown = TEARDOWN_RE.test(code);
|
|
250
|
+
const ownsLifecycle = hasAccumulation && hasTeardown;
|
|
135
251
|
for (const reg of registers) {
|
|
136
252
|
registersFound += 1;
|
|
137
253
|
const ann = findIgnoreAnnotations(content, reg.name);
|
|
@@ -146,7 +262,7 @@ export function buildRegistryLifecycleReport(input) {
|
|
|
146
262
|
continue;
|
|
147
263
|
}
|
|
148
264
|
const candidates = expectedRemoverNames(reg.name);
|
|
149
|
-
const remover = findRemoverInContent(
|
|
265
|
+
const remover = findRemoverInContent(code, candidates);
|
|
150
266
|
if (remover) {
|
|
151
267
|
matchedPairs.push({
|
|
152
268
|
registerName: reg.name,
|
|
@@ -156,7 +272,7 @@ export function buildRegistryLifecycleReport(input) {
|
|
|
156
272
|
removerLine: remover.line,
|
|
157
273
|
});
|
|
158
274
|
}
|
|
159
|
-
else {
|
|
275
|
+
else if (ownsLifecycle) {
|
|
160
276
|
missingRemovers.push({
|
|
161
277
|
registerName: reg.name,
|
|
162
278
|
expectedRemoverNames: candidates,
|
|
@@ -165,6 +281,15 @@ export function buildRegistryLifecycleReport(input) {
|
|
|
165
281
|
suggestion: `Add ${candidates[0]}() / ${candidates[1]}() / ${candidates[2]}() — or annotate with \`@shrkcrft lifecycle-ignore <reason>\` / \`@shrkcrft lifecycle-managed-by <name>\` if cleanup is owned elsewhere.`,
|
|
166
282
|
});
|
|
167
283
|
}
|
|
284
|
+
else {
|
|
285
|
+
// No teardown-shaped API in the file → one-shot / bootstrap registration.
|
|
286
|
+
oneShotBootstrap.push({
|
|
287
|
+
registerName: reg.name,
|
|
288
|
+
file: relative(projectRoot, file),
|
|
289
|
+
line: reg.line,
|
|
290
|
+
reason: 'no teardown-shaped API in file — treated as one-shot bootstrap',
|
|
291
|
+
});
|
|
292
|
+
}
|
|
168
293
|
}
|
|
169
294
|
}
|
|
170
295
|
const recommendations = [];
|
|
@@ -177,6 +302,7 @@ export function buildRegistryLifecycleReport(input) {
|
|
|
177
302
|
registersFound,
|
|
178
303
|
matchedPairs,
|
|
179
304
|
missingRemovers,
|
|
305
|
+
oneShotBootstrap,
|
|
180
306
|
ignored,
|
|
181
307
|
recommendations,
|
|
182
308
|
};
|
|
@@ -188,6 +314,7 @@ export function renderRegistryLifecycleReportText(report) {
|
|
|
188
314
|
lines.push(` registers found ${report.registersFound}`);
|
|
189
315
|
lines.push(` matched pairs ${report.matchedPairs.length}`);
|
|
190
316
|
lines.push(` missing removers ${report.missingRemovers.length}`);
|
|
317
|
+
lines.push(` one-shot bootstrap ${report.oneShotBootstrap.length}`);
|
|
191
318
|
lines.push(` ignored ${report.ignored.length}`);
|
|
192
319
|
lines.push('');
|
|
193
320
|
if (report.missingRemovers.length > 0) {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"review-packet.d.ts","sourceRoot":"","sources":["../src/review-packet.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"review-packet.d.ts","sourceRoot":"","sources":["../src/review-packet.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,qBAAqB,EAAE,MAAM,2BAA2B,CAAC;AAIvE,MAAM,WAAW,aAAa;IAC5B,YAAY,EAAE,SAAS,MAAM,EAAE,CAAC;IAChC,kEAAkE;IAClE,aAAa,EAAE,SAAS,MAAM,EAAE,CAAC;IACjC,8CAA8C;IAC9C,aAAa,EAAE,SAAS;QAAE,EAAE,EAAE,MAAM,CAAC;QAAC,KAAK,EAAE,MAAM,CAAC;QAAC,MAAM,EAAE,MAAM,CAAA;KAAE,EAAE,CAAC;IACxE,2CAA2C;IAC3C,iBAAiB,EAAE,SAAS;QAAE,EAAE,EAAE,MAAM,CAAC;QAAC,IAAI,EAAE,MAAM,CAAA;KAAE,EAAE,CAAC;IAC3D,iBAAiB,EAAE,SAAS;QAAE,EAAE,EAAE,MAAM,CAAC;QAAC,KAAK,EAAE,MAAM,CAAA;KAAE,EAAE,CAAC;IAC5D,2DAA2D;IAC3D,kBAAkB,EAAE,SAAS;QAC3B,MAAM,EAAE,MAAM,CAAC;QACf,IAAI,EAAE,MAAM,CAAC;QACb,eAAe,EAAE,MAAM,CAAC;QACxB,IAAI,EAAE,MAAM,CAAC;QACb,QAAQ,EAAE,MAAM,CAAC;QACjB,OAAO,EAAE,MAAM,CAAC;KACjB,EAAE,CAAC;IACJ,+DAA+D;IAC/D,qBAAqB,EAAE,SAAS,MAAM,EAAE,CAAC;IACzC,4DAA4D;IAC5D,oBAAoB,EAAE,SAAS,MAAM,EAAE,CAAC;IACxC,mEAAmE;IACnE,oBAAoB,EAAE,MAAM,CAAC;CAC9B;AAED,MAAM,WAAW,yBAAyB;IACxC;;;;;OAKG;IACH,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,MAAM,CAAC,EAAE,OAAO,CAAC;IACjB,KAAK,CAAC,EAAE,SAAS,MAAM,EAAE,CAAC;CAC3B;AAyCD,wBAAgB,iBAAiB,CAC/B,UAAU,EAAE,qBAAqB,EACjC,OAAO,GAAE,yBAA8B,GACtC,aAAa,CA+Ef"}
|
package/dist/review-packet.js
CHANGED
|
@@ -1,5 +1,7 @@
|
|
|
1
1
|
import { spawnSync } from 'node:child_process';
|
|
2
2
|
import { evaluateBoundaries, loadTsconfigPaths, scanImports } from '@shrkcrft/boundaries';
|
|
3
|
+
import { matchAffectedConventions } from '@shrkcrft/paths';
|
|
4
|
+
import { resolveVerificationCommands } from "./resolve-verification-commands.js";
|
|
3
5
|
import { rankAll } from "./task-ranker.js";
|
|
4
6
|
function gitDiffFiles(cwd, opts) {
|
|
5
7
|
if (opts.files && opts.files.length > 0)
|
|
@@ -50,17 +52,10 @@ export function buildReviewPacket(inspection, options = {}) {
|
|
|
50
52
|
const changedFiles = gitDiffFiles(inspection.projectRoot, options);
|
|
51
53
|
const pseudoTask = buildPseudoTask(changedFiles);
|
|
52
54
|
const ranking = rankAll(inspection, pseudoTask, 8);
|
|
53
|
-
// Affected paths:
|
|
54
|
-
//
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
for (const seg of f.split('/'))
|
|
58
|
-
segments.add(seg.toLowerCase());
|
|
59
|
-
}
|
|
60
|
-
const affectedPaths = inspection.pathService
|
|
61
|
-
.list()
|
|
62
|
-
.filter((p) => [...segments].some((s) => (p.title + ' ' + p.content).toLowerCase().includes(s)))
|
|
63
|
-
.map((p) => p.id);
|
|
55
|
+
// Affected paths: conventions the changed files structurally fall under
|
|
56
|
+
// (directory-prefix match against each convention's metadata.path), not a
|
|
57
|
+
// free-text substring of the description.
|
|
58
|
+
const affectedPaths = matchAffectedConventions(inspection.pathService.list(), changedFiles).map((p) => p.id);
|
|
64
59
|
// Boundary violations restricted to changed files.
|
|
65
60
|
let boundaryViolations = [];
|
|
66
61
|
if (inspection.boundaryRegistry.size() > 0 && changedFiles.length > 0) {
|
|
@@ -81,12 +76,14 @@ export function buildReviewPacket(inspection, options = {}) {
|
|
|
81
76
|
message: v.message,
|
|
82
77
|
}));
|
|
83
78
|
}
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
79
|
+
// Verification: prefer the project's configured verificationCommands (resolved
|
|
80
|
+
// from config + matched pipelines); fall back to the generic tsc/test pair only
|
|
81
|
+
// when nothing is configured. SharkCraft's own meta-checks stay as a prefix.
|
|
82
|
+
const resolvedGates = resolveVerificationCommands(inspection, {
|
|
83
|
+
pipelineIds: ranking.pipelines.slice(0, 3).map((p) => p.item.id),
|
|
84
|
+
knowledgeDefaults: ['bun x tsc -p tsconfig.base.json --noEmit', 'bun test'],
|
|
85
|
+
});
|
|
86
|
+
const verificationCommands = unique(['shrk doctor', 'shrk check boundaries', ...resolvedGates]);
|
|
90
87
|
const reviewerInstructions = [
|
|
91
88
|
`# AI reviewer instructions`,
|
|
92
89
|
``,
|
package/dist/why-file.js
CHANGED
|
@@ -23,7 +23,7 @@ export function buildWhyReport(input) {
|
|
|
23
23
|
const inferredPackage = inferPackage(target.relativePath);
|
|
24
24
|
const inferredLayer = inferLayer(target.relativePath);
|
|
25
25
|
const pathConventions = matchPathConventions(input.inspection, target);
|
|
26
|
-
const rules = matchRules(input.inspection, target, limit);
|
|
26
|
+
const rules = matchRules(input.inspection, target, limit, inferredPackage, inferredLayer);
|
|
27
27
|
const boundaries = matchBoundaries(input.inspection, target);
|
|
28
28
|
const knowledge = matchKnowledge(input.inspection, target, limit);
|
|
29
29
|
const suggestedNext = buildSuggestions(target, rules, knowledge);
|
|
@@ -78,14 +78,20 @@ function inferLayer(relPath) {
|
|
|
78
78
|
return segments[1];
|
|
79
79
|
return undefined;
|
|
80
80
|
}
|
|
81
|
+
/** Does `targetRel` equal, or live under, the canonical directory/file path? */
|
|
82
|
+
function pathCovers(targetRel, canonical) {
|
|
83
|
+
const normalized = canonical.replace(/^\.\//, '').replace(/\/+$/, '');
|
|
84
|
+
if (!normalized)
|
|
85
|
+
return false;
|
|
86
|
+
return targetRel === normalized || targetRel.startsWith(`${normalized}/`);
|
|
87
|
+
}
|
|
81
88
|
function matchPathConventions(inspection, target) {
|
|
82
89
|
const out = [];
|
|
83
90
|
for (const p of inspection.pathService.list()) {
|
|
84
91
|
const canonical = p.metadata?.path ?? '';
|
|
85
92
|
if (!canonical)
|
|
86
93
|
continue;
|
|
87
|
-
|
|
88
|
-
if (target.relativePath === normalized || target.relativePath.startsWith(normalized.endsWith('/') ? normalized : `${normalized}/`)) {
|
|
94
|
+
if (pathCovers(target.relativePath, canonical)) {
|
|
89
95
|
out.push({
|
|
90
96
|
id: p.id,
|
|
91
97
|
title: p.title,
|
|
@@ -96,30 +102,74 @@ function matchPathConventions(inspection, target) {
|
|
|
96
102
|
}
|
|
97
103
|
return out;
|
|
98
104
|
}
|
|
99
|
-
|
|
100
|
-
|
|
105
|
+
/**
|
|
106
|
+
* Precise PATH evidence that a rule applies to a file — not topical token
|
|
107
|
+
* overlap (scope/tags/appliesWhen are free-form labels, so the old
|
|
108
|
+
* intersection attached nearly every rule to every file). Priority order:
|
|
109
|
+
* explicit file/dir references → path-glob scope/tag → package reference →
|
|
110
|
+
* scope/tag equal to the inferred package or layer.
|
|
111
|
+
*/
|
|
112
|
+
function ruleReasonForFile(r, target, inferredPackage, inferredLayer) {
|
|
113
|
+
const rel = target.relativePath;
|
|
114
|
+
// 1. Explicit file/directory references that cover the target.
|
|
115
|
+
for (const ref of r.references ?? []) {
|
|
116
|
+
const p = (ref.path ?? '').replace(/^\.\//, '');
|
|
117
|
+
if ((ref.kind === 'file' || ref.kind === 'directory') && p && pathCovers(rel, p)) {
|
|
118
|
+
return ref.kind === 'directory' ? `directory reference ${p}` : `file reference ${p}`;
|
|
119
|
+
}
|
|
120
|
+
}
|
|
121
|
+
// 1b. Anchors that point at a covering path.
|
|
122
|
+
for (const a of r.anchors ?? []) {
|
|
123
|
+
const p = (a.path ?? '').replace(/^\.\//, '');
|
|
124
|
+
if (p && pathCovers(rel, p))
|
|
125
|
+
return `anchor path ${p}`;
|
|
126
|
+
}
|
|
127
|
+
// 2. Scope/tag values that are themselves path globs matching the target.
|
|
128
|
+
const pathish = [...(r.scope ?? []), ...(r.tags ?? [])].filter((s) => /[/*?[]/.test(s));
|
|
129
|
+
if (pathish.length > 0) {
|
|
130
|
+
const hit = pathish.find((g) => matchesAny(rel, [g]));
|
|
131
|
+
if (hit)
|
|
132
|
+
return `path pattern ${hit}`;
|
|
133
|
+
}
|
|
134
|
+
// 3. Package reference / scope-or-tag equal to the inferred package or layer.
|
|
135
|
+
const labels = [...(r.scope ?? []), ...(r.tags ?? [])];
|
|
136
|
+
if (inferredPackage) {
|
|
137
|
+
for (const ref of r.references ?? []) {
|
|
138
|
+
if (ref.kind === 'package' && ref.id && samePath(ref.id, inferredPackage)) {
|
|
139
|
+
return `package reference ${ref.id}`;
|
|
140
|
+
}
|
|
141
|
+
}
|
|
142
|
+
if (labels.some((l) => samePath(l, inferredPackage)))
|
|
143
|
+
return `scoped to package ${inferredPackage}`;
|
|
144
|
+
}
|
|
145
|
+
if (inferredLayer && labels.some((l) => l.toLowerCase() === inferredLayer.toLowerCase())) {
|
|
146
|
+
return `scoped to layer ${inferredLayer}`;
|
|
147
|
+
}
|
|
148
|
+
return undefined;
|
|
149
|
+
}
|
|
150
|
+
function samePath(a, b) {
|
|
151
|
+
const n = (s) => s.replace(/^\.?\/+/, '').replace(/\/+$/, '').toLowerCase();
|
|
152
|
+
return n(a) === n(b);
|
|
153
|
+
}
|
|
154
|
+
function matchRules(inspection, target, limit, inferredPackage, inferredLayer) {
|
|
101
155
|
const out = [];
|
|
102
156
|
for (const rule of inspection.ruleService.list()) {
|
|
103
157
|
const r = rule;
|
|
104
|
-
const
|
|
105
|
-
|
|
106
|
-
const appliesWhen = r.appliesWhen ?? [];
|
|
107
|
-
const allTokens = new Set([...scope, ...tags, ...appliesWhen].map((t) => t.toLowerCase()));
|
|
108
|
-
const hits = tokens.filter((t) => allTokens.has(t.toLowerCase()));
|
|
109
|
-
if (hits.length === 0)
|
|
158
|
+
const reason = ruleReasonForFile(r, target, inferredPackage, inferredLayer);
|
|
159
|
+
if (!reason)
|
|
110
160
|
continue;
|
|
111
161
|
out.push({
|
|
112
162
|
id: r.id,
|
|
113
163
|
title: r.title,
|
|
114
164
|
priority: r.priority ?? 'medium',
|
|
115
|
-
scope,
|
|
116
|
-
tags,
|
|
117
|
-
appliesWhen,
|
|
118
|
-
reason
|
|
165
|
+
scope: r.scope ?? [],
|
|
166
|
+
tags: r.tags ?? [],
|
|
167
|
+
appliesWhen: r.appliesWhen ?? [],
|
|
168
|
+
reason,
|
|
119
169
|
...sourceField(inspection, r.id),
|
|
120
170
|
});
|
|
121
171
|
}
|
|
122
|
-
// Sort by priority weight desc
|
|
172
|
+
// Sort by priority weight desc (stable for equal weights).
|
|
123
173
|
const weight = { critical: 4, high: 3, medium: 2, low: 1 };
|
|
124
174
|
out.sort((a, b) => (weight[b.priority] ?? 2) - (weight[a.priority] ?? 2));
|
|
125
175
|
return out.slice(0, limit);
|
|
@@ -183,12 +233,6 @@ function buildSuggestions(target, rules, knowledge) {
|
|
|
183
233
|
out.push(`shrk impact "${target.relativePath}"`);
|
|
184
234
|
return out;
|
|
185
235
|
}
|
|
186
|
-
function pathTokens(relPath) {
|
|
187
|
-
return relPath
|
|
188
|
-
.replace(/\.[^./]+$/, '') // drop extension
|
|
189
|
-
.split(/[/\\.\-_]/)
|
|
190
|
-
.filter((t) => t.length > 0);
|
|
191
|
-
}
|
|
192
236
|
function sourceField(inspection, id) {
|
|
193
237
|
let map;
|
|
194
238
|
if (inspection && 'entrySources' in inspection) {
|
package/package.json
CHANGED
|
@@ -1,12 +1,12 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@shrkcrft/inspector",
|
|
3
|
-
"version": "0.1.0-alpha.
|
|
3
|
+
"version": "0.1.0-alpha.20",
|
|
4
4
|
"description": "SharkCraft inspector: project overview, doctor checks, AI-agent instructions.",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"author": "SharkCraft contributors",
|
|
7
7
|
"type": "module",
|
|
8
8
|
"main": "./dist/index.js",
|
|
9
|
-
"types": "./dist/index.d.
|
|
9
|
+
"types": "./dist/index.d.ts",
|
|
10
10
|
"exports": {
|
|
11
11
|
".": {
|
|
12
12
|
"types": "./dist/index.d.ts",
|
|
@@ -42,22 +42,22 @@
|
|
|
42
42
|
"typecheck": "tsc --noEmit -p tsconfig.json"
|
|
43
43
|
},
|
|
44
44
|
"dependencies": {
|
|
45
|
-
"@shrkcrft/core": "^0.1.0-alpha.
|
|
46
|
-
"@shrkcrft/config": "^0.1.0-alpha.
|
|
47
|
-
"@shrkcrft/workspace": "^0.1.0-alpha.
|
|
48
|
-
"@shrkcrft/knowledge": "^0.1.0-alpha.
|
|
49
|
-
"@shrkcrft/rules": "^0.1.0-alpha.
|
|
50
|
-
"@shrkcrft/paths": "^0.1.0-alpha.
|
|
51
|
-
"@shrkcrft/templates": "^0.1.0-alpha.
|
|
52
|
-
"@shrkcrft/context": "^0.1.0-alpha.
|
|
53
|
-
"@shrkcrft/pipelines": "^0.1.0-alpha.
|
|
54
|
-
"@shrkcrft/packs": "^0.1.0-alpha.
|
|
55
|
-
"@shrkcrft/presets": "^0.1.0-alpha.
|
|
56
|
-
"@shrkcrft/boundaries": "^0.1.0-alpha.
|
|
57
|
-
"@shrkcrft/generator": "^0.1.0-alpha.
|
|
58
|
-
"@shrkcrft/importer": "^0.1.0-alpha.
|
|
59
|
-
"@shrkcrft/plugin-api": "^0.1.0-alpha.
|
|
60
|
-
"@shrkcrft/dashboard-api": "^0.1.0-alpha.
|
|
45
|
+
"@shrkcrft/core": "^0.1.0-alpha.20",
|
|
46
|
+
"@shrkcrft/config": "^0.1.0-alpha.20",
|
|
47
|
+
"@shrkcrft/workspace": "^0.1.0-alpha.20",
|
|
48
|
+
"@shrkcrft/knowledge": "^0.1.0-alpha.20",
|
|
49
|
+
"@shrkcrft/rules": "^0.1.0-alpha.20",
|
|
50
|
+
"@shrkcrft/paths": "^0.1.0-alpha.20",
|
|
51
|
+
"@shrkcrft/templates": "^0.1.0-alpha.20",
|
|
52
|
+
"@shrkcrft/context": "^0.1.0-alpha.20",
|
|
53
|
+
"@shrkcrft/pipelines": "^0.1.0-alpha.20",
|
|
54
|
+
"@shrkcrft/packs": "^0.1.0-alpha.20",
|
|
55
|
+
"@shrkcrft/presets": "^0.1.0-alpha.20",
|
|
56
|
+
"@shrkcrft/boundaries": "^0.1.0-alpha.20",
|
|
57
|
+
"@shrkcrft/generator": "^0.1.0-alpha.20",
|
|
58
|
+
"@shrkcrft/importer": "^0.1.0-alpha.20",
|
|
59
|
+
"@shrkcrft/plugin-api": "^0.1.0-alpha.20",
|
|
60
|
+
"@shrkcrft/dashboard-api": "^0.1.0-alpha.20",
|
|
61
61
|
"typescript": "^5.6.0"
|
|
62
62
|
},
|
|
63
63
|
"publishConfig": {
|