@shrkcrft/inspector 0.1.0-alpha.23 → 0.1.0-alpha.25
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 +15 -1
- package/dist/changes-summary.d.ts.map +1 -1
- package/dist/changes-summary.js +54 -3
- package/dist/coverage-report.d.ts.map +1 -1
- package/dist/coverage-report.js +31 -8
- package/dist/git-helpers.d.ts.map +1 -1
- package/dist/git-helpers.js +10 -1
- package/dist/pack-quality-score.d.ts.map +1 -1
- package/dist/pack-quality-score.js +11 -5
- package/dist/plan-simulation.d.ts.map +1 -1
- package/dist/plan-simulation.js +9 -0
- package/dist/registry-lifecycle.d.ts +26 -0
- package/dist/registry-lifecycle.d.ts.map +1 -1
- package/dist/registry-lifecycle.js +111 -18
- package/dist/resolve-project-config.d.ts.map +1 -1
- package/dist/resolve-project-config.js +10 -2
- package/package.json +17 -17
|
@@ -30,7 +30,13 @@ export declare enum ChangeArea {
|
|
|
30
30
|
}
|
|
31
31
|
export interface IChangedFileSummary {
|
|
32
32
|
path: string;
|
|
33
|
-
|
|
33
|
+
/**
|
|
34
|
+
* Resolved area. One of the built-in {@link ChangeArea} slugs, OR a
|
|
35
|
+
* project-declared area (a boundary-rule tag/id or a monorepo package name)
|
|
36
|
+
* when the built-in taxonomy doesn't cover the file. `'unknown'` only when no
|
|
37
|
+
* declared taxonomy matches either — a high unknown rate is itself a signal.
|
|
38
|
+
*/
|
|
39
|
+
area: string;
|
|
34
40
|
isTest: boolean;
|
|
35
41
|
isDoc: boolean;
|
|
36
42
|
isMcpTool: boolean;
|
|
@@ -48,6 +54,14 @@ export interface IChangesSummaryReport {
|
|
|
48
54
|
roundLabel?: string;
|
|
49
55
|
totalFiles: number;
|
|
50
56
|
filesByArea: Record<string, readonly string[]>;
|
|
57
|
+
/**
|
|
58
|
+
* Fraction (0..1) of changed files that resolved to no declared area. A high
|
|
59
|
+
* rate is a classifier self-diagnostic — the declared taxonomy is missing
|
|
60
|
+
* globs, not that the diff is low-risk.
|
|
61
|
+
*/
|
|
62
|
+
unknownRate: number;
|
|
63
|
+
/** Count of files bucketed as `unknown` (the numerator behind `unknownRate`). */
|
|
64
|
+
unknownFiles: number;
|
|
51
65
|
files: readonly IChangedFileSummary[];
|
|
52
66
|
/** Touched CLI command files (relative). */
|
|
53
67
|
touchedCommands: readonly string[];
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"changes-summary.d.ts","sourceRoot":"","sources":["../src/changes-summary.ts"],"names":[],"mappings":"
|
|
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
|
@@ -11,6 +11,7 @@
|
|
|
11
11
|
*
|
|
12
12
|
* Read-only; no AI; deterministic. Schema: sharkcraft.changes-summary/v1.
|
|
13
13
|
*/
|
|
14
|
+
import { globToRegex } from '@shrkcrft/boundaries';
|
|
14
15
|
import { getChangedFiles } from "./git-helpers.js";
|
|
15
16
|
import { resolveVerificationCommands } from "./resolve-verification-commands.js";
|
|
16
17
|
export const CHANGES_SUMMARY_SCHEMA = 'sharkcraft.changes-summary/v1';
|
|
@@ -98,8 +99,50 @@ function classifyArea(file) {
|
|
|
98
99
|
return ChangeArea.Docs;
|
|
99
100
|
return ChangeArea.Unknown;
|
|
100
101
|
}
|
|
101
|
-
|
|
102
|
-
|
|
102
|
+
/** Generic monorepo package/app root → area name. */
|
|
103
|
+
const PACKAGE_ROOT_RE = /^(?:packages|apps|libs|modules|services)\/([^/]+)\//;
|
|
104
|
+
/**
|
|
105
|
+
* Build a resolver that maps a file to a declared area, falling back to the
|
|
106
|
+
* built-in SharkCraft prefixes. Sources, in priority order:
|
|
107
|
+
* 1. the built-in {@link classifyArea} slugs (nice names for this repo);
|
|
108
|
+
* 2. the boundary gate's own `from` globs — the declared layer/area taxonomy;
|
|
109
|
+
* 3. a generic monorepo package/app root (`packages/<name>/…` → `<name>`), so
|
|
110
|
+
* a foreign monorepo's packages resolve instead of bucketing to `unknown`.
|
|
111
|
+
* A file only stays `unknown` when NONE of these match — and a high unknown rate
|
|
112
|
+
* is surfaced as a self-diagnostic (`unknownRate`), not a low-risk diff.
|
|
113
|
+
*/
|
|
114
|
+
function buildAreaResolver(inspection) {
|
|
115
|
+
const boundaryMatchers = [];
|
|
116
|
+
try {
|
|
117
|
+
for (const rule of inspection.boundaryRegistry?.list() ?? []) {
|
|
118
|
+
const from = rule.from ?? [];
|
|
119
|
+
if (from.length === 0)
|
|
120
|
+
continue;
|
|
121
|
+
boundaryMatchers.push({
|
|
122
|
+
area: rule.tags?.[0] ?? rule.id,
|
|
123
|
+
matchers: from.map((g) => globToRegex(g)),
|
|
124
|
+
});
|
|
125
|
+
}
|
|
126
|
+
}
|
|
127
|
+
catch {
|
|
128
|
+
// Boundary registry unavailable — fall through to built-ins + package roots.
|
|
129
|
+
}
|
|
130
|
+
return (file) => {
|
|
131
|
+
const builtin = classifyArea(file);
|
|
132
|
+
if (builtin !== ChangeArea.Unknown)
|
|
133
|
+
return builtin;
|
|
134
|
+
for (const b of boundaryMatchers) {
|
|
135
|
+
if (b.matchers.some((re) => re.test(file)))
|
|
136
|
+
return b.area;
|
|
137
|
+
}
|
|
138
|
+
const pkg = PACKAGE_ROOT_RE.exec(file);
|
|
139
|
+
if (pkg?.[1])
|
|
140
|
+
return pkg[1];
|
|
141
|
+
return ChangeArea.Unknown;
|
|
142
|
+
};
|
|
143
|
+
}
|
|
144
|
+
function classifyFile(file, resolveArea) {
|
|
145
|
+
const area = resolveArea(file);
|
|
103
146
|
const lower = file.toLowerCase();
|
|
104
147
|
const isTest = lower.includes('__tests__/') ||
|
|
105
148
|
lower.endsWith('.test.ts') ||
|
|
@@ -246,8 +289,11 @@ export async function buildChangesSummary(inspection, options = {}) {
|
|
|
246
289
|
changedFiles = getChangedFiles(cwd, { includeWorktree: true });
|
|
247
290
|
source = 'working-tree';
|
|
248
291
|
}
|
|
249
|
-
const
|
|
292
|
+
const resolveArea = buildAreaResolver(inspection);
|
|
293
|
+
const classified = changedFiles.map((f) => classifyFile(f, resolveArea));
|
|
250
294
|
const filesByArea = groupByArea(classified);
|
|
295
|
+
const unknownFiles = classified.filter((c) => c.area === ChangeArea.Unknown).length;
|
|
296
|
+
const unknownRate = classified.length > 0 ? unknownFiles / classified.length : 0;
|
|
251
297
|
const touchedCommands = classified.filter((c) => c.isCliCommand).map((c) => c.path);
|
|
252
298
|
const touchedMcpTools = classified.filter((c) => c.isMcpTool).map((c) => c.path);
|
|
253
299
|
const touchedSchemas = classified.filter((c) => c.isSchema).map((c) => c.path);
|
|
@@ -264,6 +310,8 @@ export async function buildChangesSummary(inspection, options = {}) {
|
|
|
264
310
|
...(options.roundLabel ? { roundLabel: options.roundLabel } : {}),
|
|
265
311
|
totalFiles: classified.length,
|
|
266
312
|
filesByArea,
|
|
313
|
+
unknownRate,
|
|
314
|
+
unknownFiles,
|
|
267
315
|
files: classified,
|
|
268
316
|
touchedCommands,
|
|
269
317
|
touchedMcpTools,
|
|
@@ -296,6 +344,9 @@ export function renderChangesSummaryMarkdown(report) {
|
|
|
296
344
|
for (const f of files)
|
|
297
345
|
lines.push(`- ${f}`);
|
|
298
346
|
}
|
|
347
|
+
if (report.unknownFiles > 0) {
|
|
348
|
+
lines.push(`> ⚠ ${report.unknownFiles}/${report.totalFiles} file(s) (${Math.round(report.unknownRate * 100)}%) matched no declared area — the layer/area taxonomy may be missing globs (classifier diagnostic).`);
|
|
349
|
+
}
|
|
299
350
|
if (report.touchedCommands.length > 0) {
|
|
300
351
|
lines.push('');
|
|
301
352
|
lines.push('## Touched CLI commands');
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"coverage-report.d.ts","sourceRoot":"","sources":["../src/coverage-report.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"coverage-report.d.ts","sourceRoot":"","sources":["../src/coverage-report.ts"],"names":[],"mappings":"AAOA,OAAO,KAAK,EAAE,qBAAqB,EAAE,MAAM,2BAA2B,CAAC;AAGvE,MAAM,WAAW,iBAAiB;IAChC,EAAE,EAAE,MAAM,CAAC;IACX,KAAK,EAAE,MAAM,CAAC;IACd,KAAK,EAAE,MAAM,CAAC;IACd,OAAO,EAAE,MAAM,CAAC;IAChB,yBAAyB;IACzB,KAAK,EAAE,MAAM,CAAC;IACd,+CAA+C;IAC/C,OAAO,EAAE,MAAM,EAAE,CAAC;CACnB;AAED,MAAM,WAAW,eAAe;IAC9B,UAAU,EAAE,iBAAiB,EAAE,CAAC;IAChC,sCAAsC;IACtC,OAAO,EAAE,MAAM,CAAC;IAChB,6BAA6B;IAC7B,WAAW,EAAE,MAAM,EAAE,CAAC;CACvB;AAOD;;;;GAIG;AACH,wBAAgB,mBAAmB,CAAC,UAAU,EAAE,qBAAqB,GAAG,eAAe,CA2NtF"}
|
package/dist/coverage-report.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { hasActionHints } from '@shrkcrft/knowledge';
|
|
1
|
+
import { hasActionHints, hasMeaningfulActionHints, KNOWLEDGE_TYPES_NO_ACTION, } from '@shrkcrft/knowledge';
|
|
2
2
|
import { resolvePreset, resolvePresetReferences } from '@shrkcrft/presets';
|
|
3
3
|
import { inspectionReferenceLookup } from "./reference-lookup.js";
|
|
4
4
|
function pct(covered, total) {
|
|
@@ -57,24 +57,47 @@ export function buildCoverageReport(inspection) {
|
|
|
57
57
|
missing,
|
|
58
58
|
});
|
|
59
59
|
}
|
|
60
|
-
// 3. Critical/high knowledge entries
|
|
60
|
+
// 3. Critical/high knowledge entries carry a MEANINGFUL action hint.
|
|
61
|
+
// Quality, not mere presence: a hollow/templated hint (a `<command>`
|
|
62
|
+
// placeholder, a lone requiresHumanReview, an empty object) does NOT count,
|
|
63
|
+
// so an agent can't clear the gate with uniform low-value metadata. Entries
|
|
64
|
+
// with no actionable next step are exempt from the denominator — a per-entry
|
|
65
|
+
// author `noAction: true` (the precise lever) OR a purely-descriptive type
|
|
66
|
+
// (business/decision — the conservative floor) — so the target isn't
|
|
67
|
+
// artificially 100% and nobody is pushed to bolt a hollow hint on.
|
|
61
68
|
{
|
|
62
69
|
const eligible = inspection.knowledgeEntries.filter((e) => {
|
|
63
70
|
const p = String(e.priority);
|
|
64
71
|
return p === 'critical' || p === 'high';
|
|
65
72
|
});
|
|
66
|
-
const
|
|
73
|
+
const actionable = eligible.filter((e) => e.noAction !== true && !KNOWLEDGE_TYPES_NO_ACTION.has(e.type));
|
|
74
|
+
const total = actionable.length;
|
|
75
|
+
const knowledgeIds = new Set(inspection.knowledgeEntries.map((x) => x.id));
|
|
76
|
+
const templateIds = new Set(inspection.templates.map((t) => t.id));
|
|
67
77
|
const missing = [];
|
|
68
78
|
let covered = 0;
|
|
69
|
-
for (const e of
|
|
70
|
-
if (
|
|
79
|
+
for (const e of actionable) {
|
|
80
|
+
if (hasMeaningfulActionHints(e)) {
|
|
71
81
|
covered += 1;
|
|
72
|
-
|
|
73
|
-
|
|
82
|
+
continue;
|
|
83
|
+
}
|
|
84
|
+
// Reward RESOLVED cross-references: a hint whose related ids actually
|
|
85
|
+
// point at real entries/templates is substantive even without a command.
|
|
86
|
+
const a = e.actionHints;
|
|
87
|
+
const resolvedXref = !!a &&
|
|
88
|
+
((a.relatedKnowledge?.some((id) => knowledgeIds.has(id)) ?? false) ||
|
|
89
|
+
(a.relatedTemplates?.some((id) => templateIds.has(id)) ?? false));
|
|
90
|
+
if (resolvedXref) {
|
|
91
|
+
covered += 1;
|
|
92
|
+
continue;
|
|
93
|
+
}
|
|
94
|
+
missing.push(hasActionHints(e)
|
|
95
|
+
? `${e.id} — actionHints present but low-value (templated/empty/unresolved cross-refs)`
|
|
96
|
+
: `${e.id} — no actionHints`);
|
|
74
97
|
}
|
|
75
98
|
categories.push({
|
|
76
99
|
id: 'hint-coverage',
|
|
77
|
-
title: 'Critical/high entries carry
|
|
100
|
+
title: 'Critical/high entries carry a meaningful actionHint',
|
|
78
101
|
total,
|
|
79
102
|
covered,
|
|
80
103
|
score: pct(covered, total),
|
|
@@ -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;
|
|
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;AAqBD,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
|
@@ -1,8 +1,17 @@
|
|
|
1
1
|
import { spawnSync } from 'node:child_process';
|
|
2
2
|
import { existsSync } from 'node:fs';
|
|
3
3
|
import * as nodePath from 'node:path';
|
|
4
|
+
// 512 MB — the same generous ceiling @shrkcrft/shared's runGitLines uses. A
|
|
5
|
+
// `diff`/`log --name-only` listing on a large changeset overflows Node's 1 MB
|
|
6
|
+
// default `maxBuffer` and dies with ENOBUFS; a name listing never approaches
|
|
7
|
+
// 512 MB, so this is effectively unbounded while still capping a runaway.
|
|
8
|
+
const GIT_MAX_BUFFER = 512 * 1024 * 1024;
|
|
4
9
|
function runGit(cwd, args) {
|
|
5
|
-
const res = spawnSync('git', args, {
|
|
10
|
+
const res = spawnSync('git', args, {
|
|
11
|
+
cwd,
|
|
12
|
+
encoding: 'utf8',
|
|
13
|
+
maxBuffer: GIT_MAX_BUFFER,
|
|
14
|
+
});
|
|
6
15
|
return {
|
|
7
16
|
ok: res.status === 0,
|
|
8
17
|
stdout: (res.stdout ?? '').toString(),
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"pack-quality-score.d.ts","sourceRoot":"","sources":["../src/pack-quality-score.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"pack-quality-score.d.ts","sourceRoot":"","sources":["../src/pack-quality-score.ts"],"names":[],"mappings":"AAMA,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,iBAAiB,CAAC;AACvD,OAAO,KAAK,EAAE,qBAAqB,EAAE,MAAM,2BAA2B,CAAC;AAIvE,eAAO,MAAM,mBAAmB,qCAAqC,CAAC;AACtE,eAAO,MAAM,wBAAwB,oCAAoC,CAAC;AAE1E,MAAM,WAAW,gBAAgB;IAC/B,MAAM,EAAE,OAAO,wBAAwB,CAAC;IACxC,WAAW,EAAE,MAAM,CAAC;IACpB,UAAU,EAAE,MAAM,CAAC;IACnB,UAAU,EAAE,MAAM,CAAC;IACnB,KAAK,EAAE,MAAM,CAAC;IACd,eAAe,EAAE,SAAS;QAAE,EAAE,EAAE,MAAM,CAAC;QAAC,QAAQ,EAAE,MAAM,CAAC;QAAC,QAAQ,EAAE,MAAM,CAAC;QAAC,KAAK,EAAE,MAAM,CAAA;KAAE,EAAE,CAAC;IAC9F,KAAK,EAAE,SAAS,MAAM,EAAE,CAAC;IACzB,OAAO,EAAE,SAAS,MAAM,EAAE,CAAC;IAC3B,eAAe,CAAC,EAAE;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,EAAE,EAAE,MAAM,CAAA;KAAE,CAAC;CAChD;AAED,wBAAgB,eAAe,CAC7B,QAAQ,EAAE,iBAAiB,EAC3B,QAAQ,EAAE,iBAAiB,GAC1B,gBAAgB,CA2BlB;AAED,MAAM,WAAW,qBAAqB;IACpC,EAAE,EAAE,MAAM,CAAC;IACX,KAAK,EAAE,MAAM,CAAC;IACd,aAAa;IACb,KAAK,EAAE,MAAM,CAAC;IACd,MAAM,EAAE,MAAM,CAAC;IACf,KAAK,EAAE,SAAS,MAAM,EAAE,CAAC;CAC1B;AAED,MAAM,WAAW,iBAAiB;IAChC,MAAM,EAAE,OAAO,mBAAmB,CAAC;IACnC,WAAW,EAAE,MAAM,CAAC;IACpB,cAAc,EAAE,MAAM,CAAC;IACvB,sCAAsC;IACtC,OAAO,EAAE,MAAM,CAAC;IAChB,UAAU,EAAE,SAAS,qBAAqB,EAAE,CAAC;IAC7C,QAAQ,EAAE,SAAS,MAAM,EAAE,CAAC;CAC7B;AAMD,wBAAgB,SAAS,CACvB,UAAU,EAAE,qBAAqB,EACjC,IAAI,EAAE,eAAe,GACpB,iBAAiB,CAyInB;AAED,wBAAgB,aAAa,CAAC,UAAU,EAAE,qBAAqB,GAAG,iBAAiB,EAAE,CAEpF"}
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { CONTRIBUTION_FILE_KEYS } from '@shrkcrft/plugin-api';
|
|
2
|
+
import { hasMeaningfulActionHints, KNOWLEDGE_TYPES_NO_ACTION, } from '@shrkcrft/knowledge';
|
|
2
3
|
import { lintTemplates } from "./template-lint.js";
|
|
3
4
|
import { lintPipelines } from "./pipeline-lint.js";
|
|
4
5
|
export const PACK_QUALITY_SCHEMA = 'sharkcraft.pack-quality-score/v1';
|
|
@@ -117,15 +118,20 @@ export function scorePack(inspection, pack) {
|
|
|
117
118
|
weight: 0.7,
|
|
118
119
|
notes: pipFromPack.length === 0 ? ['No pipelines contributed'] : [],
|
|
119
120
|
});
|
|
120
|
-
// Action hints presence
|
|
121
|
+
// Action hints QUALITY (not mere presence): score only entries that carry a
|
|
122
|
+
// substantive, non-templated hint, and exempt purely-descriptive types
|
|
123
|
+
// (business/decision) from the denominator so a pack can't game the gate with
|
|
124
|
+
// hollow metadata on context-only entries.
|
|
121
125
|
const packEntries = inspection.knowledgeEntries.filter((e) => inspection.entrySources.get(e.id)?.packageName === pack.packageName);
|
|
122
|
-
const
|
|
126
|
+
const actionable = packEntries.filter((e) => e.noAction !== true && !KNOWLEDGE_TYPES_NO_ACTION.has(e.type));
|
|
127
|
+
const entriesWithMeaningfulHints = actionable.filter((e) => hasMeaningfulActionHints(e)).length;
|
|
128
|
+
const hollow = actionable.length - entriesWithMeaningfulHints;
|
|
123
129
|
dims.push({
|
|
124
130
|
id: 'action-hints',
|
|
125
|
-
label: 'Action hints',
|
|
126
|
-
score:
|
|
131
|
+
label: 'Action hints quality',
|
|
132
|
+
score: actionable.length === 0 ? 70 : Math.round((entriesWithMeaningfulHints / actionable.length) * 100),
|
|
127
133
|
weight: 0.6,
|
|
128
|
-
notes: [],
|
|
134
|
+
notes: hollow > 0 ? [`${hollow} entry(ies) lack a meaningful (non-templated) actionHint`] : [],
|
|
129
135
|
});
|
|
130
136
|
// Duplicate ids guard.
|
|
131
137
|
dims.push({
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"plan-simulation.d.ts","sourceRoot":"","sources":["../src/plan-simulation.ts"],"names":[],"mappings":"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
|
|
1
|
+
{"version":3,"file":"plan-simulation.d.ts","sourceRoot":"","sources":["../src/plan-simulation.ts"],"names":[],"mappings":"AAwBA,OAAO,EAAmB,KAAK,iBAAiB,EAAE,MAAM,kBAAkB,CAAC;AAK3E,OAAO,KAAK,EAAE,qBAAqB,EAAE,MAAM,2BAA2B,CAAC;AAEvE,eAAO,MAAM,sBAAsB,kCAAkC,CAAC;AAEtE,oBAAY,8BAA8B;IACxC,KAAK,UAAU;IACf,cAAc,oBAAoB;IAClC,QAAQ,aAAa;IACrB,gBAAgB,sBAAsB;IACtC,UAAU,gBAAgB;CAC3B;AAED,oBAAY,kBAAkB;IAC5B,KAAK,UAAU;IACf,eAAe,sBAAsB;IACrC,gBAAgB,sBAAsB;IACtC,aAAa,mBAAmB;IAChC,eAAe,qBAAqB;IACpC,gBAAgB,sBAAsB;IACtC,oBAAoB,2BAA2B;CAChD;AAED,MAAM,WAAW,mBAAmB;IAClC,YAAY,EAAE,MAAM,CAAC;IACrB,UAAU,EAAE,MAAM,CAAC;IACnB,OAAO,EAAE,8BAA8B,CAAC;IACxC,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,SAAS,EAAE,MAAM,CAAC;IAClB;;qCAEiC;IACjC,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB;gCAC4B;IAC5B,gBAAgB,EAAE,OAAO,CAAC;IAC1B,mBAAmB,EAAE,OAAO,CAAC;IAC7B,iBAAiB,EAAE,OAAO,CAAC;IAC3B,oBAAoB,EAAE,OAAO,CAAC;IAC9B,oBAAoB,EAAE,OAAO,CAAC;IAC9B,cAAc,EAAE,OAAO,CAAC;IACxB,8CAA8C;IAC9C,eAAe,CAAC,EAAE,MAAM,CAAC;IACzB,cAAc,CAAC,EAAE,MAAM,CAAC;IACxB,qDAAqD;IACrD,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,yCAAyC;IACzC,aAAa,CAAC,EAAE,OAAO,CAAC;IACxB,gDAAgD;IAChD,eAAe,CAAC,EAAE,MAAM,CAAC;CAC1B;AAED,MAAM,WAAW,0BAA0B;IACzC,IAAI,EAAE,MAAM,CAAC;IACb,MAAM,EAAE,MAAM,CAAC;IACf,eAAe,EAAE,MAAM,CAAC;IACxB,IAAI,EAAE,MAAM,CAAC;IACb,QAAQ,EAAE,MAAM,CAAC;IACjB,OAAO,EAAE,MAAM,CAAC;CACjB;AAED,MAAM,WAAW,qBAAqB;IACpC,MAAM,EAAE,OAAO,sBAAsB,CAAC;IACtC,WAAW,EAAE,MAAM,CAAC;IACpB,MAAM,EAAE,MAAM,CAAC;IACf,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,UAAU,EAAE,MAAM,CAAC;IACnB,SAAS,EAAE,QAAQ,GAAG,SAAS,GAAG,SAAS,CAAC;IAC5C,gBAAgB,CAAC,EAAE,MAAM,CAAC;IAC1B,KAAK,EAAE,SAAS,mBAAmB,EAAE,CAAC;IACtC,aAAa,EAAE,SAAS,MAAM,EAAE,CAAC;IACjC,uBAAuB,EAAE,SAAS,MAAM,EAAE,CAAC;IAC3C,gBAAgB,EAAE,OAAO,CAAC;IAC1B,mBAAmB,EAAE,OAAO,CAAC;IAC7B,iBAAiB,EAAE,OAAO,CAAC;IAC3B,oBAAoB,EAAE,OAAO,CAAC;IAC9B,oBAAoB,EAAE,OAAO,CAAC;IAC9B,sBAAsB,EAAE,OAAO,CAAC;IAChC,sBAAsB,EAAE,OAAO,CAAC;IAChC,uBAAuB,EAAE,OAAO,CAAC;IACjC,oBAAoB,EAAE,SAAS,MAAM,EAAE,CAAC;IACxC,WAAW,EAAE,SAAS,MAAM,EAAE,CAAC;IAC/B,mBAAmB,EAAE,SAAS,MAAM,EAAE,CAAC;IACvC,kBAAkB,EAAE,SAAS,MAAM,EAAE,CAAC;IACtC,iBAAiB,EAAE,SAAS,MAAM,EAAE,CAAC;IACrC,yBAAyB,EAAE,SAAS,0BAA0B,EAAE,CAAC;IACjE,8BAA8B,EAAE,SAAS,0BAA0B,EAAE,CAAC;IACtE,cAAc,EAAE,SAAS,MAAM,EAAE,CAAC;IAClC,cAAc,EAAE,kBAAkB,CAAC;IACnC,qBAAqB,EAAE,SAAS,MAAM,EAAE,CAAC;IACzC,qBAAqB,EAAE,MAAM,CAAC;IAC9B,WAAW,EAAE,SAAS,MAAM,EAAE,CAAC;IAC/B,YAAY,CAAC,EAAE,iBAAiB,CAAC;IACjC,WAAW,EAAE,SAAS,MAAM,EAAE,CAAC;CAChC;AAED,MAAM,WAAW,sBAAsB;IACrC,iEAAiE;IACjE,MAAM,CAAC,EAAE,OAAO,CAAC;IACjB,iBAAiB,CAAC,EAAE,OAAO,CAAC;IAC5B,aAAa,CAAC,EAAE,OAAO,CAAC;IACxB,YAAY,CAAC,EAAE,OAAO,CAAC;IACvB,eAAe,CAAC,EAAE,OAAO,CAAC;IAC1B,gBAAgB,CAAC,EAAE,OAAO,CAAC;IAC3B,aAAa,CAAC,EAAE,OAAO,CAAC;IACxB,mDAAmD;IACnD,IAAI,CAAC,EAAE,OAAO,CAAC;IACf,mDAAmD;IACnD,YAAY,CAAC,EAAE,MAAM,CAAC;CACvB;AAYD;;;;GAIG;AACH,wBAAgB,WAAW,CAAC,UAAU,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,EAAE,IAAI,EAAE;IAAE,OAAO,CAAC,EAAE,MAAM,CAAC;IAAC,QAAQ,CAAC,EAAE,MAAM,CAAC;IAAC,YAAY,EAAE,MAAM,CAAA;CAAE,GAAG;IAAE,IAAI,EAAE,MAAM,CAAC;IAAC,SAAS,EAAE,OAAO,CAAA;CAAE,CAoG5K;AA+GD,wBAAsB,YAAY,CAChC,UAAU,EAAE,qBAAqB,EACjC,QAAQ,EAAE,MAAM,EAChB,OAAO,GAAE,sBAA2B,GACnC,OAAO,CAAC,qBAAqB,CAAC,CAwVhC;AAOD,wBAAgB,wBAAwB,CAAC,CAAC,EAAE,qBAAqB,GAAG,MAAM,CAwDzE;AAOD,wBAAgB,4BAA4B,CAAC,CAAC,EAAE,qBAAqB,GAAG,MAAM,CAkD7E;AAWD,wBAAgB,wBAAwB,CAAC,CAAC,EAAE,qBAAqB,GAAG,MAAM,CAWzE"}
|
package/dist/plan-simulation.js
CHANGED
|
@@ -522,6 +522,15 @@ export async function simulatePlan(inspection, planPath, options = {}) {
|
|
|
522
522
|
if (potentialBoundaryConcerns.length > 0 || planIntroducedBoundaryConcerns.length > 0) {
|
|
523
523
|
requiredValidations.add('shrk architecture violations');
|
|
524
524
|
}
|
|
525
|
+
// Scale the required-validation wall to BLAST RADIUS: a one-file scaffold and a
|
|
526
|
+
// multi-file / multi-package construct shouldn't get the same wall. A broad
|
|
527
|
+
// change earns the composite changed-only "safe to finish?" verdict (project-
|
|
528
|
+
// agnostic — always a valid shrk command) on top of the per-file checks.
|
|
529
|
+
const touchedPackages = new Set(sourceList.map((c) => /^((?:packages|apps|libs|modules|services)\/[^/]+)\//.exec(c.relativePath)?.[1] ?? '(root)'));
|
|
530
|
+
const blastRadius = { files: sourceList.length, packages: touchedPackages.size };
|
|
531
|
+
if (blastRadius.files >= 5 || blastRadius.packages >= 2) {
|
|
532
|
+
requiredValidations.add('shrk finish');
|
|
533
|
+
}
|
|
525
534
|
// Affected constructs / playbooks (lightweight).
|
|
526
535
|
await loadConstructs(inspection);
|
|
527
536
|
const constructList = listConstructs(inspection) ?? [];
|
|
@@ -37,6 +37,10 @@ export interface IRegistryLifecycleReport {
|
|
|
37
37
|
totalFiles: number;
|
|
38
38
|
/** True when the scan hit the file cap and did NOT see every candidate file. */
|
|
39
39
|
truncated: boolean;
|
|
40
|
+
/** True when the scan hit its wall-clock budget and flushed partial results. */
|
|
41
|
+
timedOut: boolean;
|
|
42
|
+
/** True when the scan was scoped to the changed file set (`--changed-only`). */
|
|
43
|
+
changedOnly: boolean;
|
|
40
44
|
/** Project-relative subtree the scan was scoped to, when `--scope` was used. */
|
|
41
45
|
scope?: string;
|
|
42
46
|
registersFound: number;
|
|
@@ -51,11 +55,33 @@ export interface IRegistryLifecycleReport {
|
|
|
51
55
|
ignored: ReadonlyArray<IRegistryIgnored>;
|
|
52
56
|
recommendations: ReadonlyArray<string>;
|
|
53
57
|
}
|
|
58
|
+
/**
|
|
59
|
+
* Default directories the walk skips — build artefacts + non-source trees that
|
|
60
|
+
* inflate the scan without owning runtime lifecycle. This is the DEFAULT only;
|
|
61
|
+
* a repo that genuinely registers code under `tools/`, a non-standard root, etc.
|
|
62
|
+
* can override the set via config (`registryLifecycle.skipDirs`) / the engine's
|
|
63
|
+
* `skipDirs` input, so a hardcoded exclusion never silently blinds the check.
|
|
64
|
+
*/
|
|
65
|
+
export declare const DEFAULT_REGISTRY_LIFECYCLE_SKIP_DIRS: readonly string[];
|
|
54
66
|
export declare function buildRegistryLifecycleReport(input: {
|
|
55
67
|
projectRoot: string;
|
|
56
68
|
limit?: number;
|
|
57
69
|
/** Project-relative subtree to scope the scan to (sub-second on a subtree). */
|
|
58
70
|
scope?: string;
|
|
71
|
+
/**
|
|
72
|
+
* Changed-only scope: scan JUST these files (project-relative or absolute)
|
|
73
|
+
* instead of walking the tree. Non-`.ts/.tsx` entries are ignored. When set,
|
|
74
|
+
* an empty relevant set is reported as a loud skip, never a green pass.
|
|
75
|
+
*/
|
|
76
|
+
files?: readonly string[];
|
|
77
|
+
/** Hard wall-clock budget (ms). The scan flushes partial results on timeout. */
|
|
78
|
+
budgetMs?: number;
|
|
79
|
+
/**
|
|
80
|
+
* Directory names the walk skips. Overrides {@link DEFAULT_REGISTRY_LIFECYCLE_SKIP_DIRS}
|
|
81
|
+
* so a repo that registers code under `tools/` / a non-standard root isn't
|
|
82
|
+
* silently blinded by a baked-in exclusion. Ignored on the changed-only path.
|
|
83
|
+
*/
|
|
84
|
+
skipDirs?: readonly string[];
|
|
59
85
|
}): IRegistryLifecycleReport;
|
|
60
86
|
export declare function renderRegistryLifecycleReportText(report: IRegistryLifecycleReport): string;
|
|
61
87
|
//# sourceMappingURL=registry-lifecycle.d.ts.map
|
|
@@ -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,oEAAoE;IACpE,UAAU,EAAE,MAAM,CAAC;IACnB,gFAAgF;IAChF,SAAS,EAAE,OAAO,CAAC;IACnB,gFAAgF;IAChF,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,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;
|
|
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,oEAAoE;IACpE,UAAU,EAAE,MAAM,CAAC;IACnB,gFAAgF;IAChF,SAAS,EAAE,OAAO,CAAC;IACnB,gFAAgF;IAChF,QAAQ,EAAE,OAAO,CAAC;IAClB,gFAAgF;IAChF,WAAW,EAAE,OAAO,CAAC;IACrB,gFAAgF;IAChF,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,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;AAED;;;;;;GAMG;AACH,eAAO,MAAM,oCAAoC,EAAE,SAAS,MAAM,EAiBhE,CAAC;AA2NH,wBAAgB,4BAA4B,CAAC,KAAK,EAAE;IAClD,WAAW,EAAE,MAAM,CAAC;IACpB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,+EAA+E;IAC/E,KAAK,CAAC,EAAE,MAAM,CAAC;IACf;;;;OAIG;IACH,KAAK,CAAC,EAAE,SAAS,MAAM,EAAE,CAAC;IAC1B,gFAAgF;IAChF,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB;;;;OAIG;IACH,QAAQ,CAAC,EAAE,SAAS,MAAM,EAAE,CAAC;CAC9B,GAAG,wBAAwB,CAyH3B;AAED,wBAAgB,iCAAiC,CAAC,MAAM,EAAE,wBAAwB,GAAG,MAAM,CAiD1F"}
|
|
@@ -11,7 +11,14 @@
|
|
|
11
11
|
*/
|
|
12
12
|
import { readdirSync, readFileSync } from 'node:fs';
|
|
13
13
|
import { extname, join, relative } from 'node:path';
|
|
14
|
-
|
|
14
|
+
/**
|
|
15
|
+
* Default directories the walk skips — build artefacts + non-source trees that
|
|
16
|
+
* inflate the scan without owning runtime lifecycle. This is the DEFAULT only;
|
|
17
|
+
* a repo that genuinely registers code under `tools/`, a non-standard root, etc.
|
|
18
|
+
* can override the set via config (`registryLifecycle.skipDirs`) / the engine's
|
|
19
|
+
* `skipDirs` input, so a hardcoded exclusion never silently blinds the check.
|
|
20
|
+
*/
|
|
21
|
+
export const DEFAULT_REGISTRY_LIFECYCLE_SKIP_DIRS = Object.freeze([
|
|
15
22
|
'node_modules',
|
|
16
23
|
'dist',
|
|
17
24
|
'.git',
|
|
@@ -20,8 +27,20 @@ const SKIP_DIRS = new Set([
|
|
|
20
27
|
'.nx',
|
|
21
28
|
'build',
|
|
22
29
|
'out',
|
|
30
|
+
'examples',
|
|
31
|
+
'e2e',
|
|
32
|
+
'fixtures',
|
|
33
|
+
'__fixtures__',
|
|
34
|
+
'scripts',
|
|
35
|
+
'tools',
|
|
36
|
+
'.agents',
|
|
37
|
+
'.github',
|
|
23
38
|
]);
|
|
24
39
|
const SCAN_EXTENSIONS = new Set(['.ts', '.tsx']);
|
|
40
|
+
/** Skip pathological single files — a 200 KB command file has no registry to pair. */
|
|
41
|
+
const MAX_SCAN_FILE_BYTES = 256 * 1024;
|
|
42
|
+
/** Hard wall-clock budget so the scan fails loud (partial flush) instead of hanging. */
|
|
43
|
+
const DEFAULT_BUDGET_MS = 15_000;
|
|
25
44
|
function isGeneratedFile(file, content) {
|
|
26
45
|
if (file.endsWith('.d.ts'))
|
|
27
46
|
return true;
|
|
@@ -31,7 +50,7 @@ function isGeneratedFile(file, content) {
|
|
|
31
50
|
return true;
|
|
32
51
|
return false;
|
|
33
52
|
}
|
|
34
|
-
function walk(dir, projectRoot, out) {
|
|
53
|
+
function walk(dir, projectRoot, out, skipDirs) {
|
|
35
54
|
let entries;
|
|
36
55
|
try {
|
|
37
56
|
entries = readdirSync(dir, { withFileTypes: true });
|
|
@@ -40,7 +59,7 @@ function walk(dir, projectRoot, out) {
|
|
|
40
59
|
return;
|
|
41
60
|
}
|
|
42
61
|
for (const e of entries) {
|
|
43
|
-
if (
|
|
62
|
+
if (skipDirs.has(e.name))
|
|
44
63
|
continue;
|
|
45
64
|
if (e.name.startsWith('.') && e.name !== '.sharkcraft') {
|
|
46
65
|
// skip hidden dotfiles
|
|
@@ -49,7 +68,7 @@ function walk(dir, projectRoot, out) {
|
|
|
49
68
|
}
|
|
50
69
|
const abs = join(dir, e.name);
|
|
51
70
|
if (e.isDirectory()) {
|
|
52
|
-
walk(abs, projectRoot, out);
|
|
71
|
+
walk(abs, projectRoot, out, skipDirs);
|
|
53
72
|
}
|
|
54
73
|
else if (e.isFile() && SCAN_EXTENSIONS.has(extname(e.name))) {
|
|
55
74
|
out.push(abs);
|
|
@@ -174,7 +193,38 @@ function stripCommentsAndLiterals(content) {
|
|
|
174
193
|
}
|
|
175
194
|
return out.join('');
|
|
176
195
|
}
|
|
177
|
-
|
|
196
|
+
/**
|
|
197
|
+
* Precompute the byte offset of each line start, so an offset → line lookup is
|
|
198
|
+
* O(log n) instead of the O(fileLen) `content.slice(0, i).split('\n')` done PER
|
|
199
|
+
* MATCH (the original quadratic hotspot — a 57 KB file with 200 `register*`
|
|
200
|
+
* tokens paid ~200 × 57 KB of slicing). Built once per file.
|
|
201
|
+
*/
|
|
202
|
+
function buildLineStarts(content) {
|
|
203
|
+
const starts = [0];
|
|
204
|
+
for (let i = 0; i < content.length; i += 1) {
|
|
205
|
+
if (content.charCodeAt(i) === 10 /* \n */)
|
|
206
|
+
starts.push(i + 1);
|
|
207
|
+
}
|
|
208
|
+
return starts;
|
|
209
|
+
}
|
|
210
|
+
/** 1-based line number for a byte offset, via binary search over line starts. */
|
|
211
|
+
function lineAtOffset(lineStarts, offset) {
|
|
212
|
+
let lo = 0;
|
|
213
|
+
let hi = lineStarts.length - 1;
|
|
214
|
+
let ans = 0;
|
|
215
|
+
while (lo <= hi) {
|
|
216
|
+
const mid = (lo + hi) >> 1;
|
|
217
|
+
if (lineStarts[mid] <= offset) {
|
|
218
|
+
ans = mid;
|
|
219
|
+
lo = mid + 1;
|
|
220
|
+
}
|
|
221
|
+
else {
|
|
222
|
+
hi = mid - 1;
|
|
223
|
+
}
|
|
224
|
+
}
|
|
225
|
+
return ans + 1;
|
|
226
|
+
}
|
|
227
|
+
function findRegistersInFile(content, lineStarts) {
|
|
178
228
|
const out = [];
|
|
179
229
|
const seen = new Set();
|
|
180
230
|
for (const re of REGISTER_PATTERNS) {
|
|
@@ -185,8 +235,7 @@ function findRegistersInFile(content) {
|
|
|
185
235
|
if (seen.has(`${name}@${m.index}`))
|
|
186
236
|
continue;
|
|
187
237
|
seen.add(`${name}@${m.index}`);
|
|
188
|
-
|
|
189
|
-
out.push({ name, line });
|
|
238
|
+
out.push({ name, line: lineAtOffset(lineStarts, m.index) });
|
|
190
239
|
}
|
|
191
240
|
}
|
|
192
241
|
return out;
|
|
@@ -217,13 +266,12 @@ function expectedRemoverNames(registerName) {
|
|
|
217
266
|
`${stem}Off`,
|
|
218
267
|
];
|
|
219
268
|
}
|
|
220
|
-
function findRemoverInContent(content, candidates) {
|
|
269
|
+
function findRemoverInContent(content, candidates, lineStarts) {
|
|
221
270
|
for (const name of candidates) {
|
|
222
271
|
const re = new RegExp(`(?:export\\s+)?(?:async\\s+)?function\\s+${name}\\s*\\(|\\b${name}\\s*=\\s*\\(|(?:public|private|protected)?\\s*(?:async\\s+)?${name}\\s*\\(`);
|
|
223
272
|
const m = content.match(re);
|
|
224
273
|
if (m && typeof m.index === 'number') {
|
|
225
|
-
|
|
226
|
-
return { name, line };
|
|
274
|
+
return { name, line: lineAtOffset(lineStarts, m.index) };
|
|
227
275
|
}
|
|
228
276
|
}
|
|
229
277
|
return null;
|
|
@@ -231,17 +279,39 @@ function findRemoverInContent(content, candidates) {
|
|
|
231
279
|
export function buildRegistryLifecycleReport(input) {
|
|
232
280
|
const { projectRoot } = input;
|
|
233
281
|
const scope = input.scope && input.scope.length > 0 ? input.scope : undefined;
|
|
234
|
-
const
|
|
235
|
-
const
|
|
236
|
-
walk(walkRoot, projectRoot, files);
|
|
282
|
+
const changedOnly = input.files !== undefined;
|
|
283
|
+
const deadline = Date.now() + (input.budgetMs ?? DEFAULT_BUDGET_MS);
|
|
237
284
|
const limit = input.limit ?? 2000;
|
|
285
|
+
const skipDirs = new Set(input.skipDirs ?? DEFAULT_REGISTRY_LIFECYCLE_SKIP_DIRS);
|
|
286
|
+
// Candidate files: either the explicit changed set (bypassing the walk) or a
|
|
287
|
+
// bounded tree walk. The changed set resolves relative paths under the root
|
|
288
|
+
// and keeps only scannable extensions.
|
|
289
|
+
let files;
|
|
290
|
+
if (input.files !== undefined) {
|
|
291
|
+
files = input.files
|
|
292
|
+
.map((f) => (f.startsWith('/') ? f : join(projectRoot, f)))
|
|
293
|
+
.filter((f) => SCAN_EXTENSIONS.has(extname(f)));
|
|
294
|
+
}
|
|
295
|
+
else {
|
|
296
|
+
const walkRoot = scope ? join(projectRoot, scope) : projectRoot;
|
|
297
|
+
files = [];
|
|
298
|
+
walk(walkRoot, projectRoot, files, skipDirs);
|
|
299
|
+
}
|
|
238
300
|
const scanFiles = files.slice(0, limit);
|
|
239
301
|
const matchedPairs = [];
|
|
240
302
|
const missingRemovers = [];
|
|
241
303
|
const oneShotBootstrap = [];
|
|
242
304
|
const ignored = [];
|
|
243
305
|
let registersFound = 0;
|
|
306
|
+
let timedOut = false;
|
|
307
|
+
let filesScanned = 0;
|
|
244
308
|
for (const file of scanFiles) {
|
|
309
|
+
// Hard wall-clock budget checked between files — the scan is synchronous, so
|
|
310
|
+
// a Date.now() deadline is the only interruption point. Flush partial results.
|
|
311
|
+
if (Date.now() > deadline) {
|
|
312
|
+
timedOut = true;
|
|
313
|
+
break;
|
|
314
|
+
}
|
|
245
315
|
let content;
|
|
246
316
|
try {
|
|
247
317
|
content = readFileSync(file, 'utf8');
|
|
@@ -249,12 +319,19 @@ export function buildRegistryLifecycleReport(input) {
|
|
|
249
319
|
catch {
|
|
250
320
|
continue;
|
|
251
321
|
}
|
|
322
|
+
// Per-file size cap: a huge file (a big command/aggregate module) is a
|
|
323
|
+
// catastrophic-backtracking / quadratic hazard and never holds a registry
|
|
324
|
+
// that owes a remover. Skip it rather than let one file wedge the scan.
|
|
325
|
+
if (content.length > MAX_SCAN_FILE_BYTES)
|
|
326
|
+
continue;
|
|
252
327
|
if (isGeneratedFile(file, content))
|
|
253
328
|
continue;
|
|
329
|
+
filesScanned += 1;
|
|
254
330
|
// Scan declarations on code with comments/strings blanked out; keep the raw
|
|
255
331
|
// content only for the comment-based @shrkcrft annotations.
|
|
256
332
|
const code = stripCommentsAndLiterals(content);
|
|
257
|
-
const
|
|
333
|
+
const lineStarts = buildLineStarts(code);
|
|
334
|
+
const registers = findRegistersInFile(code, lineStarts);
|
|
258
335
|
// Per-file lifecycle evidence: only a file that BOTH accumulates removable
|
|
259
336
|
// state AND has a teardown-shaped API plausibly owes a per-register remover.
|
|
260
337
|
const hasAccumulation = ACCUMULATION_RE.test(code);
|
|
@@ -274,7 +351,7 @@ export function buildRegistryLifecycleReport(input) {
|
|
|
274
351
|
continue;
|
|
275
352
|
}
|
|
276
353
|
const candidates = expectedRemoverNames(reg.name);
|
|
277
|
-
const remover = findRemoverInContent(code, candidates);
|
|
354
|
+
const remover = findRemoverInContent(code, candidates, lineStarts);
|
|
278
355
|
if (remover) {
|
|
279
356
|
matchedPairs.push({
|
|
280
357
|
registerName: reg.name,
|
|
@@ -310,9 +387,11 @@ export function buildRegistryLifecycleReport(input) {
|
|
|
310
387
|
}
|
|
311
388
|
return {
|
|
312
389
|
schema: 'sharkcraft.registry-lifecycle/v1',
|
|
313
|
-
filesScanned
|
|
390
|
+
filesScanned,
|
|
314
391
|
totalFiles: files.length,
|
|
315
|
-
truncated: files.length > scanFiles.length,
|
|
392
|
+
truncated: files.length > scanFiles.length || timedOut,
|
|
393
|
+
timedOut,
|
|
394
|
+
changedOnly,
|
|
316
395
|
...(scope ? { scope } : {}),
|
|
317
396
|
registersFound,
|
|
318
397
|
matchedPairs,
|
|
@@ -327,8 +406,22 @@ export function renderRegistryLifecycleReportText(report) {
|
|
|
327
406
|
lines.push('=== Registry lifecycle ===');
|
|
328
407
|
if (report.scope)
|
|
329
408
|
lines.push(` scope ${report.scope}`);
|
|
409
|
+
if (report.changedOnly)
|
|
410
|
+
lines.push(' scope changed-only');
|
|
411
|
+
// Loud skip: a changed diff that touches no scannable file was NOT verified —
|
|
412
|
+
// never let "scanned nothing" read as a clean pass.
|
|
413
|
+
if (report.changedOnly && report.filesScanned === 0) {
|
|
414
|
+
lines.push('');
|
|
415
|
+
lines.push(' ! 0 files in the changed scope — lifecycle NOT verified (this is not a pass).');
|
|
416
|
+
return lines.join('\n') + '\n';
|
|
417
|
+
}
|
|
418
|
+
if (report.timedOut) {
|
|
419
|
+
lines.push(` ! wall-clock budget hit — scanned ${report.filesScanned}/${report.totalFiles} before flushing partial results (re-run with --scope <dir> to finish).`);
|
|
420
|
+
}
|
|
330
421
|
lines.push(` files scanned ${report.filesScanned}` +
|
|
331
|
-
(report.truncated
|
|
422
|
+
(report.truncated && !report.timedOut
|
|
423
|
+
? ` ! capped (${report.totalFiles} candidates — re-run with --scope <dir> for the rest)`
|
|
424
|
+
: ''));
|
|
332
425
|
lines.push(` registers found ${report.registersFound}`);
|
|
333
426
|
lines.push(` matched pairs ${report.matchedPairs.length}`);
|
|
334
427
|
lines.push(` missing removers ${report.missingRemovers.length}`);
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"resolve-project-config.d.ts","sourceRoot":"","sources":["../src/resolve-project-config.ts"],"names":[],"mappings":"AAuBA,OAAO,EAGL,KAAK,QAAQ,
|
|
1
|
+
{"version":3,"file":"resolve-project-config.d.ts","sourceRoot":"","sources":["../src/resolve-project-config.ts"],"names":[],"mappings":"AAuBA,OAAO,EAGL,KAAK,QAAQ,EAMb,KAAK,MAAM,EACZ,MAAM,gBAAgB,CAAC;AACxB,OAAO,EAOL,KAAK,YAAY,EAClB,MAAM,kBAAkB,CAAC;AAG1B;;;GAGG;AACH,MAAM,WAAW,sBAAuB,SAAQ,YAAY;IAC1D;;;;;;OAMG;IACH,QAAQ,CAAC,gBAAgB,EAAE,SAAS,MAAM,EAAE,CAAC;CAC9C;AAoHD;;;;;;;GAOG;AACH,wBAAsB,oBAAoB,CACxC,GAAG,EAAE,MAAM,GACV,OAAO,CAAC,MAAM,CAAC,sBAAsB,EAAE,QAAQ,CAAC,CAAC,CAoEnD"}
|
|
@@ -22,7 +22,7 @@
|
|
|
22
22
|
import { existsSync } from 'node:fs';
|
|
23
23
|
import * as nodePath from 'node:path';
|
|
24
24
|
import { importModuleViaLoader, ok, } from '@shrkcrft/core';
|
|
25
|
-
import { loadProjectConfig, PolicyRuleSchema, RegistryDeclarationSchema, ReusePrimitiveSchema, WiringRuleSchema, } from '@shrkcrft/config';
|
|
25
|
+
import { loadProjectConfig, PolicyRuleSchema, RegistrationIdiomSchema, RegistryDeclarationSchema, ReusePrimitiveSchema, WiringRuleSchema, } from '@shrkcrft/config';
|
|
26
26
|
import { discoverPacks } from '@shrkcrft/packs';
|
|
27
27
|
/**
|
|
28
28
|
* Generic per-plane load + validate + merge. Seeds the merged map from the
|
|
@@ -118,11 +118,19 @@ export async function resolveProjectConfig(cwd) {
|
|
|
118
118
|
}
|
|
119
119
|
const wiringRules = await mergePlane(base.config.wiringRules ?? [], gatherPackContribs(validPacks, 'wiringRuleFiles'), WiringRuleSchema, (r) => r.id, 'wiringRule', diagnostics);
|
|
120
120
|
const registries = await mergePlane(base.config.registries ?? [], gatherPackContribs(validPacks, 'registryFiles'), RegistryDeclarationSchema, (r) => r.name, 'registry', diagnostics);
|
|
121
|
+
const registrationGraph = await mergePlane(base.config.registrationGraph ?? [], gatherPackContribs(validPacks, 'registrationGraphFiles'), RegistrationIdiomSchema, (r) => r.name, 'registrationIdiom', diagnostics);
|
|
121
122
|
const policyRules = await mergePlane(base.config.policyRules ?? [], gatherPackContribs(validPacks, 'policyRuleFiles'), PolicyRuleSchema, (r) => r.id, 'policyRule', diagnostics);
|
|
122
123
|
const reusePrimitives = await mergePlane(base.config.reusePrimitives ?? [], gatherPackContribs(validPacks, 'reusePrimitiveFiles'), ReusePrimitiveSchema, (r) => r.symbol, 'reusePrimitive', diagnostics);
|
|
123
124
|
return ok({
|
|
124
125
|
...base,
|
|
125
|
-
config: {
|
|
126
|
+
config: {
|
|
127
|
+
...base.config,
|
|
128
|
+
wiringRules,
|
|
129
|
+
registries,
|
|
130
|
+
registrationGraph,
|
|
131
|
+
policyRules,
|
|
132
|
+
reusePrimitives,
|
|
133
|
+
},
|
|
126
134
|
planeDiagnostics: diagnostics,
|
|
127
135
|
});
|
|
128
136
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@shrkcrft/inspector",
|
|
3
|
-
"version": "0.1.0-alpha.
|
|
3
|
+
"version": "0.1.0-alpha.25",
|
|
4
4
|
"description": "SharkCraft inspector: project overview, doctor checks, AI-agent instructions.",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"author": "SharkCraft contributors",
|
|
@@ -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.25",
|
|
46
|
+
"@shrkcrft/config": "^0.1.0-alpha.25",
|
|
47
|
+
"@shrkcrft/workspace": "^0.1.0-alpha.25",
|
|
48
|
+
"@shrkcrft/knowledge": "^0.1.0-alpha.25",
|
|
49
|
+
"@shrkcrft/rules": "^0.1.0-alpha.25",
|
|
50
|
+
"@shrkcrft/paths": "^0.1.0-alpha.25",
|
|
51
|
+
"@shrkcrft/templates": "^0.1.0-alpha.25",
|
|
52
|
+
"@shrkcrft/context": "^0.1.0-alpha.25",
|
|
53
|
+
"@shrkcrft/pipelines": "^0.1.0-alpha.25",
|
|
54
|
+
"@shrkcrft/packs": "^0.1.0-alpha.25",
|
|
55
|
+
"@shrkcrft/presets": "^0.1.0-alpha.25",
|
|
56
|
+
"@shrkcrft/boundaries": "^0.1.0-alpha.25",
|
|
57
|
+
"@shrkcrft/generator": "^0.1.0-alpha.25",
|
|
58
|
+
"@shrkcrft/importer": "^0.1.0-alpha.25",
|
|
59
|
+
"@shrkcrft/plugin-api": "^0.1.0-alpha.25",
|
|
60
|
+
"@shrkcrft/dashboard-api": "^0.1.0-alpha.25",
|
|
61
61
|
"typescript": "^5.6.0"
|
|
62
62
|
},
|
|
63
63
|
"publishConfig": {
|