slopbrick 0.24.0 → 0.25.0
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 +50 -1
- package/dist/engine/worker.js +51 -2
- package/dist/index.cjs +102 -58
- package/dist/index.d.cts +35 -1
- package/dist/index.d.ts +35 -1
- package/dist/index.js +132 -88
- package/package.json +1 -1
package/dist/engine/worker.cjs
CHANGED
|
@@ -37,6 +37,7 @@ module.exports = __toCommonJS(worker_exports);
|
|
|
37
37
|
var import_node_worker_threads = require("worker_threads");
|
|
38
38
|
var import_node_path9 = require("path");
|
|
39
39
|
var import_node_path10 = require("path");
|
|
40
|
+
var import_minimatch = require("minimatch");
|
|
40
41
|
|
|
41
42
|
// ../engine/dist/index.js
|
|
42
43
|
var import_promises = require("fs/promises");
|
|
@@ -4364,6 +4365,7 @@ function parseSource(source, filePath) {
|
|
|
4364
4365
|
case "py":
|
|
4365
4366
|
case "go":
|
|
4366
4367
|
case "rs":
|
|
4368
|
+
case "java":
|
|
4367
4369
|
return parseBlankModule(source);
|
|
4368
4370
|
default:
|
|
4369
4371
|
return parseWithSwc(source, filePath);
|
|
@@ -37820,6 +37822,38 @@ var DEFAULT_CONFIG3 = {
|
|
|
37820
37822
|
*/
|
|
37821
37823
|
testIntelligence: {
|
|
37822
37824
|
missingEdgeCase: false
|
|
37825
|
+
},
|
|
37826
|
+
/**
|
|
37827
|
+
* v0.25.0: self-scan exclude paths. Defaults cover the three paths
|
|
37828
|
+
* that are always false positives when scanning the slopbrick repo
|
|
37829
|
+
* itself:
|
|
37830
|
+
*
|
|
37831
|
+
* - `src/rules/**` — rule definitions contain example patterns
|
|
37832
|
+
* the rules themselves detect (self-fire). E.g. a
|
|
37833
|
+
* `security/sql-construction` rule's source file has a SQL
|
|
37834
|
+
* concat string literal that fires its own regex.
|
|
37835
|
+
* - `tests/fixtures/**` — test fixtures contain intentional bad
|
|
37836
|
+
* code that the rules must fire on to be useful (each fixture
|
|
37837
|
+
* is a positive test case). Scanning them in a self-scan
|
|
37838
|
+
* produces ~70 false-positive "issues" that are really just
|
|
37839
|
+
* test data.
|
|
37840
|
+
* - `tests/rules/**` — rule test files contain expected-issue
|
|
37841
|
+
* assertions, also meta-code.
|
|
37842
|
+
*
|
|
37843
|
+
* Three patterns, ~70 issues removed per self-scan. Combined with
|
|
37844
|
+
* the v0.25.0 graded security cap, this restores the v9 plan's
|
|
37845
|
+
* "security ≥ 80" criterion (unachievable in v0.24.0 due to 90
|
|
37846
|
+
* self-scan FPs collapsing the score to 0).
|
|
37847
|
+
*
|
|
37848
|
+
* Set `selfScan: { excludePaths: [] }` in `slopbrick.config.mjs`
|
|
37849
|
+
* to opt out and scan every file (legacy behavior).
|
|
37850
|
+
*/
|
|
37851
|
+
selfScan: {
|
|
37852
|
+
excludePaths: [
|
|
37853
|
+
"src/rules/**",
|
|
37854
|
+
"tests/fixtures/**",
|
|
37855
|
+
"tests/rules/**"
|
|
37856
|
+
]
|
|
37823
37857
|
}
|
|
37824
37858
|
};
|
|
37825
37859
|
|
|
@@ -45471,7 +45505,23 @@ function applyRuleOverrides(issues, rules) {
|
|
|
45471
45505
|
}
|
|
45472
45506
|
return result;
|
|
45473
45507
|
}
|
|
45508
|
+
function isExcludedBySelfScan(filePath, cwd, excludePaths) {
|
|
45509
|
+
if (!excludePaths || excludePaths.length === 0) return false;
|
|
45510
|
+
const rel = (0, import_node_path10.relative)(cwd, filePath).split(import_node_path10.sep).join("/");
|
|
45511
|
+
return excludePaths.some((pattern) => (0, import_minimatch.minimatch)(rel, pattern, { dot: true }));
|
|
45512
|
+
}
|
|
45474
45513
|
async function scanFile(filePath, config, registry, cwd = process.cwd()) {
|
|
45514
|
+
if (isExcludedBySelfScan(filePath, cwd, config.selfScan?.excludePaths)) {
|
|
45515
|
+
return {
|
|
45516
|
+
filePath,
|
|
45517
|
+
componentCount: 0,
|
|
45518
|
+
issues: [],
|
|
45519
|
+
gapValues: [],
|
|
45520
|
+
styleSources: [],
|
|
45521
|
+
elementTags: [],
|
|
45522
|
+
unmatchedStringLiterals: []
|
|
45523
|
+
};
|
|
45524
|
+
}
|
|
45475
45525
|
const cache = buildParserCacheConfig(cwd);
|
|
45476
45526
|
const ext = (0, import_node_path9.extname)(filePath).toLowerCase();
|
|
45477
45527
|
const UNSUPPORTED_LANGS = /* @__PURE__ */ new Set([
|
|
@@ -45486,7 +45536,6 @@ async function scanFile(filePath, config, registry, cwd = process.cwd()) {
|
|
|
45486
45536
|
".h",
|
|
45487
45537
|
".hpp",
|
|
45488
45538
|
".hxx",
|
|
45489
|
-
".java",
|
|
45490
45539
|
".rb",
|
|
45491
45540
|
".php"
|
|
45492
45541
|
]);
|
package/dist/engine/worker.js
CHANGED
|
@@ -7,7 +7,8 @@ var __export = (target, all) => {
|
|
|
7
7
|
// src/engine/worker.ts
|
|
8
8
|
import { isMainThread, parentPort, workerData } from "worker_threads";
|
|
9
9
|
import { extname as extname4 } from "path";
|
|
10
|
-
import { join as join11 } from "path";
|
|
10
|
+
import { join as join11, relative as relative2, sep } from "path";
|
|
11
|
+
import { minimatch } from "minimatch";
|
|
11
12
|
|
|
12
13
|
// ../engine/dist/index.js
|
|
13
14
|
import { readFile, writeFile, mkdir, access } from "fs/promises";
|
|
@@ -4335,6 +4336,7 @@ function parseSource(source, filePath) {
|
|
|
4335
4336
|
case "py":
|
|
4336
4337
|
case "go":
|
|
4337
4338
|
case "rs":
|
|
4339
|
+
case "java":
|
|
4338
4340
|
return parseBlankModule(source);
|
|
4339
4341
|
default:
|
|
4340
4342
|
return parseWithSwc(source, filePath);
|
|
@@ -37791,6 +37793,38 @@ var DEFAULT_CONFIG3 = {
|
|
|
37791
37793
|
*/
|
|
37792
37794
|
testIntelligence: {
|
|
37793
37795
|
missingEdgeCase: false
|
|
37796
|
+
},
|
|
37797
|
+
/**
|
|
37798
|
+
* v0.25.0: self-scan exclude paths. Defaults cover the three paths
|
|
37799
|
+
* that are always false positives when scanning the slopbrick repo
|
|
37800
|
+
* itself:
|
|
37801
|
+
*
|
|
37802
|
+
* - `src/rules/**` — rule definitions contain example patterns
|
|
37803
|
+
* the rules themselves detect (self-fire). E.g. a
|
|
37804
|
+
* `security/sql-construction` rule's source file has a SQL
|
|
37805
|
+
* concat string literal that fires its own regex.
|
|
37806
|
+
* - `tests/fixtures/**` — test fixtures contain intentional bad
|
|
37807
|
+
* code that the rules must fire on to be useful (each fixture
|
|
37808
|
+
* is a positive test case). Scanning them in a self-scan
|
|
37809
|
+
* produces ~70 false-positive "issues" that are really just
|
|
37810
|
+
* test data.
|
|
37811
|
+
* - `tests/rules/**` — rule test files contain expected-issue
|
|
37812
|
+
* assertions, also meta-code.
|
|
37813
|
+
*
|
|
37814
|
+
* Three patterns, ~70 issues removed per self-scan. Combined with
|
|
37815
|
+
* the v0.25.0 graded security cap, this restores the v9 plan's
|
|
37816
|
+
* "security ≥ 80" criterion (unachievable in v0.24.0 due to 90
|
|
37817
|
+
* self-scan FPs collapsing the score to 0).
|
|
37818
|
+
*
|
|
37819
|
+
* Set `selfScan: { excludePaths: [] }` in `slopbrick.config.mjs`
|
|
37820
|
+
* to opt out and scan every file (legacy behavior).
|
|
37821
|
+
*/
|
|
37822
|
+
selfScan: {
|
|
37823
|
+
excludePaths: [
|
|
37824
|
+
"src/rules/**",
|
|
37825
|
+
"tests/fixtures/**",
|
|
37826
|
+
"tests/rules/**"
|
|
37827
|
+
]
|
|
37794
37828
|
}
|
|
37795
37829
|
};
|
|
37796
37830
|
|
|
@@ -45442,7 +45476,23 @@ function applyRuleOverrides(issues, rules) {
|
|
|
45442
45476
|
}
|
|
45443
45477
|
return result;
|
|
45444
45478
|
}
|
|
45479
|
+
function isExcludedBySelfScan(filePath, cwd, excludePaths) {
|
|
45480
|
+
if (!excludePaths || excludePaths.length === 0) return false;
|
|
45481
|
+
const rel = relative2(cwd, filePath).split(sep).join("/");
|
|
45482
|
+
return excludePaths.some((pattern) => minimatch(rel, pattern, { dot: true }));
|
|
45483
|
+
}
|
|
45445
45484
|
async function scanFile(filePath, config, registry, cwd = process.cwd()) {
|
|
45485
|
+
if (isExcludedBySelfScan(filePath, cwd, config.selfScan?.excludePaths)) {
|
|
45486
|
+
return {
|
|
45487
|
+
filePath,
|
|
45488
|
+
componentCount: 0,
|
|
45489
|
+
issues: [],
|
|
45490
|
+
gapValues: [],
|
|
45491
|
+
styleSources: [],
|
|
45492
|
+
elementTags: [],
|
|
45493
|
+
unmatchedStringLiterals: []
|
|
45494
|
+
};
|
|
45495
|
+
}
|
|
45446
45496
|
const cache = buildParserCacheConfig(cwd);
|
|
45447
45497
|
const ext = extname4(filePath).toLowerCase();
|
|
45448
45498
|
const UNSUPPORTED_LANGS = /* @__PURE__ */ new Set([
|
|
@@ -45457,7 +45507,6 @@ async function scanFile(filePath, config, registry, cwd = process.cwd()) {
|
|
|
45457
45507
|
".h",
|
|
45458
45508
|
".hpp",
|
|
45459
45509
|
".hxx",
|
|
45460
|
-
".java",
|
|
45461
45510
|
".rb",
|
|
45462
45511
|
".php"
|
|
45463
45512
|
]);
|
package/dist/index.cjs
CHANGED
|
@@ -36,7 +36,7 @@ var VERSION;
|
|
|
36
36
|
var init_header = __esm({
|
|
37
37
|
"src/types/_header.ts"() {
|
|
38
38
|
"use strict";
|
|
39
|
-
VERSION = "0.
|
|
39
|
+
VERSION = "0.25.0";
|
|
40
40
|
}
|
|
41
41
|
});
|
|
42
42
|
|
|
@@ -326,6 +326,38 @@ var init_defaults = __esm({
|
|
|
326
326
|
*/
|
|
327
327
|
testIntelligence: {
|
|
328
328
|
missingEdgeCase: false
|
|
329
|
+
},
|
|
330
|
+
/**
|
|
331
|
+
* v0.25.0: self-scan exclude paths. Defaults cover the three paths
|
|
332
|
+
* that are always false positives when scanning the slopbrick repo
|
|
333
|
+
* itself:
|
|
334
|
+
*
|
|
335
|
+
* - `src/rules/**` — rule definitions contain example patterns
|
|
336
|
+
* the rules themselves detect (self-fire). E.g. a
|
|
337
|
+
* `security/sql-construction` rule's source file has a SQL
|
|
338
|
+
* concat string literal that fires its own regex.
|
|
339
|
+
* - `tests/fixtures/**` — test fixtures contain intentional bad
|
|
340
|
+
* code that the rules must fire on to be useful (each fixture
|
|
341
|
+
* is a positive test case). Scanning them in a self-scan
|
|
342
|
+
* produces ~70 false-positive "issues" that are really just
|
|
343
|
+
* test data.
|
|
344
|
+
* - `tests/rules/**` — rule test files contain expected-issue
|
|
345
|
+
* assertions, also meta-code.
|
|
346
|
+
*
|
|
347
|
+
* Three patterns, ~70 issues removed per self-scan. Combined with
|
|
348
|
+
* the v0.25.0 graded security cap, this restores the v9 plan's
|
|
349
|
+
* "security ≥ 80" criterion (unachievable in v0.24.0 due to 90
|
|
350
|
+
* self-scan FPs collapsing the score to 0).
|
|
351
|
+
*
|
|
352
|
+
* Set `selfScan: { excludePaths: [] }` in `slopbrick.config.mjs`
|
|
353
|
+
* to opt out and scan every file (legacy behavior).
|
|
354
|
+
*/
|
|
355
|
+
selfScan: {
|
|
356
|
+
excludePaths: [
|
|
357
|
+
"src/rules/**",
|
|
358
|
+
"tests/fixtures/**",
|
|
359
|
+
"tests/rules/**"
|
|
360
|
+
]
|
|
329
361
|
}
|
|
330
362
|
};
|
|
331
363
|
}
|
|
@@ -36375,6 +36407,7 @@ function parseSource(source, filePath) {
|
|
|
36375
36407
|
case "py":
|
|
36376
36408
|
case "go":
|
|
36377
36409
|
case "rs":
|
|
36410
|
+
case "java":
|
|
36378
36411
|
return parseBlankModule(source);
|
|
36379
36412
|
default:
|
|
36380
36413
|
return parseWithSwc(source, filePath);
|
|
@@ -51555,7 +51588,23 @@ function applyRuleOverrides(issues, rules) {
|
|
|
51555
51588
|
}
|
|
51556
51589
|
return result;
|
|
51557
51590
|
}
|
|
51591
|
+
function isExcludedBySelfScan(filePath, cwd, excludePaths) {
|
|
51592
|
+
if (!excludePaths || excludePaths.length === 0) return false;
|
|
51593
|
+
const rel = (0, import_node_path13.relative)(cwd, filePath).split(import_node_path13.sep).join("/");
|
|
51594
|
+
return excludePaths.some((pattern) => (0, import_minimatch2.minimatch)(rel, pattern, { dot: true }));
|
|
51595
|
+
}
|
|
51558
51596
|
async function scanFile(filePath, config, registry, cwd = process.cwd()) {
|
|
51597
|
+
if (isExcludedBySelfScan(filePath, cwd, config.selfScan?.excludePaths)) {
|
|
51598
|
+
return {
|
|
51599
|
+
filePath,
|
|
51600
|
+
componentCount: 0,
|
|
51601
|
+
issues: [],
|
|
51602
|
+
gapValues: [],
|
|
51603
|
+
styleSources: [],
|
|
51604
|
+
elementTags: [],
|
|
51605
|
+
unmatchedStringLiterals: []
|
|
51606
|
+
};
|
|
51607
|
+
}
|
|
51559
51608
|
const cache = buildParserCacheConfig(cwd);
|
|
51560
51609
|
const ext = (0, import_node_path12.extname)(filePath).toLowerCase();
|
|
51561
51610
|
const UNSUPPORTED_LANGS = /* @__PURE__ */ new Set([
|
|
@@ -51570,7 +51619,6 @@ async function scanFile(filePath, config, registry, cwd = process.cwd()) {
|
|
|
51570
51619
|
".h",
|
|
51571
51620
|
".hpp",
|
|
51572
51621
|
".hxx",
|
|
51573
|
-
".java",
|
|
51574
51622
|
".rb",
|
|
51575
51623
|
".php"
|
|
51576
51624
|
]);
|
|
@@ -51673,13 +51721,14 @@ function collectStyleSources(facts) {
|
|
|
51673
51721
|
}
|
|
51674
51722
|
return sources;
|
|
51675
51723
|
}
|
|
51676
|
-
var import_node_worker_threads, import_node_path12, import_node_path13;
|
|
51724
|
+
var import_node_worker_threads, import_node_path12, import_node_path13, import_minimatch2;
|
|
51677
51725
|
var init_worker = __esm({
|
|
51678
51726
|
"src/engine/worker.ts"() {
|
|
51679
51727
|
"use strict";
|
|
51680
51728
|
import_node_worker_threads = require("worker_threads");
|
|
51681
51729
|
import_node_path12 = require("path");
|
|
51682
51730
|
import_node_path13 = require("path");
|
|
51731
|
+
import_minimatch2 = require("minimatch");
|
|
51683
51732
|
init_dist2();
|
|
51684
51733
|
init_visitor();
|
|
51685
51734
|
init_registry();
|
|
@@ -51862,45 +51911,6 @@ var init_flywheel = __esm({
|
|
|
51862
51911
|
}
|
|
51863
51912
|
});
|
|
51864
51913
|
|
|
51865
|
-
// src/engine/ai-security-risk.ts
|
|
51866
|
-
function computeAiSecurityRisk(issues) {
|
|
51867
|
-
const findings = { critical: 0, high: 0, medium: 0, low: 0 };
|
|
51868
|
-
for (const issue of issues) {
|
|
51869
|
-
switch (issue.severity) {
|
|
51870
|
-
case "high":
|
|
51871
|
-
findings.high += 1;
|
|
51872
|
-
break;
|
|
51873
|
-
case "medium":
|
|
51874
|
-
findings.medium += 1;
|
|
51875
|
-
break;
|
|
51876
|
-
case "low":
|
|
51877
|
-
findings.low += 1;
|
|
51878
|
-
break;
|
|
51879
|
-
default:
|
|
51880
|
-
findings.low += 1;
|
|
51881
|
-
}
|
|
51882
|
-
}
|
|
51883
|
-
let risk = "low";
|
|
51884
|
-
if (findings.critical >= 1 || findings.high >= 3) {
|
|
51885
|
-
risk = "critical";
|
|
51886
|
-
} else if (findings.high >= 1 || findings.medium >= 3) {
|
|
51887
|
-
risk = "high";
|
|
51888
|
-
} else if (findings.medium >= 1) {
|
|
51889
|
-
risk = "medium";
|
|
51890
|
-
}
|
|
51891
|
-
return { risk, findings };
|
|
51892
|
-
}
|
|
51893
|
-
function formatAiSecurityRiskLine(risk, findings) {
|
|
51894
|
-
const total = findings.critical + findings.high + findings.medium + findings.low;
|
|
51895
|
-
if (total === 0) return "AI Security Risk: low";
|
|
51896
|
-
return `AI Security Risk: ${risk.toUpperCase()} (${total} findings)`;
|
|
51897
|
-
}
|
|
51898
|
-
var init_ai_security_risk = __esm({
|
|
51899
|
-
"src/engine/ai-security-risk.ts"() {
|
|
51900
|
-
"use strict";
|
|
51901
|
-
}
|
|
51902
|
-
});
|
|
51903
|
-
|
|
51904
51914
|
// src/engine/test-quality.ts
|
|
51905
51915
|
var test_quality_exports = {};
|
|
51906
51916
|
__export(test_quality_exports, {
|
|
@@ -52076,14 +52086,10 @@ function aggregateReport(scores, issueGroups, config, compositeScores) {
|
|
|
52076
52086
|
});
|
|
52077
52087
|
}
|
|
52078
52088
|
}
|
|
52079
|
-
const
|
|
52080
|
-
|
|
52081
|
-
|
|
52082
|
-
|
|
52083
|
-
high: 33,
|
|
52084
|
-
critical: 0
|
|
52085
|
-
};
|
|
52086
|
-
const security = securityFromRisk[risk];
|
|
52089
|
+
const securityIssueCount = flatIssues.filter(
|
|
52090
|
+
(i) => i.category === "security" || (i.ruleId ?? "").startsWith("security/")
|
|
52091
|
+
).length;
|
|
52092
|
+
const security = Math.max(0, 100 / (1 + securityIssueCount / 5));
|
|
52087
52093
|
const engineeringCategoryScores = [
|
|
52088
52094
|
categoryScores.arch ?? 0,
|
|
52089
52095
|
categoryScores.logic ?? 0,
|
|
@@ -52142,7 +52148,6 @@ var init_metrics = __esm({
|
|
|
52142
52148
|
"src/engine/metrics.ts"() {
|
|
52143
52149
|
"use strict";
|
|
52144
52150
|
import_node_path15 = require("path");
|
|
52145
|
-
init_ai_security_risk();
|
|
52146
52151
|
init_test_quality();
|
|
52147
52152
|
SEVERITY_WEIGHTS = {
|
|
52148
52153
|
low: 1,
|
|
@@ -54074,6 +54079,45 @@ var init_business_logic = __esm({
|
|
|
54074
54079
|
}
|
|
54075
54080
|
});
|
|
54076
54081
|
|
|
54082
|
+
// src/engine/ai-security-risk.ts
|
|
54083
|
+
function computeAiSecurityRisk(issues) {
|
|
54084
|
+
const findings = { critical: 0, high: 0, medium: 0, low: 0 };
|
|
54085
|
+
for (const issue of issues) {
|
|
54086
|
+
switch (issue.severity) {
|
|
54087
|
+
case "high":
|
|
54088
|
+
findings.high += 1;
|
|
54089
|
+
break;
|
|
54090
|
+
case "medium":
|
|
54091
|
+
findings.medium += 1;
|
|
54092
|
+
break;
|
|
54093
|
+
case "low":
|
|
54094
|
+
findings.low += 1;
|
|
54095
|
+
break;
|
|
54096
|
+
default:
|
|
54097
|
+
findings.low += 1;
|
|
54098
|
+
}
|
|
54099
|
+
}
|
|
54100
|
+
let risk = "low";
|
|
54101
|
+
if (findings.critical >= 1 || findings.high >= 3) {
|
|
54102
|
+
risk = "critical";
|
|
54103
|
+
} else if (findings.high >= 1 || findings.medium >= 3) {
|
|
54104
|
+
risk = "high";
|
|
54105
|
+
} else if (findings.medium >= 1) {
|
|
54106
|
+
risk = "medium";
|
|
54107
|
+
}
|
|
54108
|
+
return { risk, findings };
|
|
54109
|
+
}
|
|
54110
|
+
function formatAiSecurityRiskLine(risk, findings) {
|
|
54111
|
+
const total = findings.critical + findings.high + findings.medium + findings.low;
|
|
54112
|
+
if (total === 0) return "AI Security Risk: low";
|
|
54113
|
+
return `AI Security Risk: ${risk.toUpperCase()} (${total} findings)`;
|
|
54114
|
+
}
|
|
54115
|
+
var init_ai_security_risk = __esm({
|
|
54116
|
+
"src/engine/ai-security-risk.ts"() {
|
|
54117
|
+
"use strict";
|
|
54118
|
+
}
|
|
54119
|
+
});
|
|
54120
|
+
|
|
54077
54121
|
// src/engine/maintenance-cost.ts
|
|
54078
54122
|
var maintenance_cost_exports = {};
|
|
54079
54123
|
__export(maintenance_cost_exports, {
|
|
@@ -54813,7 +54857,7 @@ function computeDomainScores(issues) {
|
|
|
54813
54857
|
performance2.score = issueCountToScore(performance2.issueCount);
|
|
54814
54858
|
const security = tally(SECURITY_CATEGORIES);
|
|
54815
54859
|
security.name = "security";
|
|
54816
|
-
security.score =
|
|
54860
|
+
security.score = Math.max(0, 100 / (1 + security.issueCount / 5));
|
|
54817
54861
|
return { codeHygiene, accessibility, performance: performance2, security };
|
|
54818
54862
|
}
|
|
54819
54863
|
var COHERENCE_WEIGHTS, AI_DEBT_NUMERIC, CODE_HYGIENE_CATEGORIES, ACCESSIBILITY_CATEGORIES, PERFORMANCE_CATEGORIES, SECURITY_CATEGORIES;
|
|
@@ -57847,7 +57891,7 @@ async function runScan(options, explicitPaths) {
|
|
|
57847
57891
|
let files;
|
|
57848
57892
|
if (explicitPaths && explicitPaths.length > 0) {
|
|
57849
57893
|
const { globby: globby4 } = await import("globby");
|
|
57850
|
-
const { minimatch:
|
|
57894
|
+
const { minimatch: minimatch4 } = await import("minimatch");
|
|
57851
57895
|
const resolved = explicitPaths.map((p) => (0, import_node_path30.resolve)(cwd, p));
|
|
57852
57896
|
const expanded = [];
|
|
57853
57897
|
for (const p of resolved) {
|
|
@@ -57856,10 +57900,10 @@ async function runScan(options, explicitPaths) {
|
|
|
57856
57900
|
for (const f of found) {
|
|
57857
57901
|
if (!ALL_SOURCE_EXTENSIONS.has((0, import_node_path30.extname)(f).toLowerCase())) continue;
|
|
57858
57902
|
const rel = (0, import_node_path30.relative)(cwd, f).split(import_node_path30.sep).join("/");
|
|
57859
|
-
if (config.include.length > 0 && !config.include.some((pattern) =>
|
|
57903
|
+
if (config.include.length > 0 && !config.include.some((pattern) => minimatch4(rel, pattern))) {
|
|
57860
57904
|
continue;
|
|
57861
57905
|
}
|
|
57862
|
-
if (config.exclude.some((pattern) =>
|
|
57906
|
+
if (config.exclude.some((pattern) => minimatch4(rel, pattern, { dot: true }))) {
|
|
57863
57907
|
continue;
|
|
57864
57908
|
}
|
|
57865
57909
|
expanded.push(f);
|
|
@@ -61313,7 +61357,7 @@ var import_node_fs39 = require("fs");
|
|
|
61313
61357
|
var import_node_path52 = require("path");
|
|
61314
61358
|
var import_node_child_process3 = require("child_process");
|
|
61315
61359
|
var import_node_util2 = require("util");
|
|
61316
|
-
var
|
|
61360
|
+
var import_minimatch3 = require("minimatch");
|
|
61317
61361
|
init_git();
|
|
61318
61362
|
init_worker();
|
|
61319
61363
|
init_metrics();
|
|
@@ -61360,10 +61404,10 @@ async function discoverPrFiles(cwd, config, base, head, maxFiles) {
|
|
|
61360
61404
|
const ext = (0, import_node_path52.extname)(abs).toLowerCase();
|
|
61361
61405
|
if (!PR_EXTENSIONS.has(ext)) continue;
|
|
61362
61406
|
const rel = (0, import_node_path52.relative)(cwd, abs).split("\\").join("/");
|
|
61363
|
-
if (config.include.length > 0 && !config.include.some((pattern) => (0,
|
|
61407
|
+
if (config.include.length > 0 && !config.include.some((pattern) => (0, import_minimatch3.minimatch)(rel, pattern))) {
|
|
61364
61408
|
continue;
|
|
61365
61409
|
}
|
|
61366
|
-
if (config.exclude.some((pattern) => (0,
|
|
61410
|
+
if (config.exclude.some((pattern) => (0, import_minimatch3.minimatch)(rel, pattern))) {
|
|
61367
61411
|
continue;
|
|
61368
61412
|
}
|
|
61369
61413
|
sourceFiles.push(abs);
|
package/dist/index.d.cts
CHANGED
|
@@ -737,6 +737,27 @@ interface RuleContext {
|
|
|
737
737
|
supportsRsc?: boolean;
|
|
738
738
|
hotspotIssues?: Issue[];
|
|
739
739
|
}
|
|
740
|
+
/**
|
|
741
|
+
* v0.25.0: self-scan excludes. When `selfScan.excludePaths` is set, the
|
|
742
|
+
* scan worker skips files whose workspace-relative path matches any of
|
|
743
|
+
* the glob patterns. This is for *self-scanning* the slopbrick repo
|
|
744
|
+
* itself, where rule definitions (`src/rules/**`) and test fixtures
|
|
745
|
+
* (`tests/fixtures/**`, `tests/rules/**`) are meta-code — the rules
|
|
746
|
+
* contain examples of the patterns they detect (self-fire), and test
|
|
747
|
+
* fixtures contain intentional bad code that the rules must fire on
|
|
748
|
+
* to be useful. Both are false positives in the self-scan context.
|
|
749
|
+
*
|
|
750
|
+
* Default excludes (in `config/defaults.ts`) cover exactly these three
|
|
751
|
+
* paths. Users who scan a *different* repo can leave `selfScan` unset
|
|
752
|
+
* (or set `excludePaths: []`) to opt out. Empty array disables; absent
|
|
753
|
+
* field uses defaults.
|
|
754
|
+
*/
|
|
755
|
+
interface ScanSelfScanConfig {
|
|
756
|
+
/** Glob patterns (minimatch) to exclude from the scan. Matched against
|
|
757
|
+
* the workspace-relative POSIX-style path. Dot files are matched
|
|
758
|
+
* (`{ dot: true }` semantics). */
|
|
759
|
+
excludePaths: string[];
|
|
760
|
+
}
|
|
740
761
|
interface Rule<Context = unknown> {
|
|
741
762
|
id: string;
|
|
742
763
|
category: Category;
|
|
@@ -832,6 +853,19 @@ interface ResolvedConfig {
|
|
|
832
853
|
/** Walk production AST to find branches without test coverage. */
|
|
833
854
|
missingEdgeCase?: boolean;
|
|
834
855
|
};
|
|
856
|
+
/**
|
|
857
|
+
* v0.25.0: self-scan exclude paths. Applied at scan time (in
|
|
858
|
+
* `engine/worker.ts`) so files matching any glob in `excludePaths`
|
|
859
|
+
* short-circuit with empty issues. Defaults (in `config/defaults.ts`)
|
|
860
|
+
* cover the three "always false positive in self-scan" paths:
|
|
861
|
+
* rule definitions (`src/rules/**`), test fixtures
|
|
862
|
+
* (`tests/fixtures/**`), and rule test files (`tests/rules/**`).
|
|
863
|
+
*
|
|
864
|
+
* Empty array `excludePaths: []` disables exclusion entirely
|
|
865
|
+
* (legacy behavior — every file is scanned). Unset field uses
|
|
866
|
+
* defaults.
|
|
867
|
+
*/
|
|
868
|
+
selfScan?: ScanSelfScanConfig;
|
|
835
869
|
}
|
|
836
870
|
|
|
837
871
|
/**
|
|
@@ -1578,4 +1612,4 @@ declare function formatBadge(report: ProjectReport): string;
|
|
|
1578
1612
|
/** Render an array of values as a Unicode sparkline (▁▂▃▄▅▆▇█). */
|
|
1579
1613
|
declare function formatSparkline(values: number[]): string;
|
|
1580
1614
|
|
|
1581
|
-
export { AI_SECURITY_NUMERIC, type AiDebt, type AiMaintenanceCost, type AiMaintenanceCostResult, type AstroComponentFact, type AutoTunedRule, type BaselineCache, type BaselineMeta, type CachedFile, type Category, type ClassNameFact, type CommentFact, type ComponentFacts, type ComponentScore, type ComponentSizeFact, type ConsoleCallFact, type Constitution, DEFAULT_CONFIG, type DangerouslySetInnerHtmlFact, type DbDriftLevel, type DbFinding, type DialogCallFact, type DisabledLintRuleFact, type DocDriftLevel, type DocFinding, type DomQueryFact, type ElementFact, type EvalCallFact, type ExplicitAnyFact, type FetchCallFact, type FileScanResult, type FixSuggestion, type FlywheelOutput, type FlywheelState, type Framework$1 as Framework, type HealthFile, type HookCallFact, type HookDependencyArrayFact, type HookFact, type ImportFact, type InlineEventHandlerFact, type Issue, type JsxAttributeStringLiteralFact, type JsxTextLiteralFact, type KeyPropFact, type LogicalExpressionFact, type MagicNumberSpacingConfig, type MaintenanceAxes, type MaintenanceAxisHealth, type NonNullAssertionFact, type OptimisticUpdateFact, type ProjectReport, type PropMutationFact, type PropPassThroughFact, REPOSITORY_HEALTH_WEIGHTS, type ReportReadResult, type RepositoryHealth, type RepositoryHealthInputs, type ResearchMetrics, type ResolvedConfig, type Rule, type RuleContext, type RuleSeverity, type RuleSuggestion, type ScanCache, type ScanFacts, type ScanProjectOptions, type Severity, type SlopAuditRun, type StateBinding, type StateBindingFact, type StringLiteralFact, type StylePropFact, type TamaguiStylePropFact, type TopOffender, type UseEffectBodyFact, VERSION, baselineStatusMessage, colorForSlop, failedThresholdCount, filterByDisabledDirectives, filterIssues, formatBadge, formatReportFromFile, formatSparkline, loadConfig, readReportFile, runCli, runInitWizard, scanProject, serializeConfig, stagedGating, thresholdExceeded };
|
|
1615
|
+
export { AI_SECURITY_NUMERIC, type AiDebt, type AiMaintenanceCost, type AiMaintenanceCostResult, type AstroComponentFact, type AutoTunedRule, type BaselineCache, type BaselineMeta, type CachedFile, type Category, type ClassNameFact, type CommentFact, type ComponentFacts, type ComponentScore, type ComponentSizeFact, type ConsoleCallFact, type Constitution, DEFAULT_CONFIG, type DangerouslySetInnerHtmlFact, type DbDriftLevel, type DbFinding, type DialogCallFact, type DisabledLintRuleFact, type DocDriftLevel, type DocFinding, type DomQueryFact, type ElementFact, type EvalCallFact, type ExplicitAnyFact, type FetchCallFact, type FileScanResult, type FixSuggestion, type FlywheelOutput, type FlywheelState, type Framework$1 as Framework, type HealthFile, type HookCallFact, type HookDependencyArrayFact, type HookFact, type ImportFact, type InlineEventHandlerFact, type Issue, type JsxAttributeStringLiteralFact, type JsxTextLiteralFact, type KeyPropFact, type LogicalExpressionFact, type MagicNumberSpacingConfig, type MaintenanceAxes, type MaintenanceAxisHealth, type NonNullAssertionFact, type OptimisticUpdateFact, type ProjectReport, type PropMutationFact, type PropPassThroughFact, REPOSITORY_HEALTH_WEIGHTS, type ReportReadResult, type RepositoryHealth, type RepositoryHealthInputs, type ResearchMetrics, type ResolvedConfig, type Rule, type RuleContext, type RuleSeverity, type RuleSuggestion, type ScanCache, type ScanFacts, type ScanProjectOptions, type ScanSelfScanConfig, type Severity, type SlopAuditRun, type StateBinding, type StateBindingFact, type StringLiteralFact, type StylePropFact, type TamaguiStylePropFact, type TopOffender, type UseEffectBodyFact, VERSION, baselineStatusMessage, colorForSlop, failedThresholdCount, filterByDisabledDirectives, filterIssues, formatBadge, formatReportFromFile, formatSparkline, loadConfig, readReportFile, runCli, runInitWizard, scanProject, serializeConfig, stagedGating, thresholdExceeded };
|
package/dist/index.d.ts
CHANGED
|
@@ -737,6 +737,27 @@ interface RuleContext {
|
|
|
737
737
|
supportsRsc?: boolean;
|
|
738
738
|
hotspotIssues?: Issue[];
|
|
739
739
|
}
|
|
740
|
+
/**
|
|
741
|
+
* v0.25.0: self-scan excludes. When `selfScan.excludePaths` is set, the
|
|
742
|
+
* scan worker skips files whose workspace-relative path matches any of
|
|
743
|
+
* the glob patterns. This is for *self-scanning* the slopbrick repo
|
|
744
|
+
* itself, where rule definitions (`src/rules/**`) and test fixtures
|
|
745
|
+
* (`tests/fixtures/**`, `tests/rules/**`) are meta-code — the rules
|
|
746
|
+
* contain examples of the patterns they detect (self-fire), and test
|
|
747
|
+
* fixtures contain intentional bad code that the rules must fire on
|
|
748
|
+
* to be useful. Both are false positives in the self-scan context.
|
|
749
|
+
*
|
|
750
|
+
* Default excludes (in `config/defaults.ts`) cover exactly these three
|
|
751
|
+
* paths. Users who scan a *different* repo can leave `selfScan` unset
|
|
752
|
+
* (or set `excludePaths: []`) to opt out. Empty array disables; absent
|
|
753
|
+
* field uses defaults.
|
|
754
|
+
*/
|
|
755
|
+
interface ScanSelfScanConfig {
|
|
756
|
+
/** Glob patterns (minimatch) to exclude from the scan. Matched against
|
|
757
|
+
* the workspace-relative POSIX-style path. Dot files are matched
|
|
758
|
+
* (`{ dot: true }` semantics). */
|
|
759
|
+
excludePaths: string[];
|
|
760
|
+
}
|
|
740
761
|
interface Rule<Context = unknown> {
|
|
741
762
|
id: string;
|
|
742
763
|
category: Category;
|
|
@@ -832,6 +853,19 @@ interface ResolvedConfig {
|
|
|
832
853
|
/** Walk production AST to find branches without test coverage. */
|
|
833
854
|
missingEdgeCase?: boolean;
|
|
834
855
|
};
|
|
856
|
+
/**
|
|
857
|
+
* v0.25.0: self-scan exclude paths. Applied at scan time (in
|
|
858
|
+
* `engine/worker.ts`) so files matching any glob in `excludePaths`
|
|
859
|
+
* short-circuit with empty issues. Defaults (in `config/defaults.ts`)
|
|
860
|
+
* cover the three "always false positive in self-scan" paths:
|
|
861
|
+
* rule definitions (`src/rules/**`), test fixtures
|
|
862
|
+
* (`tests/fixtures/**`), and rule test files (`tests/rules/**`).
|
|
863
|
+
*
|
|
864
|
+
* Empty array `excludePaths: []` disables exclusion entirely
|
|
865
|
+
* (legacy behavior — every file is scanned). Unset field uses
|
|
866
|
+
* defaults.
|
|
867
|
+
*/
|
|
868
|
+
selfScan?: ScanSelfScanConfig;
|
|
835
869
|
}
|
|
836
870
|
|
|
837
871
|
/**
|
|
@@ -1578,4 +1612,4 @@ declare function formatBadge(report: ProjectReport): string;
|
|
|
1578
1612
|
/** Render an array of values as a Unicode sparkline (▁▂▃▄▅▆▇█). */
|
|
1579
1613
|
declare function formatSparkline(values: number[]): string;
|
|
1580
1614
|
|
|
1581
|
-
export { AI_SECURITY_NUMERIC, type AiDebt, type AiMaintenanceCost, type AiMaintenanceCostResult, type AstroComponentFact, type AutoTunedRule, type BaselineCache, type BaselineMeta, type CachedFile, type Category, type ClassNameFact, type CommentFact, type ComponentFacts, type ComponentScore, type ComponentSizeFact, type ConsoleCallFact, type Constitution, DEFAULT_CONFIG, type DangerouslySetInnerHtmlFact, type DbDriftLevel, type DbFinding, type DialogCallFact, type DisabledLintRuleFact, type DocDriftLevel, type DocFinding, type DomQueryFact, type ElementFact, type EvalCallFact, type ExplicitAnyFact, type FetchCallFact, type FileScanResult, type FixSuggestion, type FlywheelOutput, type FlywheelState, type Framework$1 as Framework, type HealthFile, type HookCallFact, type HookDependencyArrayFact, type HookFact, type ImportFact, type InlineEventHandlerFact, type Issue, type JsxAttributeStringLiteralFact, type JsxTextLiteralFact, type KeyPropFact, type LogicalExpressionFact, type MagicNumberSpacingConfig, type MaintenanceAxes, type MaintenanceAxisHealth, type NonNullAssertionFact, type OptimisticUpdateFact, type ProjectReport, type PropMutationFact, type PropPassThroughFact, REPOSITORY_HEALTH_WEIGHTS, type ReportReadResult, type RepositoryHealth, type RepositoryHealthInputs, type ResearchMetrics, type ResolvedConfig, type Rule, type RuleContext, type RuleSeverity, type RuleSuggestion, type ScanCache, type ScanFacts, type ScanProjectOptions, type Severity, type SlopAuditRun, type StateBinding, type StateBindingFact, type StringLiteralFact, type StylePropFact, type TamaguiStylePropFact, type TopOffender, type UseEffectBodyFact, VERSION, baselineStatusMessage, colorForSlop, failedThresholdCount, filterByDisabledDirectives, filterIssues, formatBadge, formatReportFromFile, formatSparkline, loadConfig, readReportFile, runCli, runInitWizard, scanProject, serializeConfig, stagedGating, thresholdExceeded };
|
|
1615
|
+
export { AI_SECURITY_NUMERIC, type AiDebt, type AiMaintenanceCost, type AiMaintenanceCostResult, type AstroComponentFact, type AutoTunedRule, type BaselineCache, type BaselineMeta, type CachedFile, type Category, type ClassNameFact, type CommentFact, type ComponentFacts, type ComponentScore, type ComponentSizeFact, type ConsoleCallFact, type Constitution, DEFAULT_CONFIG, type DangerouslySetInnerHtmlFact, type DbDriftLevel, type DbFinding, type DialogCallFact, type DisabledLintRuleFact, type DocDriftLevel, type DocFinding, type DomQueryFact, type ElementFact, type EvalCallFact, type ExplicitAnyFact, type FetchCallFact, type FileScanResult, type FixSuggestion, type FlywheelOutput, type FlywheelState, type Framework$1 as Framework, type HealthFile, type HookCallFact, type HookDependencyArrayFact, type HookFact, type ImportFact, type InlineEventHandlerFact, type Issue, type JsxAttributeStringLiteralFact, type JsxTextLiteralFact, type KeyPropFact, type LogicalExpressionFact, type MagicNumberSpacingConfig, type MaintenanceAxes, type MaintenanceAxisHealth, type NonNullAssertionFact, type OptimisticUpdateFact, type ProjectReport, type PropMutationFact, type PropPassThroughFact, REPOSITORY_HEALTH_WEIGHTS, type ReportReadResult, type RepositoryHealth, type RepositoryHealthInputs, type ResearchMetrics, type ResolvedConfig, type Rule, type RuleContext, type RuleSeverity, type RuleSuggestion, type ScanCache, type ScanFacts, type ScanProjectOptions, type ScanSelfScanConfig, type Severity, type SlopAuditRun, type StateBinding, type StateBindingFact, type StringLiteralFact, type StylePropFact, type TamaguiStylePropFact, type TopOffender, type UseEffectBodyFact, VERSION, baselineStatusMessage, colorForSlop, failedThresholdCount, filterByDisabledDirectives, filterIssues, formatBadge, formatReportFromFile, formatSparkline, loadConfig, readReportFile, runCli, runInitWizard, scanProject, serializeConfig, stagedGating, thresholdExceeded };
|
package/dist/index.js
CHANGED
|
@@ -19,7 +19,7 @@ var VERSION;
|
|
|
19
19
|
var init_header = __esm({
|
|
20
20
|
"src/types/_header.ts"() {
|
|
21
21
|
"use strict";
|
|
22
|
-
VERSION = "0.
|
|
22
|
+
VERSION = "0.25.0";
|
|
23
23
|
}
|
|
24
24
|
});
|
|
25
25
|
|
|
@@ -309,6 +309,38 @@ var init_defaults = __esm({
|
|
|
309
309
|
*/
|
|
310
310
|
testIntelligence: {
|
|
311
311
|
missingEdgeCase: false
|
|
312
|
+
},
|
|
313
|
+
/**
|
|
314
|
+
* v0.25.0: self-scan exclude paths. Defaults cover the three paths
|
|
315
|
+
* that are always false positives when scanning the slopbrick repo
|
|
316
|
+
* itself:
|
|
317
|
+
*
|
|
318
|
+
* - `src/rules/**` — rule definitions contain example patterns
|
|
319
|
+
* the rules themselves detect (self-fire). E.g. a
|
|
320
|
+
* `security/sql-construction` rule's source file has a SQL
|
|
321
|
+
* concat string literal that fires its own regex.
|
|
322
|
+
* - `tests/fixtures/**` — test fixtures contain intentional bad
|
|
323
|
+
* code that the rules must fire on to be useful (each fixture
|
|
324
|
+
* is a positive test case). Scanning them in a self-scan
|
|
325
|
+
* produces ~70 false-positive "issues" that are really just
|
|
326
|
+
* test data.
|
|
327
|
+
* - `tests/rules/**` — rule test files contain expected-issue
|
|
328
|
+
* assertions, also meta-code.
|
|
329
|
+
*
|
|
330
|
+
* Three patterns, ~70 issues removed per self-scan. Combined with
|
|
331
|
+
* the v0.25.0 graded security cap, this restores the v9 plan's
|
|
332
|
+
* "security ≥ 80" criterion (unachievable in v0.24.0 due to 90
|
|
333
|
+
* self-scan FPs collapsing the score to 0).
|
|
334
|
+
*
|
|
335
|
+
* Set `selfScan: { excludePaths: [] }` in `slopbrick.config.mjs`
|
|
336
|
+
* to opt out and scan every file (legacy behavior).
|
|
337
|
+
*/
|
|
338
|
+
selfScan: {
|
|
339
|
+
excludePaths: [
|
|
340
|
+
"src/rules/**",
|
|
341
|
+
"tests/fixtures/**",
|
|
342
|
+
"tests/rules/**"
|
|
343
|
+
]
|
|
312
344
|
}
|
|
313
345
|
};
|
|
314
346
|
}
|
|
@@ -36365,6 +36397,7 @@ function parseSource(source, filePath) {
|
|
|
36365
36397
|
case "py":
|
|
36366
36398
|
case "go":
|
|
36367
36399
|
case "rs":
|
|
36400
|
+
case "java":
|
|
36368
36401
|
return parseBlankModule(source);
|
|
36369
36402
|
default:
|
|
36370
36403
|
return parseWithSwc(source, filePath);
|
|
@@ -51516,7 +51549,8 @@ var init_signal_strength2 = __esm({
|
|
|
51516
51549
|
// src/engine/worker.ts
|
|
51517
51550
|
import { isMainThread, parentPort, workerData } from "worker_threads";
|
|
51518
51551
|
import { extname as extname5 } from "path";
|
|
51519
|
-
import { join as join13 } from "path";
|
|
51552
|
+
import { join as join13, relative as relative5, sep as sep2 } from "path";
|
|
51553
|
+
import { minimatch as minimatch2 } from "minimatch";
|
|
51520
51554
|
function buildParserCacheConfig(cwd) {
|
|
51521
51555
|
const envVal = process.env.SLOP_AUDIT_CACHE;
|
|
51522
51556
|
const enabled = envVal === "1" || envVal === "true";
|
|
@@ -51536,7 +51570,23 @@ function applyRuleOverrides(issues, rules) {
|
|
|
51536
51570
|
}
|
|
51537
51571
|
return result;
|
|
51538
51572
|
}
|
|
51573
|
+
function isExcludedBySelfScan(filePath, cwd, excludePaths) {
|
|
51574
|
+
if (!excludePaths || excludePaths.length === 0) return false;
|
|
51575
|
+
const rel = relative5(cwd, filePath).split(sep2).join("/");
|
|
51576
|
+
return excludePaths.some((pattern) => minimatch2(rel, pattern, { dot: true }));
|
|
51577
|
+
}
|
|
51539
51578
|
async function scanFile(filePath, config, registry, cwd = process.cwd()) {
|
|
51579
|
+
if (isExcludedBySelfScan(filePath, cwd, config.selfScan?.excludePaths)) {
|
|
51580
|
+
return {
|
|
51581
|
+
filePath,
|
|
51582
|
+
componentCount: 0,
|
|
51583
|
+
issues: [],
|
|
51584
|
+
gapValues: [],
|
|
51585
|
+
styleSources: [],
|
|
51586
|
+
elementTags: [],
|
|
51587
|
+
unmatchedStringLiterals: []
|
|
51588
|
+
};
|
|
51589
|
+
}
|
|
51540
51590
|
const cache = buildParserCacheConfig(cwd);
|
|
51541
51591
|
const ext = extname5(filePath).toLowerCase();
|
|
51542
51592
|
const UNSUPPORTED_LANGS = /* @__PURE__ */ new Set([
|
|
@@ -51551,7 +51601,6 @@ async function scanFile(filePath, config, registry, cwd = process.cwd()) {
|
|
|
51551
51601
|
".h",
|
|
51552
51602
|
".hpp",
|
|
51553
51603
|
".hxx",
|
|
51554
|
-
".java",
|
|
51555
51604
|
".rb",
|
|
51556
51605
|
".php"
|
|
51557
51606
|
]);
|
|
@@ -51839,45 +51888,6 @@ var init_flywheel = __esm({
|
|
|
51839
51888
|
}
|
|
51840
51889
|
});
|
|
51841
51890
|
|
|
51842
|
-
// src/engine/ai-security-risk.ts
|
|
51843
|
-
function computeAiSecurityRisk(issues) {
|
|
51844
|
-
const findings = { critical: 0, high: 0, medium: 0, low: 0 };
|
|
51845
|
-
for (const issue of issues) {
|
|
51846
|
-
switch (issue.severity) {
|
|
51847
|
-
case "high":
|
|
51848
|
-
findings.high += 1;
|
|
51849
|
-
break;
|
|
51850
|
-
case "medium":
|
|
51851
|
-
findings.medium += 1;
|
|
51852
|
-
break;
|
|
51853
|
-
case "low":
|
|
51854
|
-
findings.low += 1;
|
|
51855
|
-
break;
|
|
51856
|
-
default:
|
|
51857
|
-
findings.low += 1;
|
|
51858
|
-
}
|
|
51859
|
-
}
|
|
51860
|
-
let risk = "low";
|
|
51861
|
-
if (findings.critical >= 1 || findings.high >= 3) {
|
|
51862
|
-
risk = "critical";
|
|
51863
|
-
} else if (findings.high >= 1 || findings.medium >= 3) {
|
|
51864
|
-
risk = "high";
|
|
51865
|
-
} else if (findings.medium >= 1) {
|
|
51866
|
-
risk = "medium";
|
|
51867
|
-
}
|
|
51868
|
-
return { risk, findings };
|
|
51869
|
-
}
|
|
51870
|
-
function formatAiSecurityRiskLine(risk, findings) {
|
|
51871
|
-
const total = findings.critical + findings.high + findings.medium + findings.low;
|
|
51872
|
-
if (total === 0) return "AI Security Risk: low";
|
|
51873
|
-
return `AI Security Risk: ${risk.toUpperCase()} (${total} findings)`;
|
|
51874
|
-
}
|
|
51875
|
-
var init_ai_security_risk = __esm({
|
|
51876
|
-
"src/engine/ai-security-risk.ts"() {
|
|
51877
|
-
"use strict";
|
|
51878
|
-
}
|
|
51879
|
-
});
|
|
51880
|
-
|
|
51881
51891
|
// src/engine/test-quality.ts
|
|
51882
51892
|
var test_quality_exports = {};
|
|
51883
51893
|
__export(test_quality_exports, {
|
|
@@ -51946,7 +51956,7 @@ var init_test_quality = __esm({
|
|
|
51946
51956
|
});
|
|
51947
51957
|
|
|
51948
51958
|
// src/engine/metrics.ts
|
|
51949
|
-
import { isAbsolute as isAbsolute2, relative as
|
|
51959
|
+
import { isAbsolute as isAbsolute2, relative as relative6 } from "path";
|
|
51950
51960
|
function bucketFor(ruleId) {
|
|
51951
51961
|
return RULE_TO_BUCKET[ruleId] ?? "visual";
|
|
51952
51962
|
}
|
|
@@ -51970,7 +51980,7 @@ function scoreFile(result, frameworkMultiplier, config, baseline, cwd) {
|
|
|
51970
51980
|
100,
|
|
51971
51981
|
rawScore * frameworkMultiplier * CONTEXT_DENSITY_MULTIPLIER
|
|
51972
51982
|
);
|
|
51973
|
-
const baselineKey = cwd ? isAbsolute2(result.filePath) ?
|
|
51983
|
+
const baselineKey = cwd ? isAbsolute2(result.filePath) ? relative6(cwd, result.filePath) : result.filePath : result.filePath;
|
|
51974
51984
|
const baselineScore = baseline?.scores[baselineKey]?.baselineScore ?? 0;
|
|
51975
51985
|
const adjustedScore = baseline ? Math.max(0, componentScore - baselineScore) : componentScore;
|
|
51976
51986
|
return {
|
|
@@ -52054,14 +52064,10 @@ function aggregateReport(scores, issueGroups, config, compositeScores) {
|
|
|
52054
52064
|
});
|
|
52055
52065
|
}
|
|
52056
52066
|
}
|
|
52057
|
-
const
|
|
52058
|
-
|
|
52059
|
-
|
|
52060
|
-
|
|
52061
|
-
high: 33,
|
|
52062
|
-
critical: 0
|
|
52063
|
-
};
|
|
52064
|
-
const security = securityFromRisk[risk];
|
|
52067
|
+
const securityIssueCount = flatIssues.filter(
|
|
52068
|
+
(i) => i.category === "security" || (i.ruleId ?? "").startsWith("security/")
|
|
52069
|
+
).length;
|
|
52070
|
+
const security = Math.max(0, 100 / (1 + securityIssueCount / 5));
|
|
52065
52071
|
const engineeringCategoryScores = [
|
|
52066
52072
|
categoryScores.arch ?? 0,
|
|
52067
52073
|
categoryScores.logic ?? 0,
|
|
@@ -52119,7 +52125,6 @@ var SEVERITY_WEIGHTS, CONTEXT_DENSITY_MULTIPLIER, COMPOSITE_WEIGHTS, RULE_TO_BUC
|
|
|
52119
52125
|
var init_metrics = __esm({
|
|
52120
52126
|
"src/engine/metrics.ts"() {
|
|
52121
52127
|
"use strict";
|
|
52122
|
-
init_ai_security_risk();
|
|
52123
52128
|
init_test_quality();
|
|
52124
52129
|
SEVERITY_WEIGHTS = {
|
|
52125
52130
|
low: 1,
|
|
@@ -54051,6 +54056,45 @@ var init_business_logic = __esm({
|
|
|
54051
54056
|
}
|
|
54052
54057
|
});
|
|
54053
54058
|
|
|
54059
|
+
// src/engine/ai-security-risk.ts
|
|
54060
|
+
function computeAiSecurityRisk(issues) {
|
|
54061
|
+
const findings = { critical: 0, high: 0, medium: 0, low: 0 };
|
|
54062
|
+
for (const issue of issues) {
|
|
54063
|
+
switch (issue.severity) {
|
|
54064
|
+
case "high":
|
|
54065
|
+
findings.high += 1;
|
|
54066
|
+
break;
|
|
54067
|
+
case "medium":
|
|
54068
|
+
findings.medium += 1;
|
|
54069
|
+
break;
|
|
54070
|
+
case "low":
|
|
54071
|
+
findings.low += 1;
|
|
54072
|
+
break;
|
|
54073
|
+
default:
|
|
54074
|
+
findings.low += 1;
|
|
54075
|
+
}
|
|
54076
|
+
}
|
|
54077
|
+
let risk = "low";
|
|
54078
|
+
if (findings.critical >= 1 || findings.high >= 3) {
|
|
54079
|
+
risk = "critical";
|
|
54080
|
+
} else if (findings.high >= 1 || findings.medium >= 3) {
|
|
54081
|
+
risk = "high";
|
|
54082
|
+
} else if (findings.medium >= 1) {
|
|
54083
|
+
risk = "medium";
|
|
54084
|
+
}
|
|
54085
|
+
return { risk, findings };
|
|
54086
|
+
}
|
|
54087
|
+
function formatAiSecurityRiskLine(risk, findings) {
|
|
54088
|
+
const total = findings.critical + findings.high + findings.medium + findings.low;
|
|
54089
|
+
if (total === 0) return "AI Security Risk: low";
|
|
54090
|
+
return `AI Security Risk: ${risk.toUpperCase()} (${total} findings)`;
|
|
54091
|
+
}
|
|
54092
|
+
var init_ai_security_risk = __esm({
|
|
54093
|
+
"src/engine/ai-security-risk.ts"() {
|
|
54094
|
+
"use strict";
|
|
54095
|
+
}
|
|
54096
|
+
});
|
|
54097
|
+
|
|
54054
54098
|
// src/engine/maintenance-cost.ts
|
|
54055
54099
|
var maintenance_cost_exports = {};
|
|
54056
54100
|
__export(maintenance_cost_exports, {
|
|
@@ -54327,7 +54371,7 @@ __export(db_health_exports, {
|
|
|
54327
54371
|
buildDbHealth: () => buildDbHealth
|
|
54328
54372
|
});
|
|
54329
54373
|
import { readFileSync as readFileSync17 } from "fs";
|
|
54330
|
-
import { relative as
|
|
54374
|
+
import { relative as relative7 } from "path";
|
|
54331
54375
|
import { globby as globby3 } from "globby";
|
|
54332
54376
|
import { parse as parseSql6, loadModule as loadSqlModule6 } from "pgsql-parser";
|
|
54333
54377
|
function ensureSqlModule() {
|
|
@@ -54378,7 +54422,7 @@ async function buildDbHealth(cwd, _config, options = {}) {
|
|
|
54378
54422
|
for (const abs of sqlFiles.slice(0, maxFiles)) {
|
|
54379
54423
|
const parsed = await parseSqlFile(abs);
|
|
54380
54424
|
if (!parsed) continue;
|
|
54381
|
-
const relPath =
|
|
54425
|
+
const relPath = relative7(cwd, abs);
|
|
54382
54426
|
parsedFiles.push({ relPath, parsed });
|
|
54383
54427
|
for (const stmt of parsed.statements) {
|
|
54384
54428
|
if (stmt.type !== "IndexStmt") continue;
|
|
@@ -54433,7 +54477,7 @@ async function buildDbHealth(cwd, _config, options = {}) {
|
|
|
54433
54477
|
} catch {
|
|
54434
54478
|
continue;
|
|
54435
54479
|
}
|
|
54436
|
-
const relPath =
|
|
54480
|
+
const relPath = relative7(cwd, abs);
|
|
54437
54481
|
const context = { config: _config, filePath: relPath, cwd };
|
|
54438
54482
|
const facts = { filePath: relPath, v2: { _source: source } };
|
|
54439
54483
|
const ruleContext = sqlConcatRule.create(context);
|
|
@@ -54790,7 +54834,7 @@ function computeDomainScores(issues) {
|
|
|
54790
54834
|
performance2.score = issueCountToScore(performance2.issueCount);
|
|
54791
54835
|
const security = tally(SECURITY_CATEGORIES);
|
|
54792
54836
|
security.name = "security";
|
|
54793
|
-
security.score =
|
|
54837
|
+
security.score = Math.max(0, 100 / (1 + security.issueCount / 5));
|
|
54794
54838
|
return { codeHygiene, accessibility, performance: performance2, security };
|
|
54795
54839
|
}
|
|
54796
54840
|
var COHERENCE_WEIGHTS, AI_DEBT_NUMERIC, CODE_HYGIENE_CATEGORIES, ACCESSIBILITY_CATEGORIES, PERFORMANCE_CATEGORIES, SECURITY_CATEGORIES;
|
|
@@ -54818,7 +54862,7 @@ var init_coherence = __esm({
|
|
|
54818
54862
|
|
|
54819
54863
|
// src/cli/report/enrichReport.ts
|
|
54820
54864
|
import { readFileSync as readFileSync18 } from "fs";
|
|
54821
|
-
import { relative as
|
|
54865
|
+
import { relative as relative8 } from "path";
|
|
54822
54866
|
function collectBusinessLogicIssues(cwd, filePaths) {
|
|
54823
54867
|
const issues = [];
|
|
54824
54868
|
for (const absPath of filePaths) {
|
|
@@ -54832,7 +54876,7 @@ function collectBusinessLogicIssues(cwd, filePaths) {
|
|
|
54832
54876
|
for (const issue of fileIssues) {
|
|
54833
54877
|
issues.push({
|
|
54834
54878
|
...issue,
|
|
54835
|
-
filePath:
|
|
54879
|
+
filePath: relative8(cwd, absPath) || absPath
|
|
54836
54880
|
});
|
|
54837
54881
|
}
|
|
54838
54882
|
}
|
|
@@ -55223,7 +55267,7 @@ import {
|
|
|
55223
55267
|
statSync as statSync6
|
|
55224
55268
|
} from "fs";
|
|
55225
55269
|
import { createHash as createHash10 } from "crypto";
|
|
55226
|
-
import { dirname as dirname11, join as join17, relative as
|
|
55270
|
+
import { dirname as dirname11, join as join17, relative as relative9 } from "path";
|
|
55227
55271
|
function telemetryPath2(cwd) {
|
|
55228
55272
|
return join17(cwd, TELEMETRY_DIR, TELEMETRY_FILE2);
|
|
55229
55273
|
}
|
|
@@ -55232,7 +55276,7 @@ function hashString(input) {
|
|
|
55232
55276
|
}
|
|
55233
55277
|
function safeRelative(cwd, filePath) {
|
|
55234
55278
|
try {
|
|
55235
|
-
return
|
|
55279
|
+
return relative9(cwd, filePath);
|
|
55236
55280
|
} catch {
|
|
55237
55281
|
return filePath;
|
|
55238
55282
|
}
|
|
@@ -55580,7 +55624,7 @@ var init_structure_md = __esm({
|
|
|
55580
55624
|
|
|
55581
55625
|
// src/cli/report/persistRun.ts
|
|
55582
55626
|
import { existsSync as existsSync18, writeFileSync as writeFileSync7, mkdirSync as mkdirSync7 } from "fs";
|
|
55583
|
-
import { join as join19, relative as
|
|
55627
|
+
import { join as join19, relative as relative10 } from "path";
|
|
55584
55628
|
async function persistRun(input) {
|
|
55585
55629
|
const {
|
|
55586
55630
|
cwd,
|
|
@@ -55642,7 +55686,7 @@ async function persistRun(input) {
|
|
|
55642
55686
|
const recentTopHashes = telemetryPayloads.map(
|
|
55643
55687
|
(payload) => [...payload.files].sort((a, b) => b.score - a.score).slice(0, 10).map((file) => file.hash)
|
|
55644
55688
|
);
|
|
55645
|
-
const currentTopFiles = [...report.components].sort((a, b) => b.adjustedScore - a.adjustedScore).slice(0, 10).map((c) => ({ filePath: c.filePath, hash: hashFile(
|
|
55689
|
+
const currentTopFiles = [...report.components].sort((a, b) => b.adjustedScore - a.adjustedScore).slice(0, 10).map((c) => ({ filePath: c.filePath, hash: hashFile(relative10(cwd, c.filePath)) }));
|
|
55646
55690
|
const unmatchedStringLiterals = results.flatMap((r) => r.unmatchedStringLiterals ?? []);
|
|
55647
55691
|
const flywheelOutput = computeFlywheelOutput(
|
|
55648
55692
|
runs,
|
|
@@ -55847,11 +55891,11 @@ var init_finalizeReport = __esm({
|
|
|
55847
55891
|
});
|
|
55848
55892
|
|
|
55849
55893
|
// src/cli/report/baseline-cache.ts
|
|
55850
|
-
import { relative as
|
|
55894
|
+
import { relative as relative11 } from "path";
|
|
55851
55895
|
function buildBaselineCache(report, configHash, gitHead, cwd) {
|
|
55852
55896
|
const scores = {};
|
|
55853
55897
|
for (const component of report.components) {
|
|
55854
|
-
scores[
|
|
55898
|
+
scores[relative11(cwd, component.filePath)] = {
|
|
55855
55899
|
baselineScore: component.componentScore,
|
|
55856
55900
|
componentCount: component.componentCount
|
|
55857
55901
|
};
|
|
@@ -55929,14 +55973,14 @@ var init_json = __esm({
|
|
|
55929
55973
|
// src/report/sarif.ts
|
|
55930
55974
|
import { createHash as createHash11 } from "crypto";
|
|
55931
55975
|
import { readFileSync as readFileSync21 } from "fs";
|
|
55932
|
-
import { basename as basename3, isAbsolute as isAbsolute3, relative as
|
|
55976
|
+
import { basename as basename3, isAbsolute as isAbsolute3, relative as relative12, resolve as resolve9 } from "path";
|
|
55933
55977
|
function buildArtifactUri(filePath, cwd) {
|
|
55934
55978
|
if (!filePath) {
|
|
55935
55979
|
return ".";
|
|
55936
55980
|
}
|
|
55937
55981
|
if (cwd) {
|
|
55938
55982
|
const absoluteFilePath = isAbsolute3(filePath) ? filePath : resolve9(cwd, filePath);
|
|
55939
|
-
const rel =
|
|
55983
|
+
const rel = relative12(cwd, absoluteFilePath);
|
|
55940
55984
|
if (rel.startsWith("..")) {
|
|
55941
55985
|
return basename3(filePath);
|
|
55942
55986
|
}
|
|
@@ -57311,7 +57355,7 @@ var init_layout_token = __esm({
|
|
|
57311
57355
|
|
|
57312
57356
|
// src/report/unified-diff.ts
|
|
57313
57357
|
import { existsSync as existsSync19, readFileSync as readFileSync23 } from "fs";
|
|
57314
|
-
import { relative as
|
|
57358
|
+
import { relative as relative13 } from "path";
|
|
57315
57359
|
function collectAllFixes(issue) {
|
|
57316
57360
|
return [...issue.fix ? [issue.fix] : [], ...issue.fixes ?? []];
|
|
57317
57361
|
}
|
|
@@ -57397,7 +57441,7 @@ function formatUnifiedDiff(report, cwd) {
|
|
|
57397
57441
|
parts.push("");
|
|
57398
57442
|
hasHunk = true;
|
|
57399
57443
|
}
|
|
57400
|
-
const rel =
|
|
57444
|
+
const rel = relative13(cwd, filePath);
|
|
57401
57445
|
parts.push(`--- a/${rel}`);
|
|
57402
57446
|
parts.push(`+++ b/${rel}`);
|
|
57403
57447
|
parts.push(...formatHunk(original, patched));
|
|
@@ -57421,7 +57465,7 @@ __export(heatmap_exports, {
|
|
|
57421
57465
|
buildHeatmap: () => buildHeatmap,
|
|
57422
57466
|
formatHeatmap: () => formatHeatmap
|
|
57423
57467
|
});
|
|
57424
|
-
import { relative as
|
|
57468
|
+
import { relative as relative14 } from "path";
|
|
57425
57469
|
function isWithinDays(lastModified, reference, days) {
|
|
57426
57470
|
const msPerDay = 1e3 * 60 * 60 * 24;
|
|
57427
57471
|
const daysAgo = (reference.getTime() - lastModified.getTime()) / msPerDay;
|
|
@@ -57437,7 +57481,7 @@ async function buildHeatmap(report, cwd, helpers = { getFileEditCount, getFileLa
|
|
|
57437
57481
|
const reference = new Date(report.generatedAt);
|
|
57438
57482
|
const entries = await Promise.all(
|
|
57439
57483
|
report.components.map(async (component) => {
|
|
57440
|
-
const relPath =
|
|
57484
|
+
const relPath = relative14(cwd, component.filePath) || component.filePath;
|
|
57441
57485
|
const [edits, lastModified] = await Promise.all([
|
|
57442
57486
|
helpers.getFileEditCount(cwd, relPath, RECENCY_DAYS),
|
|
57443
57487
|
helpers.getFileLastModifiedDate(cwd, relPath)
|
|
@@ -57782,7 +57826,7 @@ __export(scan_exports, {
|
|
|
57782
57826
|
watchProject: () => watchProject
|
|
57783
57827
|
});
|
|
57784
57828
|
import { existsSync as existsSync20, statSync as statSync8 } from "fs";
|
|
57785
|
-
import { resolve as resolve12, relative as
|
|
57829
|
+
import { resolve as resolve12, relative as relative15, extname as extname7, sep as sep3 } from "path";
|
|
57786
57830
|
import { randomUUID } from "crypto";
|
|
57787
57831
|
async function runScan(options, explicitPaths) {
|
|
57788
57832
|
setLoggerQuiet(!!options.quiet);
|
|
@@ -57830,7 +57874,7 @@ async function runScan(options, explicitPaths) {
|
|
|
57830
57874
|
let files;
|
|
57831
57875
|
if (explicitPaths && explicitPaths.length > 0) {
|
|
57832
57876
|
const { globby: globby4 } = await import("globby");
|
|
57833
|
-
const { minimatch:
|
|
57877
|
+
const { minimatch: minimatch4 } = await import("minimatch");
|
|
57834
57878
|
const resolved = explicitPaths.map((p) => resolve12(cwd, p));
|
|
57835
57879
|
const expanded = [];
|
|
57836
57880
|
for (const p of resolved) {
|
|
@@ -57838,11 +57882,11 @@ async function runScan(options, explicitPaths) {
|
|
|
57838
57882
|
const found = await globby4(`${p}/**/*`, { absolute: true, onlyFiles: true });
|
|
57839
57883
|
for (const f of found) {
|
|
57840
57884
|
if (!ALL_SOURCE_EXTENSIONS.has(extname7(f).toLowerCase())) continue;
|
|
57841
|
-
const rel =
|
|
57842
|
-
if (config.include.length > 0 && !config.include.some((pattern) =>
|
|
57885
|
+
const rel = relative15(cwd, f).split(sep3).join("/");
|
|
57886
|
+
if (config.include.length > 0 && !config.include.some((pattern) => minimatch4(rel, pattern))) {
|
|
57843
57887
|
continue;
|
|
57844
57888
|
}
|
|
57845
|
-
if (config.exclude.some((pattern) =>
|
|
57889
|
+
if (config.exclude.some((pattern) => minimatch4(rel, pattern, { dot: true }))) {
|
|
57846
57890
|
continue;
|
|
57847
57891
|
}
|
|
57848
57892
|
expanded.push(f);
|
|
@@ -61076,7 +61120,7 @@ import { resolve as resolve26 } from "path";
|
|
|
61076
61120
|
init_discover();
|
|
61077
61121
|
init_patterns();
|
|
61078
61122
|
import { readFileSync as readFileSync30 } from "fs";
|
|
61079
|
-
import { basename as basename4, relative as
|
|
61123
|
+
import { basename as basename4, relative as relative16 } from "path";
|
|
61080
61124
|
async function runDrift(cwd, config, options = {}) {
|
|
61081
61125
|
const maxFiles = options.maxFiles ?? 1e3;
|
|
61082
61126
|
const allFiles = await discoverFiles(cwd, config);
|
|
@@ -61098,7 +61142,7 @@ async function runDrift(cwd, config, options = {}) {
|
|
|
61098
61142
|
byCategory[v.category] = (byCategory[v.category] ?? 0) + 1;
|
|
61099
61143
|
byFile.push({
|
|
61100
61144
|
file: absPath,
|
|
61101
|
-
relPath:
|
|
61145
|
+
relPath: relative16(cwd, absPath),
|
|
61102
61146
|
category: v.category,
|
|
61103
61147
|
import: v.import,
|
|
61104
61148
|
declared: v.declared,
|
|
@@ -61220,10 +61264,10 @@ init_metrics();
|
|
|
61220
61264
|
init_patterns();
|
|
61221
61265
|
init_discover();
|
|
61222
61266
|
import { readFileSync as readFileSync31 } from "fs";
|
|
61223
|
-
import { extname as extname9, relative as
|
|
61267
|
+
import { extname as extname9, relative as relative17, resolve as resolve27 } from "path";
|
|
61224
61268
|
import { execFile as execFileCb } from "child_process";
|
|
61225
61269
|
import { promisify as promisify2 } from "util";
|
|
61226
|
-
import { minimatch as
|
|
61270
|
+
import { minimatch as minimatch3 } from "minimatch";
|
|
61227
61271
|
var execFile2 = promisify2(execFileCb);
|
|
61228
61272
|
var PR_EXTENSIONS = /* @__PURE__ */ new Set([...SOURCE_EXTENSIONS, ".mdx"]);
|
|
61229
61273
|
async function refExists(cwd, ref) {
|
|
@@ -61264,11 +61308,11 @@ async function discoverPrFiles(cwd, config, base, head, maxFiles) {
|
|
|
61264
61308
|
const abs = resolve27(cwd, relOrAbs);
|
|
61265
61309
|
const ext = extname9(abs).toLowerCase();
|
|
61266
61310
|
if (!PR_EXTENSIONS.has(ext)) continue;
|
|
61267
|
-
const rel =
|
|
61268
|
-
if (config.include.length > 0 && !config.include.some((pattern) =>
|
|
61311
|
+
const rel = relative17(cwd, abs).split("\\").join("/");
|
|
61312
|
+
if (config.include.length > 0 && !config.include.some((pattern) => minimatch3(rel, pattern))) {
|
|
61269
61313
|
continue;
|
|
61270
61314
|
}
|
|
61271
|
-
if (config.exclude.some((pattern) =>
|
|
61315
|
+
if (config.exclude.some((pattern) => minimatch3(rel, pattern))) {
|
|
61272
61316
|
continue;
|
|
61273
61317
|
}
|
|
61274
61318
|
sourceFiles.push(abs);
|
|
@@ -61335,7 +61379,7 @@ async function runPrScan(cwd, config, options = {}) {
|
|
|
61335
61379
|
totalScore += fileScore;
|
|
61336
61380
|
files.push({
|
|
61337
61381
|
file: absPath,
|
|
61338
|
-
relPath:
|
|
61382
|
+
relPath: relative17(cwd, absPath).split("\\").join("/"),
|
|
61339
61383
|
score: fileScore,
|
|
61340
61384
|
issueCount: issues.length,
|
|
61341
61385
|
constitutionViolationCount: constitutionViolations.length,
|
|
@@ -61712,7 +61756,7 @@ import { resolve as resolve33 } from "path";
|
|
|
61712
61756
|
init_discover();
|
|
61713
61757
|
init_business_logic();
|
|
61714
61758
|
import { readFileSync as readFileSync32 } from "fs";
|
|
61715
|
-
import { relative as
|
|
61759
|
+
import { relative as relative18 } from "path";
|
|
61716
61760
|
async function runBusinessLogicScan(cwd, config, options = {}) {
|
|
61717
61761
|
const maxFiles = options.maxFiles ?? 500;
|
|
61718
61762
|
const allFiles = await discoverFiles(cwd, config);
|
|
@@ -61731,7 +61775,7 @@ async function runBusinessLogicScan(cwd, config, options = {}) {
|
|
|
61731
61775
|
for (const issue of fileIssues) {
|
|
61732
61776
|
issues.push({
|
|
61733
61777
|
...issue,
|
|
61734
|
-
filePath:
|
|
61778
|
+
filePath: relative18(cwd, absPath) || absPath
|
|
61735
61779
|
});
|
|
61736
61780
|
}
|
|
61737
61781
|
}
|
|
@@ -62293,7 +62337,7 @@ import { resolve as resolve37 } from "path";
|
|
|
62293
62337
|
init_patterns();
|
|
62294
62338
|
init_discover();
|
|
62295
62339
|
import { readFileSync as readFileSync33 } from "fs";
|
|
62296
|
-
import { basename as basename5, relative as
|
|
62340
|
+
import { basename as basename5, relative as relative19 } from "path";
|
|
62297
62341
|
var PATTERN_CATEGORIES = [
|
|
62298
62342
|
"modal",
|
|
62299
62343
|
"button",
|
|
@@ -62385,7 +62429,7 @@ function detectApiFromFiles(files, cwd) {
|
|
|
62385
62429
|
const out = [];
|
|
62386
62430
|
for (const f of files) {
|
|
62387
62431
|
if (API_PATH_RE2.test(f)) {
|
|
62388
|
-
out.push(
|
|
62432
|
+
out.push(relative19(cwd, f).split("\\").join("/"));
|
|
62389
62433
|
}
|
|
62390
62434
|
}
|
|
62391
62435
|
return out;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "slopbrick",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.25.0",
|
|
4
4
|
"description": "Discovered, modeled, and governed repository structure. SlopBrick scans source code, classifies it against 95+ rules in 15 categories, computes 4 scores (aiSlopScore: lower=cleaner, engineeringHygiene, security, repositoryHealth composite), and persists the structure for AI agents and CI.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"bin": {
|