slopbrick 0.18.3 → 0.18.5
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/engine/worker.cjs +426 -5
- package/dist/engine/worker.js +426 -5
- package/dist/index.cjs +735 -76
- package/dist/index.d.cts +611 -511
- package/dist/index.d.ts +611 -511
- package/dist/index.js +734 -75
- package/package.json +1 -1
package/dist/index.cjs
CHANGED
|
@@ -31,15 +31,41 @@ var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__ge
|
|
|
31
31
|
));
|
|
32
32
|
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
|
33
33
|
|
|
34
|
-
// src/types.ts
|
|
35
|
-
var
|
|
36
|
-
var
|
|
37
|
-
"src/types.ts"() {
|
|
34
|
+
// src/types/_header.ts
|
|
35
|
+
var VERSION;
|
|
36
|
+
var init_header = __esm({
|
|
37
|
+
"src/types/_header.ts"() {
|
|
38
|
+
"use strict";
|
|
39
|
+
VERSION = "0.18.5";
|
|
40
|
+
}
|
|
41
|
+
});
|
|
42
|
+
|
|
43
|
+
// src/types/primitives.ts
|
|
44
|
+
var init_primitives = __esm({
|
|
45
|
+
"src/types/primitives.ts"() {
|
|
46
|
+
"use strict";
|
|
47
|
+
}
|
|
48
|
+
});
|
|
49
|
+
|
|
50
|
+
// src/types/scan.ts
|
|
51
|
+
var init_scan = __esm({
|
|
52
|
+
"src/types/scan.ts"() {
|
|
53
|
+
"use strict";
|
|
54
|
+
}
|
|
55
|
+
});
|
|
56
|
+
|
|
57
|
+
// src/types/config.ts
|
|
58
|
+
var init_config = __esm({
|
|
59
|
+
"src/types/config.ts"() {
|
|
60
|
+
"use strict";
|
|
61
|
+
}
|
|
62
|
+
});
|
|
63
|
+
|
|
64
|
+
// src/types/report.ts
|
|
65
|
+
var AI_SECURITY_NUMERIC, REPOSITORY_HEALTH_WEIGHTS;
|
|
66
|
+
var init_report = __esm({
|
|
67
|
+
"src/types/report.ts"() {
|
|
38
68
|
"use strict";
|
|
39
|
-
import_node_module = require("module");
|
|
40
|
-
require2 = (0, import_node_module.createRequire)(__importMetaUrl);
|
|
41
|
-
pkg = require2("../package.json");
|
|
42
|
-
VERSION = pkg.version;
|
|
43
69
|
AI_SECURITY_NUMERIC = {
|
|
44
70
|
low: 100,
|
|
45
71
|
medium: 75,
|
|
@@ -59,6 +85,34 @@ var init_types = __esm({
|
|
|
59
85
|
}
|
|
60
86
|
});
|
|
61
87
|
|
|
88
|
+
// src/types/project-report.ts
|
|
89
|
+
var init_project_report = __esm({
|
|
90
|
+
"src/types/project-report.ts"() {
|
|
91
|
+
"use strict";
|
|
92
|
+
}
|
|
93
|
+
});
|
|
94
|
+
|
|
95
|
+
// src/types/baseline.ts
|
|
96
|
+
var init_baseline = __esm({
|
|
97
|
+
"src/types/baseline.ts"() {
|
|
98
|
+
"use strict";
|
|
99
|
+
}
|
|
100
|
+
});
|
|
101
|
+
|
|
102
|
+
// src/types/index.ts
|
|
103
|
+
var init_types = __esm({
|
|
104
|
+
"src/types/index.ts"() {
|
|
105
|
+
"use strict";
|
|
106
|
+
init_header();
|
|
107
|
+
init_primitives();
|
|
108
|
+
init_scan();
|
|
109
|
+
init_config();
|
|
110
|
+
init_report();
|
|
111
|
+
init_project_report();
|
|
112
|
+
init_baseline();
|
|
113
|
+
}
|
|
114
|
+
});
|
|
115
|
+
|
|
62
116
|
// src/config/defaults.ts
|
|
63
117
|
var DEFAULT_SPACING_SCALE, DEFAULT_RADIUS_SCALE, DEFAULT_RULE_CONFIG, DEFAULT_CONFIG;
|
|
64
118
|
var init_defaults = __esm({
|
|
@@ -310,9 +364,9 @@ function findWorkspacePackages(cwd) {
|
|
|
310
364
|
const pkgPath = (0, import_node_path.join)(root, "package.json");
|
|
311
365
|
if ((0, import_node_fs.existsSync)(pkgPath)) {
|
|
312
366
|
try {
|
|
313
|
-
const
|
|
314
|
-
if (Array.isArray(
|
|
315
|
-
for (const pattern of
|
|
367
|
+
const pkg = JSON.parse((0, import_node_fs.readFileSync)(pkgPath, "utf-8"));
|
|
368
|
+
if (Array.isArray(pkg.workspaces)) {
|
|
369
|
+
for (const pattern of pkg.workspaces) {
|
|
316
370
|
packages.push(...expandWorkspacePattern(root, pattern));
|
|
317
371
|
}
|
|
318
372
|
}
|
|
@@ -370,11 +424,11 @@ function detectStylingSolution(cwd) {
|
|
|
370
424
|
let deps = {};
|
|
371
425
|
if ((0, import_node_fs2.existsSync)(pkgPath)) {
|
|
372
426
|
try {
|
|
373
|
-
const
|
|
427
|
+
const pkg = JSON.parse((0, import_node_fs2.readFileSync)(pkgPath, "utf-8"));
|
|
374
428
|
deps = {
|
|
375
|
-
...
|
|
376
|
-
...
|
|
377
|
-
...
|
|
429
|
+
...pkg.dependencies,
|
|
430
|
+
...pkg.devDependencies,
|
|
431
|
+
...pkg.peerDependencies
|
|
378
432
|
};
|
|
379
433
|
} catch {
|
|
380
434
|
}
|
|
@@ -573,11 +627,11 @@ function detectStack(cwd) {
|
|
|
573
627
|
return {};
|
|
574
628
|
}
|
|
575
629
|
try {
|
|
576
|
-
const
|
|
630
|
+
const pkg = JSON.parse((0, import_node_fs3.readFileSync)(pkgPath, "utf-8"));
|
|
577
631
|
const deps = {
|
|
578
|
-
...
|
|
579
|
-
...
|
|
580
|
-
...
|
|
632
|
+
...pkg.dependencies,
|
|
633
|
+
...pkg.devDependencies,
|
|
634
|
+
...pkg.peerDependencies
|
|
581
635
|
};
|
|
582
636
|
const names = Object.keys(deps).map((name) => name.toLowerCase());
|
|
583
637
|
const result = {};
|
|
@@ -26213,13 +26267,13 @@ var init_default_react_stack = __esm({
|
|
|
26213
26267
|
for (const m of source.matchAll(IMPORT_LINE_RE)) {
|
|
26214
26268
|
const spec = m[1];
|
|
26215
26269
|
if (!spec) continue;
|
|
26216
|
-
const
|
|
26217
|
-
if (
|
|
26270
|
+
const pkg = spec.startsWith("@/") ? spec : spec.startsWith("@") ? spec.split("/").slice(0, 2).join("/") : spec.split("/")[0];
|
|
26271
|
+
if (pkg) importedPackages.add(pkg);
|
|
26218
26272
|
}
|
|
26219
26273
|
const hits = [];
|
|
26220
|
-
for (const
|
|
26221
|
-
if (DEFAULT_STACK_PACKAGES.some((p) => p ===
|
|
26222
|
-
hits.push(
|
|
26274
|
+
for (const pkg of importedPackages) {
|
|
26275
|
+
if (DEFAULT_STACK_PACKAGES.some((p) => p === pkg || p.startsWith(pkg + "/"))) {
|
|
26276
|
+
hits.push(pkg);
|
|
26223
26277
|
}
|
|
26224
26278
|
}
|
|
26225
26279
|
if (hits.length < MIN_HITS) return [];
|
|
@@ -28109,6 +28163,205 @@ var init_sql_concat = __esm({
|
|
|
28109
28163
|
}
|
|
28110
28164
|
});
|
|
28111
28165
|
|
|
28166
|
+
// src/rules/dead/dead-branch.ts
|
|
28167
|
+
var deadBranchRule;
|
|
28168
|
+
var init_dead_branch = __esm({
|
|
28169
|
+
"src/rules/dead/dead-branch.ts"() {
|
|
28170
|
+
"use strict";
|
|
28171
|
+
init_rule();
|
|
28172
|
+
deadBranchRule = createRule({
|
|
28173
|
+
id: "dead/dead-branch",
|
|
28174
|
+
category: "logic",
|
|
28175
|
+
severity: "medium",
|
|
28176
|
+
aiSpecific: true,
|
|
28177
|
+
description: "Literal boolean condition makes one branch statically dead",
|
|
28178
|
+
create(_context) {
|
|
28179
|
+
return {};
|
|
28180
|
+
},
|
|
28181
|
+
analyze(_context, facts) {
|
|
28182
|
+
const issues = [];
|
|
28183
|
+
if (!facts.v2) return issues;
|
|
28184
|
+
for (const cond of facts.v2.deadCode.constantConditions) {
|
|
28185
|
+
const isWhileTrue = cond.kind === "while-true";
|
|
28186
|
+
issues.push({
|
|
28187
|
+
ruleId: "dead/dead-branch",
|
|
28188
|
+
category: "logic",
|
|
28189
|
+
severity: isWhileTrue ? "low" : "medium",
|
|
28190
|
+
aiSpecific: true,
|
|
28191
|
+
message: isWhileTrue ? `Infinite loop with literal condition (${cond.kind})` : `Dead branch: condition is always ${cond.condition}`,
|
|
28192
|
+
line: cond.line,
|
|
28193
|
+
column: cond.column,
|
|
28194
|
+
advice: isWhileTrue ? `If this is an intentional infinite loop (event loop, hot loop with explicit \`break\`), add a \`// slopbrick-disable\` comment. Otherwise, replace the literal with a real condition.` : `Replace the literal with a real condition, or remove the dead branch entirely. This is the AI-iteration signature: the model toggled a feature flag to a constant or left a wrapper from a previous refactor.`
|
|
28195
|
+
});
|
|
28196
|
+
}
|
|
28197
|
+
return issues;
|
|
28198
|
+
}
|
|
28199
|
+
});
|
|
28200
|
+
}
|
|
28201
|
+
});
|
|
28202
|
+
|
|
28203
|
+
// src/rules/dead/unreachable.ts
|
|
28204
|
+
var unreachableRule;
|
|
28205
|
+
var init_unreachable = __esm({
|
|
28206
|
+
"src/rules/dead/unreachable.ts"() {
|
|
28207
|
+
"use strict";
|
|
28208
|
+
init_rule();
|
|
28209
|
+
unreachableRule = createRule({
|
|
28210
|
+
id: "dead/unreachable",
|
|
28211
|
+
category: "logic",
|
|
28212
|
+
severity: "high",
|
|
28213
|
+
aiSpecific: true,
|
|
28214
|
+
description: "Statement is unreachable after an unconditional return/throw/break/continue",
|
|
28215
|
+
create(_context) {
|
|
28216
|
+
return {};
|
|
28217
|
+
},
|
|
28218
|
+
analyze(_context, facts) {
|
|
28219
|
+
const issues = [];
|
|
28220
|
+
if (!facts.v2) return issues;
|
|
28221
|
+
for (const u of facts.v2.deadCode.unreachableStatements) {
|
|
28222
|
+
if (u.snippet === "<unreachable>") continue;
|
|
28223
|
+
issues.push({
|
|
28224
|
+
ruleId: "dead/unreachable",
|
|
28225
|
+
category: "logic",
|
|
28226
|
+
severity: "high",
|
|
28227
|
+
aiSpecific: true,
|
|
28228
|
+
message: `Unreachable after ${u.terminator}: ${u.snippet}`,
|
|
28229
|
+
line: u.line,
|
|
28230
|
+
column: u.column,
|
|
28231
|
+
advice: `Remove this statement \u2014 code after a ${u.terminator} is unreachable. This is the AI-iteration signature: the model added an early ${u.terminator} for a new error path, then forgot the rest of the function body was still sitting below it.`
|
|
28232
|
+
});
|
|
28233
|
+
}
|
|
28234
|
+
return issues;
|
|
28235
|
+
}
|
|
28236
|
+
});
|
|
28237
|
+
}
|
|
28238
|
+
});
|
|
28239
|
+
|
|
28240
|
+
// src/rules/dead/unused-import.ts
|
|
28241
|
+
var unusedImportRule;
|
|
28242
|
+
var init_unused_import = __esm({
|
|
28243
|
+
"src/rules/dead/unused-import.ts"() {
|
|
28244
|
+
"use strict";
|
|
28245
|
+
init_rule();
|
|
28246
|
+
unusedImportRule = createRule({
|
|
28247
|
+
id: "dead/unused-import",
|
|
28248
|
+
category: "logic",
|
|
28249
|
+
severity: "low",
|
|
28250
|
+
aiSpecific: true,
|
|
28251
|
+
description: "ES module import is never referenced in the file",
|
|
28252
|
+
create(_context) {
|
|
28253
|
+
return {};
|
|
28254
|
+
},
|
|
28255
|
+
analyze(_context, facts) {
|
|
28256
|
+
const issues = [];
|
|
28257
|
+
if (!facts.v2) return issues;
|
|
28258
|
+
for (const binding of facts.v2.deadCode.bindings) {
|
|
28259
|
+
if (binding.kind !== "import-specifier" && binding.kind !== "import-default" && binding.kind !== "import-namespace") {
|
|
28260
|
+
continue;
|
|
28261
|
+
}
|
|
28262
|
+
if (binding.isReferenced) continue;
|
|
28263
|
+
if (!binding.name) continue;
|
|
28264
|
+
const source = binding.source ? ` from '${binding.source}'` : "";
|
|
28265
|
+
issues.push({
|
|
28266
|
+
ruleId: "dead/unused-import",
|
|
28267
|
+
category: "logic",
|
|
28268
|
+
severity: "low",
|
|
28269
|
+
aiSpecific: true,
|
|
28270
|
+
message: `Unused import: '${binding.name}'${source}`,
|
|
28271
|
+
line: binding.line,
|
|
28272
|
+
column: binding.column,
|
|
28273
|
+
advice: `Remove the import or use '${binding.name}' somewhere in the file. This is the most common AI-iteration rot \u2014 the model added the import when it introduced a feature, then rewrote the function without cleaning up.`
|
|
28274
|
+
});
|
|
28275
|
+
}
|
|
28276
|
+
return issues;
|
|
28277
|
+
}
|
|
28278
|
+
});
|
|
28279
|
+
}
|
|
28280
|
+
});
|
|
28281
|
+
|
|
28282
|
+
// src/rules/dead/unused-local.ts
|
|
28283
|
+
var SKIP_NAMES, unusedLocalRule;
|
|
28284
|
+
var init_unused_local = __esm({
|
|
28285
|
+
"src/rules/dead/unused-local.ts"() {
|
|
28286
|
+
"use strict";
|
|
28287
|
+
init_rule();
|
|
28288
|
+
SKIP_NAMES = /* @__PURE__ */ new Set(["React", "_"]);
|
|
28289
|
+
unusedLocalRule = createRule({
|
|
28290
|
+
id: "dead/unused-local",
|
|
28291
|
+
category: "logic",
|
|
28292
|
+
severity: "low",
|
|
28293
|
+
aiSpecific: true,
|
|
28294
|
+
description: "Variable is declared but never read after declaration",
|
|
28295
|
+
create(_context) {
|
|
28296
|
+
return {};
|
|
28297
|
+
},
|
|
28298
|
+
analyze(_context, facts) {
|
|
28299
|
+
const issues = [];
|
|
28300
|
+
if (!facts.v2) return issues;
|
|
28301
|
+
for (const binding of facts.v2.deadCode.bindings) {
|
|
28302
|
+
if (binding.kind !== "var" && binding.kind !== "let" && binding.kind !== "const" && binding.kind !== "function" && binding.kind !== "class" && binding.kind !== "type" && binding.kind !== "interface" && binding.kind !== "enum") {
|
|
28303
|
+
continue;
|
|
28304
|
+
}
|
|
28305
|
+
if (binding.isReferenced) continue;
|
|
28306
|
+
if (SKIP_NAMES.has(binding.name)) continue;
|
|
28307
|
+
if (binding.name.startsWith("_")) continue;
|
|
28308
|
+
issues.push({
|
|
28309
|
+
ruleId: "dead/unused-local",
|
|
28310
|
+
category: "logic",
|
|
28311
|
+
severity: "low",
|
|
28312
|
+
aiSpecific: true,
|
|
28313
|
+
message: `Unused ${binding.kind}: '${binding.name}'`,
|
|
28314
|
+
line: binding.line,
|
|
28315
|
+
column: binding.column,
|
|
28316
|
+
advice: `Remove the declaration or use '${binding.name}' somewhere in the file. This is the second-most-common AI-iteration signature \u2014 the model declared the binding when it introduced a feature, then rewrote the function without cleaning up.`
|
|
28317
|
+
});
|
|
28318
|
+
}
|
|
28319
|
+
return issues;
|
|
28320
|
+
}
|
|
28321
|
+
});
|
|
28322
|
+
}
|
|
28323
|
+
});
|
|
28324
|
+
|
|
28325
|
+
// src/rules/dead/unused-parameter.ts
|
|
28326
|
+
var unusedParameterRule;
|
|
28327
|
+
var init_unused_parameter = __esm({
|
|
28328
|
+
"src/rules/dead/unused-parameter.ts"() {
|
|
28329
|
+
"use strict";
|
|
28330
|
+
init_rule();
|
|
28331
|
+
unusedParameterRule = createRule({
|
|
28332
|
+
id: "dead/unused-parameter",
|
|
28333
|
+
category: "logic",
|
|
28334
|
+
severity: "low",
|
|
28335
|
+
aiSpecific: true,
|
|
28336
|
+
description: "Function parameter is declared but never read",
|
|
28337
|
+
create(_context) {
|
|
28338
|
+
return {};
|
|
28339
|
+
},
|
|
28340
|
+
analyze(_context, facts) {
|
|
28341
|
+
const issues = [];
|
|
28342
|
+
if (!facts.v2) return issues;
|
|
28343
|
+
for (const binding of facts.v2.deadCode.bindings) {
|
|
28344
|
+
if (binding.kind !== "parameter") continue;
|
|
28345
|
+
if (binding.isReferenced) continue;
|
|
28346
|
+
if (binding.name.startsWith("_")) continue;
|
|
28347
|
+
if (binding.name === "props") continue;
|
|
28348
|
+
issues.push({
|
|
28349
|
+
ruleId: "dead/unused-parameter",
|
|
28350
|
+
category: "logic",
|
|
28351
|
+
severity: "low",
|
|
28352
|
+
aiSpecific: true,
|
|
28353
|
+
message: `Unused parameter: '${binding.name}'`,
|
|
28354
|
+
line: binding.line,
|
|
28355
|
+
column: binding.column,
|
|
28356
|
+
advice: `Remove the parameter (and update every call site) or use '${binding.name}' in the function body. This is the AI-iteration signature: the model added the parameter when it introduced a feature, then rewrote the function without removing parameters the new code does not need.`
|
|
28357
|
+
});
|
|
28358
|
+
}
|
|
28359
|
+
return issues;
|
|
28360
|
+
}
|
|
28361
|
+
});
|
|
28362
|
+
}
|
|
28363
|
+
});
|
|
28364
|
+
|
|
28112
28365
|
// src/engine/discover.ts
|
|
28113
28366
|
var discover_exports = {};
|
|
28114
28367
|
__export(discover_exports, {
|
|
@@ -28218,14 +28471,14 @@ var init_discover = __esm({
|
|
|
28218
28471
|
function readDeps(cwd) {
|
|
28219
28472
|
const pkgPath = (0, import_node_path5.join)(cwd, "package.json");
|
|
28220
28473
|
if (!(0, import_node_fs5.existsSync)(pkgPath)) return /* @__PURE__ */ new Set();
|
|
28221
|
-
let
|
|
28474
|
+
let pkg;
|
|
28222
28475
|
try {
|
|
28223
|
-
|
|
28476
|
+
pkg = JSON.parse((0, import_node_fs5.readFileSync)(pkgPath, "utf-8"));
|
|
28224
28477
|
} catch {
|
|
28225
28478
|
return /* @__PURE__ */ new Set();
|
|
28226
28479
|
}
|
|
28227
28480
|
const out = /* @__PURE__ */ new Set();
|
|
28228
|
-
for (const source of [
|
|
28481
|
+
for (const source of [pkg.dependencies, pkg.devDependencies]) {
|
|
28229
28482
|
if (source && typeof source === "object") {
|
|
28230
28483
|
for (const name of Object.keys(source)) out.add(name);
|
|
28231
28484
|
}
|
|
@@ -28241,8 +28494,8 @@ function detectConstitution(cwd) {
|
|
|
28241
28494
|
const deps = readDeps(cwd);
|
|
28242
28495
|
if (deps.size === 0) return {};
|
|
28243
28496
|
const out = {};
|
|
28244
|
-
for (const [
|
|
28245
|
-
if (deps.has(
|
|
28497
|
+
for (const [pkg, { field, signal }] of Object.entries(CONSTITUTION_SIGNALS)) {
|
|
28498
|
+
if (deps.has(pkg)) {
|
|
28246
28499
|
out[field] = pushUnique(
|
|
28247
28500
|
out[field],
|
|
28248
28501
|
signal
|
|
@@ -29935,9 +30188,9 @@ function declaredPackages(cwd) {
|
|
|
29935
30188
|
if (!(0, import_node_fs8.existsSync)(pkgPath)) return out;
|
|
29936
30189
|
try {
|
|
29937
30190
|
const raw = (0, import_node_fs8.readFileSync)(pkgPath, "utf-8");
|
|
29938
|
-
const
|
|
30191
|
+
const pkg = JSON.parse(raw);
|
|
29939
30192
|
for (const k of ["dependencies", "devDependencies", "peerDependencies", "optionalDependencies"]) {
|
|
29940
|
-
const v =
|
|
30193
|
+
const v = pkg[k];
|
|
29941
30194
|
if (v && typeof v === "object") {
|
|
29942
30195
|
for (const name of Object.keys(v)) {
|
|
29943
30196
|
out.add(name);
|
|
@@ -30367,7 +30620,7 @@ var init_spacing_grid = __esm({
|
|
|
30367
30620
|
"use strict";
|
|
30368
30621
|
init_rule();
|
|
30369
30622
|
init_utils();
|
|
30370
|
-
|
|
30623
|
+
init_config2();
|
|
30371
30624
|
SPACING_PREFIX_RE = /^-?(p|px|py|pt|pr|pb|pl|m|mx|my|mt|mr|mb|ml|gap|gap-x|gap-y|space-x|space-y)-(.+)$/;
|
|
30372
30625
|
ARBITRARY_VALUE_RE2 = /^(-?\d+(?:\.\d+)?)(px|rem)$/;
|
|
30373
30626
|
SKIP_VALUES = /* @__PURE__ */ new Set(["auto", "full", "screen", "min", "max", "fit", "none"]);
|
|
@@ -42455,6 +42708,78 @@ function extractStateBinding(node, lineOffsets) {
|
|
|
42455
42708
|
setterReferenced: false
|
|
42456
42709
|
};
|
|
42457
42710
|
}
|
|
42711
|
+
function findUnreachableStatements(ast, source, lineOffsets) {
|
|
42712
|
+
const out = [];
|
|
42713
|
+
function isTerminator(node) {
|
|
42714
|
+
if (node.type === "ReturnStatement") return "return";
|
|
42715
|
+
if (node.type === "ThrowStatement") return "throw";
|
|
42716
|
+
if (node.type === "BreakStatement") return "break";
|
|
42717
|
+
if (node.type === "ContinueStatement") return "continue";
|
|
42718
|
+
return null;
|
|
42719
|
+
}
|
|
42720
|
+
function snippetFor(node, src) {
|
|
42721
|
+
const span = node.span;
|
|
42722
|
+
if (!span || typeof span.start !== "number" || typeof span.end !== "number") {
|
|
42723
|
+
return "<unreachable>";
|
|
42724
|
+
}
|
|
42725
|
+
const text = src.slice(span.start, Math.min(span.end, span.start + 60));
|
|
42726
|
+
return text.replace(/\s+/g, " ").trim() || "<unreachable>";
|
|
42727
|
+
}
|
|
42728
|
+
function lineColumn(offset) {
|
|
42729
|
+
let lo = 0;
|
|
42730
|
+
let hi = lineOffsets.length - 1;
|
|
42731
|
+
while (lo < hi) {
|
|
42732
|
+
const mid = lo + hi + 1 >>> 1;
|
|
42733
|
+
const midVal = lineOffsets[mid];
|
|
42734
|
+
const loVal = lineOffsets[lo];
|
|
42735
|
+
if (midVal === void 0) break;
|
|
42736
|
+
if (midVal <= offset) lo = mid;
|
|
42737
|
+
else hi = mid - 1;
|
|
42738
|
+
void loVal;
|
|
42739
|
+
}
|
|
42740
|
+
const baseOffset = lineOffsets[lo] ?? 0;
|
|
42741
|
+
return { line: lo + 1, column: offset - baseOffset };
|
|
42742
|
+
}
|
|
42743
|
+
function visitBody(body) {
|
|
42744
|
+
if (!Array.isArray(body)) return;
|
|
42745
|
+
let lastTerminator = null;
|
|
42746
|
+
for (const stmt of body) {
|
|
42747
|
+
if (!isObject(stmt)) continue;
|
|
42748
|
+
if (lastTerminator && stmt.type !== "EmptyStatement") {
|
|
42749
|
+
const span = stmt.span;
|
|
42750
|
+
const offset = typeof span?.start === "number" ? span.start : 0;
|
|
42751
|
+
const { line, column } = lineColumn(offset);
|
|
42752
|
+
out.push({
|
|
42753
|
+
terminator: lastTerminator,
|
|
42754
|
+
line,
|
|
42755
|
+
column,
|
|
42756
|
+
snippet: snippetFor(stmt, source)
|
|
42757
|
+
});
|
|
42758
|
+
}
|
|
42759
|
+
const t = isTerminator(stmt);
|
|
42760
|
+
if (t) lastTerminator = t;
|
|
42761
|
+
}
|
|
42762
|
+
}
|
|
42763
|
+
function walk3(node) {
|
|
42764
|
+
if (!isObject(node)) return;
|
|
42765
|
+
if (node.type === "BlockStatement") {
|
|
42766
|
+
visitBody(node.stmts);
|
|
42767
|
+
} else if (node.type === "Module") {
|
|
42768
|
+
visitBody(node.body);
|
|
42769
|
+
}
|
|
42770
|
+
for (const key of Object.keys(node)) {
|
|
42771
|
+
if (key === "parent" || key === "span" || key === "ctxt") continue;
|
|
42772
|
+
const child = node[key];
|
|
42773
|
+
if (Array.isArray(child)) {
|
|
42774
|
+
for (const c of child) walk3(c);
|
|
42775
|
+
} else {
|
|
42776
|
+
walk3(child);
|
|
42777
|
+
}
|
|
42778
|
+
}
|
|
42779
|
+
}
|
|
42780
|
+
walk3(ast);
|
|
42781
|
+
return out;
|
|
42782
|
+
}
|
|
42458
42783
|
var init_scan_helpers = __esm({
|
|
42459
42784
|
"src/engine/visitors/scan-helpers.ts"() {
|
|
42460
42785
|
"use strict";
|
|
@@ -42540,15 +42865,42 @@ function handleImportDeclaration(node, _parent, _path, vctx) {
|
|
|
42540
42865
|
if (specifier.type === "ImportDefaultSpecifier" || specifier.type === "ImportNamespaceSpecifier") {
|
|
42541
42866
|
const local = specifier.local;
|
|
42542
42867
|
if (isObject(local) && local.type === "Identifier" && typeof local.value === "string") {
|
|
42543
|
-
|
|
42868
|
+
const name = local.value;
|
|
42869
|
+
importedNames.push(name);
|
|
42870
|
+
vctx.facts.deadCode.bindings.push({
|
|
42871
|
+
name,
|
|
42872
|
+
kind: specifier.type === "ImportDefaultSpecifier" ? "import-default" : "import-namespace",
|
|
42873
|
+
line,
|
|
42874
|
+
column,
|
|
42875
|
+
source,
|
|
42876
|
+
isReferenced: false
|
|
42877
|
+
});
|
|
42544
42878
|
}
|
|
42545
42879
|
} else if (specifier.type === "ImportSpecifier") {
|
|
42546
42880
|
const imported = specifier.imported;
|
|
42547
42881
|
const local = specifier.local;
|
|
42548
42882
|
if (isObject(imported) && typeof imported.value === "string" && imported.value.length > 0) {
|
|
42549
|
-
|
|
42883
|
+
const name = imported.value;
|
|
42884
|
+
importedNames.push(name);
|
|
42885
|
+
vctx.facts.deadCode.bindings.push({
|
|
42886
|
+
name,
|
|
42887
|
+
kind: "import-specifier",
|
|
42888
|
+
line,
|
|
42889
|
+
column,
|
|
42890
|
+
source,
|
|
42891
|
+
isReferenced: false
|
|
42892
|
+
});
|
|
42550
42893
|
} else if (isObject(local) && local.type === "Identifier" && typeof local.value === "string") {
|
|
42551
|
-
|
|
42894
|
+
const name = local.value;
|
|
42895
|
+
importedNames.push(name);
|
|
42896
|
+
vctx.facts.deadCode.bindings.push({
|
|
42897
|
+
name,
|
|
42898
|
+
kind: "import-specifier",
|
|
42899
|
+
line,
|
|
42900
|
+
column,
|
|
42901
|
+
source,
|
|
42902
|
+
isReferenced: false
|
|
42903
|
+
});
|
|
42552
42904
|
}
|
|
42553
42905
|
}
|
|
42554
42906
|
}
|
|
@@ -42638,6 +42990,13 @@ function isBindingSite(node, parent) {
|
|
|
42638
42990
|
if (params.some((param) => containsNode(param, node))) return true;
|
|
42639
42991
|
}
|
|
42640
42992
|
}
|
|
42993
|
+
if (parent.type === "ImportSpecifier" || parent.type === "ImportDefaultSpecifier" || parent.type === "ImportNamespaceSpecifier") {
|
|
42994
|
+
if (parent.type === "ImportSpecifier") {
|
|
42995
|
+
if (parent.imported === node || parent.local === node) return true;
|
|
42996
|
+
} else {
|
|
42997
|
+
if (parent.local === node) return true;
|
|
42998
|
+
}
|
|
42999
|
+
}
|
|
42641
43000
|
return false;
|
|
42642
43001
|
}
|
|
42643
43002
|
function isNonComputedMemberProperty(node, parent) {
|
|
@@ -42704,6 +43063,9 @@ function handleIdentifier(node, parent, path, vctx) {
|
|
|
42704
43063
|
if (typeof node.value === "string" && !isBindingSite(node, parent) && !isNonComputedMemberProperty(node, parent)) {
|
|
42705
43064
|
markStateReference(node.value, vctx);
|
|
42706
43065
|
trackPropUsage(node, parent, path, vctx);
|
|
43066
|
+
vctx.facts.referencedNames.add(node.value);
|
|
43067
|
+
const top = vctx.ctx.stack[vctx.ctx.stack.length - 1];
|
|
43068
|
+
if (top) top.references.add(node.value);
|
|
42707
43069
|
}
|
|
42708
43070
|
return false;
|
|
42709
43071
|
}
|
|
@@ -42844,6 +43206,20 @@ function handleVariableDeclarator(node, _parent, path, vctx) {
|
|
|
42844
43206
|
frame.bindings.add(bindingName);
|
|
42845
43207
|
}
|
|
42846
43208
|
}
|
|
43209
|
+
if (bindingNames.length > 0) {
|
|
43210
|
+
const parent = node.parent;
|
|
43211
|
+
const kind = isObject(parent) && parent.type === "VariableDeclaration" ? String(parent.kind ?? "var") : "var";
|
|
43212
|
+
const { line, column } = positionFrom(id, vctx.lineOffsets);
|
|
43213
|
+
for (const bindingName of bindingNames) {
|
|
43214
|
+
vctx.facts.deadCode.bindings.push({
|
|
43215
|
+
name: bindingName,
|
|
43216
|
+
kind,
|
|
43217
|
+
line,
|
|
43218
|
+
column,
|
|
43219
|
+
isReferenced: false
|
|
43220
|
+
});
|
|
43221
|
+
}
|
|
43222
|
+
}
|
|
42847
43223
|
if (isUseStateDeclarator(node)) {
|
|
42848
43224
|
const binding = extractStateBinding(node, vctx.lineOffsets);
|
|
42849
43225
|
if (binding) {
|
|
@@ -42863,6 +43239,36 @@ function handleVariableDeclarator(node, _parent, path, vctx) {
|
|
|
42863
43239
|
}
|
|
42864
43240
|
return true;
|
|
42865
43241
|
}
|
|
43242
|
+
function handleIfStatement(node, _parent, _path, vctx) {
|
|
43243
|
+
if (!isObject(node)) return false;
|
|
43244
|
+
const test = node.test;
|
|
43245
|
+
if (!isObject(test)) return false;
|
|
43246
|
+
if (test.type === "BooleanLiteral" && typeof test.value === "boolean") {
|
|
43247
|
+
const { line, column } = positionFrom(test, vctx.lineOffsets);
|
|
43248
|
+
vctx.facts.deadCode.constantConditions.push({
|
|
43249
|
+
kind: test.value ? "if-true" : "if-false",
|
|
43250
|
+
condition: String(test.value),
|
|
43251
|
+
line,
|
|
43252
|
+
column
|
|
43253
|
+
});
|
|
43254
|
+
}
|
|
43255
|
+
return false;
|
|
43256
|
+
}
|
|
43257
|
+
function handleWhileStatement(node, _parent, _path, vctx) {
|
|
43258
|
+
if (!isObject(node)) return false;
|
|
43259
|
+
const test = node.test;
|
|
43260
|
+
if (!isObject(test)) return false;
|
|
43261
|
+
if (test.type === "BooleanLiteral" && typeof test.value === "boolean") {
|
|
43262
|
+
const { line, column } = positionFrom(test, vctx.lineOffsets);
|
|
43263
|
+
vctx.facts.deadCode.constantConditions.push({
|
|
43264
|
+
kind: test.value ? "while-true" : "while-false",
|
|
43265
|
+
condition: String(test.value),
|
|
43266
|
+
line,
|
|
43267
|
+
column
|
|
43268
|
+
});
|
|
43269
|
+
}
|
|
43270
|
+
return false;
|
|
43271
|
+
}
|
|
42866
43272
|
function dispatchNode(node, parent, path, vctx) {
|
|
42867
43273
|
if (!isObject(node)) return false;
|
|
42868
43274
|
const type = getNodeType(node);
|
|
@@ -42887,7 +43293,9 @@ var init_dispatch = __esm({
|
|
|
42887
43293
|
MemberExpression: handleMemberExpression,
|
|
42888
43294
|
JSXAttribute: handleJSXAttribute,
|
|
42889
43295
|
JSXOpeningElement: handleJSXOpeningElement,
|
|
42890
|
-
VariableDeclarator: handleVariableDeclarator
|
|
43296
|
+
VariableDeclarator: handleVariableDeclarator,
|
|
43297
|
+
IfStatement: handleIfStatement,
|
|
43298
|
+
WhileStatement: handleWhileStatement
|
|
42891
43299
|
};
|
|
42892
43300
|
}
|
|
42893
43301
|
});
|
|
@@ -43038,6 +43446,17 @@ function buildV2Facts(facts, source, ext, framework, config, templateClassNames
|
|
|
43038
43446
|
},
|
|
43039
43447
|
logic: buildLogicBlock(facts),
|
|
43040
43448
|
designTokens: scanDesignTokens(facts.staticClassNames),
|
|
43449
|
+
// dead-code detector. Copy the internal accumulator
|
|
43450
|
+
// into the v2 shape, marking each binding as referenced
|
|
43451
|
+
// iff the file-level referenced-name set contains its name.
|
|
43452
|
+
deadCode: {
|
|
43453
|
+
bindings: facts.deadCode.bindings.map((b) => ({
|
|
43454
|
+
...b,
|
|
43455
|
+
isReferenced: facts.referencedNames.has(b.name)
|
|
43456
|
+
})),
|
|
43457
|
+
constantConditions: facts.deadCode.constantConditions,
|
|
43458
|
+
unreachableStatements: facts.deadCode.unreachableStatements
|
|
43459
|
+
},
|
|
43041
43460
|
componentSizes: facts.componentSizes.map((cs) => ({
|
|
43042
43461
|
name: cs.name,
|
|
43043
43462
|
lineCount: cs.lineCount,
|
|
@@ -43119,7 +43538,17 @@ function extractFacts(filePath, ast, source, supportsRsc = true, framework = "re
|
|
|
43119
43538
|
componentSizes: [],
|
|
43120
43539
|
astroComponents: [],
|
|
43121
43540
|
fetchCalls: [],
|
|
43122
|
-
optimisticUpdates: []
|
|
43541
|
+
optimisticUpdates: [],
|
|
43542
|
+
// dead-code detector. The visitor's identifier walk + import/
|
|
43543
|
+
// branch/return handlers populate these. The v2 builder at the
|
|
43544
|
+
// bottom of extractFacts() reads them and produces
|
|
43545
|
+
// `facts.v2.deadCode`.
|
|
43546
|
+
deadCode: {
|
|
43547
|
+
bindings: [],
|
|
43548
|
+
constantConditions: [],
|
|
43549
|
+
unreachableStatements: []
|
|
43550
|
+
},
|
|
43551
|
+
referencedNames: /* @__PURE__ */ new Set()
|
|
43123
43552
|
};
|
|
43124
43553
|
const ctx = {
|
|
43125
43554
|
stack: [],
|
|
@@ -43206,6 +43635,16 @@ function extractFacts(filePath, ast, source, supportsRsc = true, framework = "re
|
|
|
43206
43635
|
propBindingSet.add(bindingName);
|
|
43207
43636
|
}
|
|
43208
43637
|
}
|
|
43638
|
+
const { line: pLine, column: pCol } = positionFrom(param, lineOffsets);
|
|
43639
|
+
for (const bindingName of collectBindingNames2(param)) {
|
|
43640
|
+
facts.deadCode.bindings.push({
|
|
43641
|
+
name: bindingName,
|
|
43642
|
+
kind: "parameter",
|
|
43643
|
+
line: pLine,
|
|
43644
|
+
column: pCol,
|
|
43645
|
+
isReferenced: false
|
|
43646
|
+
});
|
|
43647
|
+
}
|
|
43209
43648
|
}
|
|
43210
43649
|
}
|
|
43211
43650
|
ctx.stack.push({
|
|
@@ -43221,6 +43660,12 @@ function extractFacts(filePath, ast, source, supportsRsc = true, framework = "re
|
|
|
43221
43660
|
propUsages: [],
|
|
43222
43661
|
isComponent,
|
|
43223
43662
|
bindings,
|
|
43663
|
+
// dead-code detector: per-frame referenced-name set.
|
|
43664
|
+
// Identifiers encountered inside the frame are added to this
|
|
43665
|
+
// set; the deadCode builder unions it with parent frames at
|
|
43666
|
+
// pop time so a binding is considered used if any reachable
|
|
43667
|
+
// scope references it.
|
|
43668
|
+
references: /* @__PURE__ */ new Set(),
|
|
43224
43669
|
propBindingSet,
|
|
43225
43670
|
propUsageSet: /* @__PURE__ */ new Set(),
|
|
43226
43671
|
node
|
|
@@ -43316,6 +43761,11 @@ function extractFacts(filePath, ast, source, supportsRsc = true, framework = "re
|
|
|
43316
43761
|
mergeTemplateClassNames(filePath, source, facts, templateClassNames);
|
|
43317
43762
|
const { ext } = splitFilePath(filePath);
|
|
43318
43763
|
facts._source = source;
|
|
43764
|
+
facts.deadCode.unreachableStatements = findUnreachableStatements(
|
|
43765
|
+
ast,
|
|
43766
|
+
source,
|
|
43767
|
+
lineOffsets
|
|
43768
|
+
);
|
|
43319
43769
|
const v2 = buildV2Facts(facts, source, ext, framework, config, templateClassNames);
|
|
43320
43770
|
return envelopeScanFacts(filePath, v2);
|
|
43321
43771
|
}
|
|
@@ -43998,6 +44448,11 @@ var init_builtins = __esm({
|
|
|
43998
44448
|
init_missing_not_null();
|
|
43999
44449
|
init_naming_inconsistency();
|
|
44000
44450
|
init_sql_concat();
|
|
44451
|
+
init_dead_branch();
|
|
44452
|
+
init_unreachable();
|
|
44453
|
+
init_unused_import();
|
|
44454
|
+
init_unused_local();
|
|
44455
|
+
init_unused_parameter();
|
|
44001
44456
|
init_broken_link();
|
|
44002
44457
|
init_expired_code_example();
|
|
44003
44458
|
init_stale_function_reference();
|
|
@@ -44094,6 +44549,11 @@ var init_builtins = __esm({
|
|
|
44094
44549
|
missingNotNullRule,
|
|
44095
44550
|
namingInconsistencyRule,
|
|
44096
44551
|
sqlConcatRule,
|
|
44552
|
+
deadBranchRule,
|
|
44553
|
+
unreachableRule,
|
|
44554
|
+
unusedImportRule,
|
|
44555
|
+
unusedLocalRule,
|
|
44556
|
+
unusedParameterRule,
|
|
44097
44557
|
brokenLinkRule,
|
|
44098
44558
|
expiredCodeExampleRule,
|
|
44099
44559
|
staleFunctionReferenceRule,
|
|
@@ -44665,8 +45125,8 @@ function detectJsLoader(configPath) {
|
|
|
44665
45125
|
const pkgPath = (0, import_node_path10.join)(current, "package.json");
|
|
44666
45126
|
if ((0, import_node_fs11.existsSync)(pkgPath)) {
|
|
44667
45127
|
try {
|
|
44668
|
-
const
|
|
44669
|
-
return
|
|
45128
|
+
const pkg = JSON.parse((0, import_node_fs11.readFileSync)(pkgPath, "utf-8"));
|
|
45129
|
+
return pkg.type === "module" ? "import" : "require";
|
|
44670
45130
|
} catch {
|
|
44671
45131
|
return "require";
|
|
44672
45132
|
}
|
|
@@ -44680,7 +45140,7 @@ function detectJsLoader(configPath) {
|
|
|
44680
45140
|
async function loadConfigFile(path) {
|
|
44681
45141
|
const loader = detectJsLoader(path);
|
|
44682
45142
|
if (loader === "require") {
|
|
44683
|
-
const req = (0,
|
|
45143
|
+
const req = (0, import_node_module.createRequire)(__importMetaUrl);
|
|
44684
45144
|
const mod2 = req(path);
|
|
44685
45145
|
return mod2.default ?? mod2;
|
|
44686
45146
|
}
|
|
@@ -44712,13 +45172,13 @@ async function loadConfig(cwd) {
|
|
|
44712
45172
|
);
|
|
44713
45173
|
return merged;
|
|
44714
45174
|
}
|
|
44715
|
-
var import_node_fs11, import_node_path10,
|
|
45175
|
+
var import_node_fs11, import_node_path10, import_node_module;
|
|
44716
45176
|
var init_load = __esm({
|
|
44717
45177
|
"src/config/load.ts"() {
|
|
44718
45178
|
"use strict";
|
|
44719
45179
|
import_node_fs11 = require("fs");
|
|
44720
45180
|
import_node_path10 = require("path");
|
|
44721
|
-
|
|
45181
|
+
import_node_module = require("module");
|
|
44722
45182
|
init_logger();
|
|
44723
45183
|
init_validation();
|
|
44724
45184
|
init_defaults();
|
|
@@ -44865,7 +45325,7 @@ var init_init = __esm({
|
|
|
44865
45325
|
});
|
|
44866
45326
|
|
|
44867
45327
|
// src/config/index.ts
|
|
44868
|
-
var
|
|
45328
|
+
var init_config2 = __esm({
|
|
44869
45329
|
"src/config/index.ts"() {
|
|
44870
45330
|
"use strict";
|
|
44871
45331
|
init_defaults();
|
|
@@ -47012,6 +47472,61 @@ var init_signal_strength = __esm({
|
|
|
47012
47472
|
_calibrationNote: "v0.17.0 ship \u2014 not in v7 per-rule table. Default-off until calibration data lands. Backed by: OWASP Foundation (2021), *OWASP Top 10 \u2014 A03:2021 Injection*, https://owasp.org/Top10/A03_2021-Injection/; OWASP Foundation (2017), *SQL Injection Prevention Cheat Sheet*. (Template-literal SQL with ${...} interpolation is the #1 SQL injection vector in AI-generated TypeScript code.)",
|
|
47013
47473
|
aiSpecific: true
|
|
47014
47474
|
},
|
|
47475
|
+
"dead/unused-import": {
|
|
47476
|
+
recall: 0,
|
|
47477
|
+
fpRate: 0,
|
|
47478
|
+
ratio: 0,
|
|
47479
|
+
precision: 0,
|
|
47480
|
+
lastCalibratedAt: "2026-06-30T00:00:00Z",
|
|
47481
|
+
verdict: "DORMANT",
|
|
47482
|
+
defaultOff: true,
|
|
47483
|
+
_calibrationNote: "v0.18.5 ship \u2014 not in v7 per-rule table. Default-off until v8 calibration data lands. The first of 5 planned `dead/*` rules (this one + dead/unused-local + dead/unused-parameter + dead/dead-branch + dead/unreachable). The pattern is the canonical AI-iteration rot: the model adds an import when introducing a feature, then rewrites the function later without cleaning up. Most real-world tsconfig.json files have `noUnusedLocals: false`, so tsc never fires.",
|
|
47484
|
+
aiSpecific: true
|
|
47485
|
+
},
|
|
47486
|
+
"dead/unused-local": {
|
|
47487
|
+
recall: 0,
|
|
47488
|
+
fpRate: 0,
|
|
47489
|
+
ratio: 0,
|
|
47490
|
+
precision: 0,
|
|
47491
|
+
lastCalibratedAt: "2026-06-30T00:00:00Z",
|
|
47492
|
+
verdict: "DORMANT",
|
|
47493
|
+
defaultOff: true,
|
|
47494
|
+
_calibrationNote: "v0.18.5b ship \u2014 not in v7 per-rule table. Default-off until v8 calibration data lands. The second of 5 planned `dead/*` rules. Muchnick 1997 Ch. 13 'liveness analysis' (textbook compiler optimization).",
|
|
47495
|
+
aiSpecific: true
|
|
47496
|
+
},
|
|
47497
|
+
"dead/unused-parameter": {
|
|
47498
|
+
recall: 0,
|
|
47499
|
+
fpRate: 0,
|
|
47500
|
+
ratio: 0,
|
|
47501
|
+
precision: 0,
|
|
47502
|
+
lastCalibratedAt: "2026-06-30T00:00:00Z",
|
|
47503
|
+
verdict: "DORMANT",
|
|
47504
|
+
defaultOff: true,
|
|
47505
|
+
_calibrationNote: "v0.18.5b ship \u2014 not in v7 per-rule table. Default-off until v8 calibration data lands. The third of 5 planned `dead/*` rules. AI agents add parameters when introducing features, then rewrite the function without removing parameters the new code does not need.",
|
|
47506
|
+
aiSpecific: true
|
|
47507
|
+
},
|
|
47508
|
+
"dead/dead-branch": {
|
|
47509
|
+
recall: 0,
|
|
47510
|
+
fpRate: 0,
|
|
47511
|
+
ratio: 0,
|
|
47512
|
+
precision: 0,
|
|
47513
|
+
lastCalibratedAt: "2026-06-30T00:00:00Z",
|
|
47514
|
+
verdict: "DORMANT",
|
|
47515
|
+
defaultOff: true,
|
|
47516
|
+
_calibrationNote: "v0.18.5b ship \u2014 not in v7 per-rule table. Default-off until v8 calibration data lands. The fourth of 5 planned `dead/*` rules. AI-iteration signature: feature flag toggled to a constant, or wrapper from a previous refactor.",
|
|
47517
|
+
aiSpecific: true
|
|
47518
|
+
},
|
|
47519
|
+
"dead/unreachable": {
|
|
47520
|
+
recall: 0,
|
|
47521
|
+
fpRate: 0,
|
|
47522
|
+
ratio: 0,
|
|
47523
|
+
precision: 0,
|
|
47524
|
+
lastCalibratedAt: "2026-06-30T00:00:00Z",
|
|
47525
|
+
verdict: "DORMANT",
|
|
47526
|
+
defaultOff: true,
|
|
47527
|
+
_calibrationNote: "v0.18.5b ship \u2014 not in v7 per-rule table. Default-off until v8 calibration data lands. The fifth of 5 planned `dead/*` rules. AI-iteration signature: model added an early return for a new error path, then forgot the rest of the function body was still sitting below it.",
|
|
47528
|
+
aiSpecific: true
|
|
47529
|
+
},
|
|
47015
47530
|
"docs/stale-package-reference": {
|
|
47016
47531
|
recall: 0,
|
|
47017
47532
|
fpRate: 0,
|
|
@@ -47973,7 +48488,7 @@ var init_cache = __esm({
|
|
|
47973
48488
|
import_node_fs16 = require("fs");
|
|
47974
48489
|
import_node_path17 = require("path");
|
|
47975
48490
|
init_types();
|
|
47976
|
-
|
|
48491
|
+
init_config2();
|
|
47977
48492
|
BASELINE_VERSION = VERSION;
|
|
47978
48493
|
BASELINE_HASH_KEYS = /* @__PURE__ */ new Set([
|
|
47979
48494
|
"framework",
|
|
@@ -50457,7 +50972,7 @@ var init_finalizeReport = __esm({
|
|
|
50457
50972
|
init_dist2();
|
|
50458
50973
|
init_logger();
|
|
50459
50974
|
init_memory_io();
|
|
50460
|
-
|
|
50975
|
+
init_config2();
|
|
50461
50976
|
init_enrichReport();
|
|
50462
50977
|
init_assembleScanReport();
|
|
50463
50978
|
init_persistRun();
|
|
@@ -52382,11 +52897,11 @@ var init_watch = __esm({
|
|
|
52382
52897
|
init_worker();
|
|
52383
52898
|
init_threshold();
|
|
52384
52899
|
init_cache();
|
|
52385
|
-
|
|
52900
|
+
init_config2();
|
|
52386
52901
|
init_render();
|
|
52387
52902
|
init_logger();
|
|
52388
52903
|
init_error();
|
|
52389
|
-
|
|
52904
|
+
init_scan2();
|
|
52390
52905
|
init_renderOutput();
|
|
52391
52906
|
init_types();
|
|
52392
52907
|
}
|
|
@@ -52667,14 +53182,14 @@ async function scanProject(options) {
|
|
|
52667
53182
|
return report;
|
|
52668
53183
|
}
|
|
52669
53184
|
var import_node_fs28, import_node_path30;
|
|
52670
|
-
var
|
|
53185
|
+
var init_scan2 = __esm({
|
|
52671
53186
|
"src/cli/scan.ts"() {
|
|
52672
53187
|
"use strict";
|
|
52673
53188
|
import_node_fs28 = require("fs");
|
|
52674
53189
|
import_node_path30 = require("path");
|
|
52675
53190
|
init_render();
|
|
52676
53191
|
init_threshold();
|
|
52677
|
-
|
|
53192
|
+
init_config2();
|
|
52678
53193
|
init_discover();
|
|
52679
53194
|
init_git();
|
|
52680
53195
|
init_cache_incremental();
|
|
@@ -52844,7 +53359,7 @@ async function runSuggest(args, ctx) {
|
|
|
52844
53359
|
}
|
|
52845
53360
|
async function runGovernance(args, ctx) {
|
|
52846
53361
|
try {
|
|
52847
|
-
const { runScan: runScan3 } = await Promise.resolve().then(() => (
|
|
53362
|
+
const { runScan: runScan3 } = await Promise.resolve().then(() => (init_scan2(), scan_exports));
|
|
52848
53363
|
const maxFiles = typeof args.maxFiles === "number" && Number.isFinite(args.maxFiles) && args.maxFiles > 0 ? Math.floor(args.maxFiles) : 500;
|
|
52849
53364
|
const { report } = await runScan3({
|
|
52850
53365
|
workspace: ctx.cwd,
|
|
@@ -53326,7 +53841,7 @@ __export(src_exports, {
|
|
|
53326
53841
|
});
|
|
53327
53842
|
module.exports = __toCommonJS(src_exports);
|
|
53328
53843
|
init_types();
|
|
53329
|
-
|
|
53844
|
+
init_config2();
|
|
53330
53845
|
init_dist2();
|
|
53331
53846
|
|
|
53332
53847
|
// src/cli/program.ts
|
|
@@ -53370,14 +53885,14 @@ function parseThreshold(value) {
|
|
|
53370
53885
|
// src/cli/program.ts
|
|
53371
53886
|
init_render();
|
|
53372
53887
|
init_threshold();
|
|
53373
|
-
|
|
53374
|
-
|
|
53888
|
+
init_scan2();
|
|
53889
|
+
init_scan2();
|
|
53375
53890
|
|
|
53376
53891
|
// src/cli/init.ts
|
|
53377
53892
|
var import_node_fs30 = require("fs");
|
|
53378
53893
|
var import_node_path32 = require("path");
|
|
53379
53894
|
var import_node_readline = require("readline");
|
|
53380
|
-
|
|
53895
|
+
init_config2();
|
|
53381
53896
|
init_discover();
|
|
53382
53897
|
init_git();
|
|
53383
53898
|
init_cache();
|
|
@@ -53867,7 +54382,7 @@ async function runDoctor(cwd) {
|
|
|
53867
54382
|
var import_node_path33 = require("path");
|
|
53868
54383
|
init_render();
|
|
53869
54384
|
init_logger();
|
|
53870
|
-
|
|
54385
|
+
init_scan2();
|
|
53871
54386
|
function registerBadge(program) {
|
|
53872
54387
|
program.command("badge").description(
|
|
53873
54388
|
"print a shields.io slop-index badge. Reads .slopbrick/health.json if present (no re-scan); falls back to a fresh scan."
|
|
@@ -53894,7 +54409,7 @@ var import_node_path34 = require("path");
|
|
|
53894
54409
|
init_advice();
|
|
53895
54410
|
init_unified_diff();
|
|
53896
54411
|
init_logger();
|
|
53897
|
-
|
|
54412
|
+
init_scan2();
|
|
53898
54413
|
function registerSuggest(program) {
|
|
53899
54414
|
program.command("suggest").description("print remediation advice").action(async (_cmdOptions, command) => {
|
|
53900
54415
|
const options = command.optsWithGlobals();
|
|
@@ -54021,6 +54536,11 @@ var RULE_HINTS = {
|
|
|
54021
54536
|
"logic/qwik-hook-leak": "Use Qwik primitives ($state, $effect, useSignal) instead of React hooks (useState, useEffect).",
|
|
54022
54537
|
"logic/reactive-hook-soup": "Coordinate state via a single derived value (useMemo) or a state machine. Avoid chained useEffects that sync local state.",
|
|
54023
54538
|
"logic/zombie-state": "Remove unused useState or wire it into the component. Don't leave declared-but-never-read state bindings.",
|
|
54539
|
+
"dead/unused-import": "Remove the import or use the symbol somewhere. Unused imports are the most common AI-iteration signature \u2014 the model added it for a feature, then rewrote the function without cleaning up.",
|
|
54540
|
+
"dead/unused-local": "Remove the declaration or use the variable. AI-iteration signature: the model declared a binding for a feature, then rewrote the function without cleaning up.",
|
|
54541
|
+
"dead/unused-parameter": "Remove the parameter (and update every call site) or use it in the function body. AI-iteration signature: the model added a parameter for a feature, then rewrote the function without removing parameters the new code does not need.",
|
|
54542
|
+
"dead/dead-branch": "Replace the literal boolean with a real condition, or remove the dead branch. AI-iteration signature: a feature flag toggled to a constant, or a wrapper from a previous refactor that was never cleaned up.",
|
|
54543
|
+
"dead/unreachable": "Remove this statement \u2014 code after a return/throw/break/continue is unreachable. AI-iteration signature: the model added an early return for a new error path, then forgot the rest of the function body was still sitting below it.",
|
|
54024
54544
|
"perf/cls-image": "Add width/height attributes or an aspect-ratio utility to prevent layout shift.",
|
|
54025
54545
|
"perf/css-bloat": "Extract to a CSS variable (`--surface-card`) or a component prop when a class string repeats 5+ times.",
|
|
54026
54546
|
"perf/halstead-anomaly": "Introduce domain-specific identifiers and varied operations. Low vocabulary per line is a strong AI signature (Halstead 1977 \xA73).",
|
|
@@ -54275,7 +54795,7 @@ init_logger();
|
|
|
54275
54795
|
|
|
54276
54796
|
// src/mcp/server.ts
|
|
54277
54797
|
init_builtins();
|
|
54278
|
-
|
|
54798
|
+
init_config2();
|
|
54279
54799
|
init_tools();
|
|
54280
54800
|
var SERVER_INFO = {
|
|
54281
54801
|
name: "slopbrick",
|
|
@@ -55705,7 +56225,7 @@ function registerTrend(program) {
|
|
|
55705
56225
|
// src/cli/commands/drift.ts
|
|
55706
56226
|
var import_node_path51 = require("path");
|
|
55707
56227
|
init_logger();
|
|
55708
|
-
|
|
56228
|
+
init_scan2();
|
|
55709
56229
|
|
|
55710
56230
|
// src/cli/drift.ts
|
|
55711
56231
|
var import_node_fs38 = require("fs");
|
|
@@ -55846,7 +56366,7 @@ function registerDrift(program) {
|
|
|
55846
56366
|
// src/cli/commands/pr.ts
|
|
55847
56367
|
var import_node_path53 = require("path");
|
|
55848
56368
|
init_logger();
|
|
55849
|
-
|
|
56369
|
+
init_scan2();
|
|
55850
56370
|
|
|
55851
56371
|
// src/cli/pr.ts
|
|
55852
56372
|
var import_node_fs39 = require("fs");
|
|
@@ -56135,7 +56655,7 @@ function registerPr(program) {
|
|
|
56135
56655
|
// src/cli/commands/security.ts
|
|
56136
56656
|
var import_node_path54 = require("path");
|
|
56137
56657
|
init_logger();
|
|
56138
|
-
|
|
56658
|
+
init_scan2();
|
|
56139
56659
|
init_ai_security_risk();
|
|
56140
56660
|
function registerSecurity(program) {
|
|
56141
56661
|
program.command("security").description(
|
|
@@ -56194,11 +56714,11 @@ function registerSecurity(program) {
|
|
|
56194
56714
|
// src/cli/commands/test.ts
|
|
56195
56715
|
var import_node_path56 = require("path");
|
|
56196
56716
|
init_logger();
|
|
56197
|
-
|
|
56717
|
+
init_scan2();
|
|
56198
56718
|
|
|
56199
56719
|
// src/cli/test.ts
|
|
56200
56720
|
var import_node_path55 = require("path");
|
|
56201
|
-
|
|
56721
|
+
init_scan2();
|
|
56202
56722
|
init_test_quality();
|
|
56203
56723
|
init_logger();
|
|
56204
56724
|
var TEST_INCLUDE_GLOBS = [
|
|
@@ -56313,7 +56833,7 @@ function registerTest(program) {
|
|
|
56313
56833
|
// src/cli/commands/architecture.ts
|
|
56314
56834
|
var import_node_path57 = require("path");
|
|
56315
56835
|
init_logger();
|
|
56316
|
-
|
|
56836
|
+
init_scan2();
|
|
56317
56837
|
init_architecture_score();
|
|
56318
56838
|
function registerArchitecture(program) {
|
|
56319
56839
|
program.command("architecture").description(
|
|
@@ -56341,7 +56861,7 @@ function registerArchitecture(program) {
|
|
|
56341
56861
|
// src/cli/commands/business-logic.ts
|
|
56342
56862
|
var import_node_path59 = require("path");
|
|
56343
56863
|
init_logger();
|
|
56344
|
-
|
|
56864
|
+
init_scan2();
|
|
56345
56865
|
|
|
56346
56866
|
// src/cli/business-logic.ts
|
|
56347
56867
|
var import_node_fs40 = require("fs");
|
|
@@ -56487,10 +57007,10 @@ function registerBusinessLogic(program) {
|
|
|
56487
57007
|
// src/cli/commands/maintenance-cost.ts
|
|
56488
57008
|
var import_node_path60 = require("path");
|
|
56489
57009
|
init_logger();
|
|
56490
|
-
|
|
57010
|
+
init_scan2();
|
|
56491
57011
|
|
|
56492
57012
|
// src/cli/maintenance-cost.ts
|
|
56493
|
-
|
|
57013
|
+
init_scan2();
|
|
56494
57014
|
init_maintenance_cost();
|
|
56495
57015
|
init_logger();
|
|
56496
57016
|
async function runMaintenanceCostScan(cwd, config, options = {}) {
|
|
@@ -56630,10 +57150,10 @@ function registerMaintenanceCost(program) {
|
|
|
56630
57150
|
// src/cli/commands/docs.ts
|
|
56631
57151
|
var import_node_path61 = require("path");
|
|
56632
57152
|
init_logger();
|
|
56633
|
-
|
|
57153
|
+
init_scan2();
|
|
56634
57154
|
|
|
56635
57155
|
// src/cli/docs.ts
|
|
56636
|
-
|
|
57156
|
+
init_scan2();
|
|
56637
57157
|
init_doc_freshness();
|
|
56638
57158
|
init_logger();
|
|
56639
57159
|
async function runDocsScan(cwd, config, options = {}) {
|
|
@@ -56779,10 +57299,10 @@ function registerDocs(program) {
|
|
|
56779
57299
|
// src/cli/commands/db.ts
|
|
56780
57300
|
var import_node_path62 = require("path");
|
|
56781
57301
|
init_logger();
|
|
56782
|
-
|
|
57302
|
+
init_scan2();
|
|
56783
57303
|
|
|
56784
57304
|
// src/cli/db.ts
|
|
56785
|
-
|
|
57305
|
+
init_scan2();
|
|
56786
57306
|
init_db_health();
|
|
56787
57307
|
init_logger();
|
|
56788
57308
|
async function runDbScan(cwd, config, options = {}) {
|
|
@@ -56922,7 +57442,7 @@ function registerDb(program) {
|
|
|
56922
57442
|
// src/cli/commands/patterns.ts
|
|
56923
57443
|
var import_node_path64 = require("path");
|
|
56924
57444
|
init_logger();
|
|
56925
|
-
|
|
57445
|
+
init_scan2();
|
|
56926
57446
|
|
|
56927
57447
|
// src/engine/patterns.ts
|
|
56928
57448
|
var import_node_fs41 = require("fs");
|
|
@@ -57271,7 +57791,7 @@ function registerPatterns(program) {
|
|
|
57271
57791
|
var import_node_fs42 = require("fs");
|
|
57272
57792
|
var import_node_path65 = require("path");
|
|
57273
57793
|
init_logger();
|
|
57274
|
-
|
|
57794
|
+
init_config2();
|
|
57275
57795
|
function registerResearch(program) {
|
|
57276
57796
|
const research = program.command("research").description("research commands for the AI UI learning loop");
|
|
57277
57797
|
research.command("generate").description("generate synthetic UI samples").requiredOption("--count <n>", "number of samples", parseCount).requiredOption("--framework <name>", "target framework").requiredOption("--component-type <type>", "component type").requiredOption("--provider <name>", "AI provider (openai)").option("--api-key <key>", "API key for provider").option("--model <name>", "model name").option("--temperature <n>", "sampling temperature", parseFloat, 0.7).option("--output-dir <path>", "output directory", ".slopbrick/corpus/generated").action(async (cmdOptions) => {
|
|
@@ -57352,8 +57872,8 @@ var import_node_fs43 = require("fs");
|
|
|
57352
57872
|
var import_node_path67 = require("path");
|
|
57353
57873
|
init_logger();
|
|
57354
57874
|
init_builtins();
|
|
57355
|
-
|
|
57356
|
-
|
|
57875
|
+
init_scan2();
|
|
57876
|
+
init_config2();
|
|
57357
57877
|
init_threshold();
|
|
57358
57878
|
init_git();
|
|
57359
57879
|
init_cache();
|
|
@@ -57834,7 +58354,7 @@ function registerScan(program, scanAction) {
|
|
|
57834
58354
|
}
|
|
57835
58355
|
|
|
57836
58356
|
// src/cli/program.ts
|
|
57837
|
-
|
|
58357
|
+
init_config2();
|
|
57838
58358
|
init_git();
|
|
57839
58359
|
init_logger();
|
|
57840
58360
|
init_unified_diff();
|
|
@@ -58267,7 +58787,140 @@ async function applyFixes(report, config, scannedFiles) {
|
|
|
58267
58787
|
// src/cli/program.ts
|
|
58268
58788
|
init_cache();
|
|
58269
58789
|
init_types();
|
|
58270
|
-
|
|
58790
|
+
|
|
58791
|
+
// src/cli/help.ts
|
|
58792
|
+
var CATEGORY_LABELS3 = {
|
|
58793
|
+
file: "File selection",
|
|
58794
|
+
filter: "Filter",
|
|
58795
|
+
output: "Output & display",
|
|
58796
|
+
perf: "Performance",
|
|
58797
|
+
fix: "Auto-fix",
|
|
58798
|
+
ci: "CI / threshold",
|
|
58799
|
+
watch: "Watch & diagnose",
|
|
58800
|
+
tokens: "Tokens",
|
|
58801
|
+
telemetry: "Telemetry",
|
|
58802
|
+
other: "Other"
|
|
58803
|
+
};
|
|
58804
|
+
var OPTION_CATEGORY = {
|
|
58805
|
+
// File selection
|
|
58806
|
+
"--include": "file",
|
|
58807
|
+
"--exclude": "file",
|
|
58808
|
+
"--since": "file",
|
|
58809
|
+
"--diff": "file",
|
|
58810
|
+
"--staged": "file",
|
|
58811
|
+
"--changed": "file",
|
|
58812
|
+
"--workspace": "file",
|
|
58813
|
+
// Filter
|
|
58814
|
+
"--ai-only": "filter",
|
|
58815
|
+
"--human-only": "filter",
|
|
58816
|
+
"--security-only": "filter",
|
|
58817
|
+
"--ignore-wcag22": "filter",
|
|
58818
|
+
"--framework": "filter",
|
|
58819
|
+
// Output & display
|
|
58820
|
+
"--format": "output",
|
|
58821
|
+
"--brief": "output",
|
|
58822
|
+
"--full": "output",
|
|
58823
|
+
"--json": "output",
|
|
58824
|
+
"--html": "output",
|
|
58825
|
+
"--no-color": "output",
|
|
58826
|
+
"--quiet": "output",
|
|
58827
|
+
"--verbose": "output",
|
|
58828
|
+
"--heatmap": "output",
|
|
58829
|
+
"--trend": "output",
|
|
58830
|
+
"--why-failing": "output",
|
|
58831
|
+
// Performance
|
|
58832
|
+
"--threads": "perf",
|
|
58833
|
+
"--incremental": "perf",
|
|
58834
|
+
"--cache": "perf",
|
|
58835
|
+
"--cache-path": "perf",
|
|
58836
|
+
// Auto-fix
|
|
58837
|
+
"--fix": "fix",
|
|
58838
|
+
"--dry-run": "fix",
|
|
58839
|
+
"--show-fixes-diff": "fix",
|
|
58840
|
+
// CI / threshold
|
|
58841
|
+
"--strict": "ci",
|
|
58842
|
+
"--no-increase": "ci",
|
|
58843
|
+
"--baseline": "ci",
|
|
58844
|
+
"--threshold": "ci",
|
|
58845
|
+
// Watch & diagnose
|
|
58846
|
+
"--watch": "watch",
|
|
58847
|
+
"--doctor": "watch",
|
|
58848
|
+
"--suggest": "watch",
|
|
58849
|
+
"--tighten": "watch",
|
|
58850
|
+
// Tokens
|
|
58851
|
+
"--tokens": "tokens",
|
|
58852
|
+
// Telemetry
|
|
58853
|
+
"--no-telemetry": "telemetry"
|
|
58854
|
+
};
|
|
58855
|
+
var CATEGORY_ORDER2 = [
|
|
58856
|
+
"file",
|
|
58857
|
+
"filter",
|
|
58858
|
+
"output",
|
|
58859
|
+
"perf",
|
|
58860
|
+
"fix",
|
|
58861
|
+
"ci",
|
|
58862
|
+
"watch",
|
|
58863
|
+
"tokens",
|
|
58864
|
+
"telemetry",
|
|
58865
|
+
"other"
|
|
58866
|
+
];
|
|
58867
|
+
function groupOptions(cmd) {
|
|
58868
|
+
const grouped = /* @__PURE__ */ new Map();
|
|
58869
|
+
for (const category of CATEGORY_ORDER2) {
|
|
58870
|
+
grouped.set(category, []);
|
|
58871
|
+
}
|
|
58872
|
+
for (const opt of cmd.options) {
|
|
58873
|
+
if (opt.hidden) continue;
|
|
58874
|
+
const longFlag = opt.long ?? opt.short ?? "";
|
|
58875
|
+
const category = longFlag ? OPTION_CATEGORY[longFlag] ?? "other" : "other";
|
|
58876
|
+
grouped.get(category).push({
|
|
58877
|
+
category,
|
|
58878
|
+
flags: opt.flags,
|
|
58879
|
+
description: opt.description ?? ""
|
|
58880
|
+
});
|
|
58881
|
+
}
|
|
58882
|
+
return grouped;
|
|
58883
|
+
}
|
|
58884
|
+
function renderOption(opt, flagWidth) {
|
|
58885
|
+
const padded = opt.flags.padEnd(flagWidth, " ");
|
|
58886
|
+
return ` ${padded} ${opt.description}`;
|
|
58887
|
+
}
|
|
58888
|
+
function formatGroupedHelp(cmd) {
|
|
58889
|
+
const lines = [];
|
|
58890
|
+
const usage = cmd.usage ? cmd.usage() : `Usage: ${cmd.name()} [options]`;
|
|
58891
|
+
lines.push(usage);
|
|
58892
|
+
lines.push("");
|
|
58893
|
+
if (cmd.description()) {
|
|
58894
|
+
lines.push(cmd.description());
|
|
58895
|
+
lines.push("");
|
|
58896
|
+
}
|
|
58897
|
+
const grouped = groupOptions(cmd);
|
|
58898
|
+
let flagWidth = 0;
|
|
58899
|
+
for (const options of grouped.values()) {
|
|
58900
|
+
for (const opt of options) {
|
|
58901
|
+
if (opt.flags.length > flagWidth) flagWidth = opt.flags.length;
|
|
58902
|
+
}
|
|
58903
|
+
}
|
|
58904
|
+
let firstCategory = true;
|
|
58905
|
+
for (const category of CATEGORY_ORDER2) {
|
|
58906
|
+
const options = grouped.get(category);
|
|
58907
|
+
if (options.length === 0) continue;
|
|
58908
|
+
if (!firstCategory) lines.push("");
|
|
58909
|
+
firstCategory = false;
|
|
58910
|
+
lines.push(` ${CATEGORY_LABELS3[category]}:`);
|
|
58911
|
+
for (const opt of options) {
|
|
58912
|
+
lines.push(renderOption(opt, flagWidth));
|
|
58913
|
+
}
|
|
58914
|
+
}
|
|
58915
|
+
lines.push("");
|
|
58916
|
+
lines.push(
|
|
58917
|
+
"Use `--help-flat` for the standard un-grouped list. See `https://usebrick.dev/docs/scan-options` for full docs."
|
|
58918
|
+
);
|
|
58919
|
+
return lines.join("\n");
|
|
58920
|
+
}
|
|
58921
|
+
|
|
58922
|
+
// src/cli/program.ts
|
|
58923
|
+
init_scan2();
|
|
58271
58924
|
process.on("uncaughtException", (err) => {
|
|
58272
58925
|
logger.error(`Unexpected error: ${err instanceof Error ? err.message : String(err)}`);
|
|
58273
58926
|
process.exit(3);
|
|
@@ -58275,6 +58928,7 @@ process.on("uncaughtException", (err) => {
|
|
|
58275
58928
|
async function runCli({ start }) {
|
|
58276
58929
|
try {
|
|
58277
58930
|
const program = new import_commander2.Command().name("slopbrick").description("Repository Coherence Scanner \u2014 surface AI-induced pattern drift, secret leaks, and design-token violations").version(VERSION).option("--framework <name>", "framework multiplier to apply").option("--include <glob>", "include pattern (repeatable)", collectGlob, []).option("--exclude <glob>", "exclude pattern (repeatable)", collectGlob, []).option("--ai-only", "only report AI-specific issues").option("--human-only", "only report human-facing issues").option("--ignore-wcag22", "ignore WCAG 2.2 related issues").option("--format <pretty|json|sarif|html>", "output format", "pretty").option("--threads <n>", "number of worker threads", parseThreads).option("--since <ref>", "only scan files changed since git ref").option("--diff <ref>", "alias for --since <ref>; also adds PR Slop Score to the report").option("--workspace <path>", "workspace/project path", process.cwd()).option("--tighten", "tighten baseline allowances").option("--fix", "apply auto-fixes").option("--dry-run", "with --fix: print what would change without writing").option("--show-fixes-diff", "print unified diff of proposed auto-fixes").option("--doctor", "run diagnostics").option("--watch", "watch files and re-run").option("--suggest", "print remediation advice").option("--why-failing", "print the top 5 rules dragging the score down").option("--brief", "terse output (verdict + headline + threshold + delta only)").option("--heatmap", "print migration ROI heatmap").option("--quiet", "suppress non-error output").option("--verbose", "enable debug logging (file paths, timings, rule-fire counts)").option("--strict", "exit 2 if any high-severity issue remains").option("--no-increase", "exit 2 if slop index increased since last run").option("--baseline", "save a baseline after this scan").option("--trend [n]", "print a sparkline of the last n runs", parseTrend).option("--json [path]", "write JSON report to path or stdout").option("--html [path]", "write HTML report to path or stdout").option("--staged", "scan only changed files (staged and unstaged)").option("--changed", "scan working-tree changes (staged + unstaged + untracked)").option("--incremental", "skip unchanged files using the persisted hash cache").option("--cache-path <path>", "path to the incremental-scan cache (default: .slopbrick-cache.json)").option("--tokens <path>", "merge tokens.json layout values into the arbitrary-value allowlist").option("--cache", "cache parsed AST results locally").option("--no-color", "suppress ANSI color codes in output").option("--security-only", "run only the security/* rules").option("--full", "show the complete report (all issues, all categories)");
|
|
58931
|
+
program.helpInformation = () => formatGroupedHelp(program);
|
|
58278
58932
|
registerInit(program);
|
|
58279
58933
|
registerInstall(program);
|
|
58280
58934
|
registerUninstall(program);
|
|
@@ -58438,6 +59092,11 @@ async function runCli({ start }) {
|
|
|
58438
59092
|
registerTokens(program);
|
|
58439
59093
|
registerReport(program);
|
|
58440
59094
|
registerScan(program, scanAction);
|
|
59095
|
+
if (process.argv.includes("--help-flat")) {
|
|
59096
|
+
delete program.helpInformation;
|
|
59097
|
+
program.outputHelp();
|
|
59098
|
+
process.exit(0);
|
|
59099
|
+
}
|
|
58441
59100
|
await program.parseAsync(process.argv);
|
|
58442
59101
|
} catch (err) {
|
|
58443
59102
|
if (err instanceof ConfigValidationError) {
|