slopbrick 0.17.2 → 0.17.4
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 +23 -15
- package/dist/engine/worker.js +21 -13
- package/dist/index.cjs +93 -62
- package/dist/index.js +87 -56
- package/package.json +1 -1
package/dist/engine/worker.cjs
CHANGED
|
@@ -4084,6 +4084,9 @@ var VERDICTS = [
|
|
|
4084
4084
|
"HYGIENE",
|
|
4085
4085
|
"DORMANT"
|
|
4086
4086
|
];
|
|
4087
|
+
function isDefaultOff(verdict) {
|
|
4088
|
+
return verdict === "NOISY" || verdict === "INVERTED" || verdict === "DORMANT";
|
|
4089
|
+
}
|
|
4087
4090
|
var signalStrengthSchema = external_exports.record(
|
|
4088
4091
|
external_exports.string(),
|
|
4089
4092
|
// ruleId
|
|
@@ -4096,7 +4099,13 @@ var signalStrengthSchema = external_exports.record(
|
|
|
4096
4099
|
verdict: external_exports.enum(VERDICTS),
|
|
4097
4100
|
// defaultOff is opt-in per-rule. Absent = the rule follows
|
|
4098
4101
|
// isDefaultOff(verdict). Present (true or false) = user override.
|
|
4099
|
-
defaultOff: external_exports.boolean().optional()
|
|
4102
|
+
defaultOff: external_exports.boolean().optional(),
|
|
4103
|
+
// v0.17.3 (B5): mark rules whose signal is specific to AI
|
|
4104
|
+
// generation. Without this field, the composite scoring pipeline
|
|
4105
|
+
// can't distinguish "this rule fires on AI slop" from "this rule
|
|
4106
|
+
// fires on sloppy code in general" — and gives zero weight to
|
|
4107
|
+
// both. See packages/engine/src/composite-scoring.ts:136,164.
|
|
4108
|
+
aiSpecific: external_exports.boolean().optional()
|
|
4100
4109
|
})
|
|
4101
4110
|
);
|
|
4102
4111
|
|
|
@@ -4162,11 +4171,6 @@ function syntaxCandidates(filePath, source) {
|
|
|
4162
4171
|
{ syntax: "typescript", jsx: true },
|
|
4163
4172
|
{ syntax: "typescript", jsx: false, tsx: false }
|
|
4164
4173
|
];
|
|
4165
|
-
case "mjs":
|
|
4166
|
-
return [
|
|
4167
|
-
{ syntax: "ecmascript", jsx: true },
|
|
4168
|
-
{ syntax: "ecmascript", jsx: false }
|
|
4169
|
-
];
|
|
4170
4174
|
default:
|
|
4171
4175
|
return [
|
|
4172
4176
|
{ syntax: "typescript", jsx: false, tsx: true },
|
|
@@ -4363,7 +4367,11 @@ var FPR_FLOOR = 1e-6;
|
|
|
4363
4367
|
var RECALL_FLOOR = 1e-6;
|
|
4364
4368
|
var LLR_CAP = 13.8;
|
|
4365
4369
|
var DEFAULT_PRIOR_PREVALENCE = 0.3;
|
|
4366
|
-
var ELIGIBLE_VERDICTS =
|
|
4370
|
+
var ELIGIBLE_VERDICTS = new Set(
|
|
4371
|
+
["USEFUL", "OK", "NOISY", "INVERTED", "HYGIENE", "DORMANT"].filter(
|
|
4372
|
+
(v) => v !== "HYGIENE" && !isDefaultOff(v)
|
|
4373
|
+
)
|
|
4374
|
+
);
|
|
4367
4375
|
function loadSignals(signalData) {
|
|
4368
4376
|
const map = /* @__PURE__ */ new Map();
|
|
4369
4377
|
for (const [ruleId, entry] of Object.entries(signalData)) {
|
|
@@ -34908,7 +34916,7 @@ var mathElementUniformityRule = createRule({
|
|
|
34908
34916
|
if (!anchor) anchor = { line: el.line, column: el.column };
|
|
34909
34917
|
}
|
|
34910
34918
|
}
|
|
34911
|
-
const values = [counts.button, counts.input, counts.select].filter((v) => v > 0);
|
|
34919
|
+
const values = [counts.button, counts.input, counts.select].filter((v) => typeof v === "number" && v > 0);
|
|
34912
34920
|
if (values.length < 2) return issues;
|
|
34913
34921
|
const max = Math.max(...values);
|
|
34914
34922
|
const min = Math.min(...values);
|
|
@@ -34957,7 +34965,7 @@ var mathGridUniformityRule = createRule({
|
|
|
34957
34965
|
const { h, vocab, total } = shannonEntropy(counts);
|
|
34958
34966
|
if (total < 4) return issues;
|
|
34959
34967
|
if (h > 1) return issues;
|
|
34960
|
-
const anchor = facts.v2 ? flatClassNames(facts.v2)[0] : { line: 1, column: 1 };
|
|
34968
|
+
const anchor = facts.v2 ? flatClassNames(facts.v2)[0] ?? { line: 1, column: 1 } : { line: 1, column: 1 };
|
|
34961
34969
|
issues.push({
|
|
34962
34970
|
ruleId: "layout/math-grid-uniformity",
|
|
34963
34971
|
category: "layout",
|
|
@@ -35840,7 +35848,7 @@ var mathGiniClassUsageRule = createRule({
|
|
|
35840
35848
|
if (g < 0.5) return issues;
|
|
35841
35849
|
const sorted = [...counts.entries()].sort((a, b) => b[1] - a[1]).slice(0, 3);
|
|
35842
35850
|
const topStr = sorted.map(([k, v]) => `${k}\xD7${v}`).join(", ");
|
|
35843
|
-
const anchor = facts.v2 ? flatClassNames(facts.v2)[0] : { line: 1, column: 1 };
|
|
35851
|
+
const anchor = facts.v2 ? flatClassNames(facts.v2)[0] ?? { line: 1, column: 1 } : { line: 1, column: 1 };
|
|
35844
35852
|
issues.push({
|
|
35845
35853
|
ruleId: "logic/math-gini-class-usage",
|
|
35846
35854
|
category: "logic",
|
|
@@ -37659,7 +37667,7 @@ function looksRealistic(value) {
|
|
|
37659
37667
|
}
|
|
37660
37668
|
|
|
37661
37669
|
// src/rules/test/missing-edge-case.ts
|
|
37662
|
-
var
|
|
37670
|
+
var import_core4 = require("@swc/core");
|
|
37663
37671
|
var import_node_fs11 = require("fs");
|
|
37664
37672
|
var MAX_PER_FILE = 20;
|
|
37665
37673
|
var missingEdgeCaseRule = createRule({
|
|
@@ -37703,7 +37711,7 @@ var missingEdgeCaseRule = createRule({
|
|
|
37703
37711
|
if (!source) return issues;
|
|
37704
37712
|
let ast;
|
|
37705
37713
|
try {
|
|
37706
|
-
ast = (0,
|
|
37714
|
+
ast = (0, import_core4.parseSync)(source, {
|
|
37707
37715
|
syntax: "typescript",
|
|
37708
37716
|
tsx: filePath.endsWith("tsx") || filePath.endsWith("jsx"),
|
|
37709
37717
|
target: "es2022"
|
|
@@ -38820,7 +38828,7 @@ var mathFontEntropyRule = createRule({
|
|
|
38820
38828
|
const { h, vocab, total } = shannonEntropy(counts);
|
|
38821
38829
|
if (total < 6) return issues;
|
|
38822
38830
|
if (h > 1.4) return issues;
|
|
38823
|
-
const anchor = flatClassNames(facts.v2)[0];
|
|
38831
|
+
const anchor = flatClassNames(facts.v2)[0] ?? { line: 1, column: 1 };
|
|
38824
38832
|
issues.push({
|
|
38825
38833
|
ruleId: "visual/math-font-entropy",
|
|
38826
38834
|
category: "visual",
|
|
@@ -38942,7 +38950,7 @@ var mathRoundedEntropyRule = createRule({
|
|
|
38942
38950
|
const { h, vocab, total } = shannonEntropy(counts);
|
|
38943
38951
|
if (total < 6) return issues;
|
|
38944
38952
|
if (h > 1.8) return issues;
|
|
38945
|
-
const anchor = flatClassNames(facts.v2)[0];
|
|
38953
|
+
const anchor = flatClassNames(facts.v2)[0] ?? { line: 1, column: 1 };
|
|
38946
38954
|
issues.push({
|
|
38947
38955
|
ruleId: "visual/math-rounded-entropy",
|
|
38948
38956
|
category: "visual",
|
|
@@ -38981,7 +38989,7 @@ var mathSpacingEntropyRule = createRule({
|
|
|
38981
38989
|
const { h, vocab, total } = shannonEntropy(counts);
|
|
38982
38990
|
if (total < 10) return issues;
|
|
38983
38991
|
if (h > 1.5) return issues;
|
|
38984
|
-
const anchor = flatClassNames(facts.v2)[0];
|
|
38992
|
+
const anchor = flatClassNames(facts.v2)[0] ?? { line: 1, column: 1 };
|
|
38985
38993
|
issues.push({
|
|
38986
38994
|
ruleId: "visual/math-spacing-entropy",
|
|
38987
38995
|
category: "visual",
|
package/dist/engine/worker.js
CHANGED
|
@@ -4065,6 +4065,9 @@ var VERDICTS = [
|
|
|
4065
4065
|
"HYGIENE",
|
|
4066
4066
|
"DORMANT"
|
|
4067
4067
|
];
|
|
4068
|
+
function isDefaultOff(verdict) {
|
|
4069
|
+
return verdict === "NOISY" || verdict === "INVERTED" || verdict === "DORMANT";
|
|
4070
|
+
}
|
|
4068
4071
|
var signalStrengthSchema = external_exports.record(
|
|
4069
4072
|
external_exports.string(),
|
|
4070
4073
|
// ruleId
|
|
@@ -4077,7 +4080,13 @@ var signalStrengthSchema = external_exports.record(
|
|
|
4077
4080
|
verdict: external_exports.enum(VERDICTS),
|
|
4078
4081
|
// defaultOff is opt-in per-rule. Absent = the rule follows
|
|
4079
4082
|
// isDefaultOff(verdict). Present (true or false) = user override.
|
|
4080
|
-
defaultOff: external_exports.boolean().optional()
|
|
4083
|
+
defaultOff: external_exports.boolean().optional(),
|
|
4084
|
+
// v0.17.3 (B5): mark rules whose signal is specific to AI
|
|
4085
|
+
// generation. Without this field, the composite scoring pipeline
|
|
4086
|
+
// can't distinguish "this rule fires on AI slop" from "this rule
|
|
4087
|
+
// fires on sloppy code in general" — and gives zero weight to
|
|
4088
|
+
// both. See packages/engine/src/composite-scoring.ts:136,164.
|
|
4089
|
+
aiSpecific: external_exports.boolean().optional()
|
|
4081
4090
|
})
|
|
4082
4091
|
);
|
|
4083
4092
|
|
|
@@ -4143,11 +4152,6 @@ function syntaxCandidates(filePath, source) {
|
|
|
4143
4152
|
{ syntax: "typescript", jsx: true },
|
|
4144
4153
|
{ syntax: "typescript", jsx: false, tsx: false }
|
|
4145
4154
|
];
|
|
4146
|
-
case "mjs":
|
|
4147
|
-
return [
|
|
4148
|
-
{ syntax: "ecmascript", jsx: true },
|
|
4149
|
-
{ syntax: "ecmascript", jsx: false }
|
|
4150
|
-
];
|
|
4151
4155
|
default:
|
|
4152
4156
|
return [
|
|
4153
4157
|
{ syntax: "typescript", jsx: false, tsx: true },
|
|
@@ -4344,7 +4348,11 @@ var FPR_FLOOR = 1e-6;
|
|
|
4344
4348
|
var RECALL_FLOOR = 1e-6;
|
|
4345
4349
|
var LLR_CAP = 13.8;
|
|
4346
4350
|
var DEFAULT_PRIOR_PREVALENCE = 0.3;
|
|
4347
|
-
var ELIGIBLE_VERDICTS =
|
|
4351
|
+
var ELIGIBLE_VERDICTS = new Set(
|
|
4352
|
+
["USEFUL", "OK", "NOISY", "INVERTED", "HYGIENE", "DORMANT"].filter(
|
|
4353
|
+
(v) => v !== "HYGIENE" && !isDefaultOff(v)
|
|
4354
|
+
)
|
|
4355
|
+
);
|
|
4348
4356
|
function loadSignals(signalData) {
|
|
4349
4357
|
const map = /* @__PURE__ */ new Map();
|
|
4350
4358
|
for (const [ruleId, entry] of Object.entries(signalData)) {
|
|
@@ -34889,7 +34897,7 @@ var mathElementUniformityRule = createRule({
|
|
|
34889
34897
|
if (!anchor) anchor = { line: el.line, column: el.column };
|
|
34890
34898
|
}
|
|
34891
34899
|
}
|
|
34892
|
-
const values = [counts.button, counts.input, counts.select].filter((v) => v > 0);
|
|
34900
|
+
const values = [counts.button, counts.input, counts.select].filter((v) => typeof v === "number" && v > 0);
|
|
34893
34901
|
if (values.length < 2) return issues;
|
|
34894
34902
|
const max = Math.max(...values);
|
|
34895
34903
|
const min = Math.min(...values);
|
|
@@ -34938,7 +34946,7 @@ var mathGridUniformityRule = createRule({
|
|
|
34938
34946
|
const { h, vocab, total } = shannonEntropy(counts);
|
|
34939
34947
|
if (total < 4) return issues;
|
|
34940
34948
|
if (h > 1) return issues;
|
|
34941
|
-
const anchor = facts.v2 ? flatClassNames(facts.v2)[0] : { line: 1, column: 1 };
|
|
34949
|
+
const anchor = facts.v2 ? flatClassNames(facts.v2)[0] ?? { line: 1, column: 1 } : { line: 1, column: 1 };
|
|
34942
34950
|
issues.push({
|
|
34943
34951
|
ruleId: "layout/math-grid-uniformity",
|
|
34944
34952
|
category: "layout",
|
|
@@ -35821,7 +35829,7 @@ var mathGiniClassUsageRule = createRule({
|
|
|
35821
35829
|
if (g < 0.5) return issues;
|
|
35822
35830
|
const sorted = [...counts.entries()].sort((a, b) => b[1] - a[1]).slice(0, 3);
|
|
35823
35831
|
const topStr = sorted.map(([k, v]) => `${k}\xD7${v}`).join(", ");
|
|
35824
|
-
const anchor = facts.v2 ? flatClassNames(facts.v2)[0] : { line: 1, column: 1 };
|
|
35832
|
+
const anchor = facts.v2 ? flatClassNames(facts.v2)[0] ?? { line: 1, column: 1 } : { line: 1, column: 1 };
|
|
35825
35833
|
issues.push({
|
|
35826
35834
|
ruleId: "logic/math-gini-class-usage",
|
|
35827
35835
|
category: "logic",
|
|
@@ -38801,7 +38809,7 @@ var mathFontEntropyRule = createRule({
|
|
|
38801
38809
|
const { h, vocab, total } = shannonEntropy(counts);
|
|
38802
38810
|
if (total < 6) return issues;
|
|
38803
38811
|
if (h > 1.4) return issues;
|
|
38804
|
-
const anchor = flatClassNames(facts.v2)[0];
|
|
38812
|
+
const anchor = flatClassNames(facts.v2)[0] ?? { line: 1, column: 1 };
|
|
38805
38813
|
issues.push({
|
|
38806
38814
|
ruleId: "visual/math-font-entropy",
|
|
38807
38815
|
category: "visual",
|
|
@@ -38923,7 +38931,7 @@ var mathRoundedEntropyRule = createRule({
|
|
|
38923
38931
|
const { h, vocab, total } = shannonEntropy(counts);
|
|
38924
38932
|
if (total < 6) return issues;
|
|
38925
38933
|
if (h > 1.8) return issues;
|
|
38926
|
-
const anchor = flatClassNames(facts.v2)[0];
|
|
38934
|
+
const anchor = flatClassNames(facts.v2)[0] ?? { line: 1, column: 1 };
|
|
38927
38935
|
issues.push({
|
|
38928
38936
|
ruleId: "visual/math-rounded-entropy",
|
|
38929
38937
|
category: "visual",
|
|
@@ -38962,7 +38970,7 @@ var mathSpacingEntropyRule = createRule({
|
|
|
38962
38970
|
const { h, vocab, total } = shannonEntropy(counts);
|
|
38963
38971
|
if (total < 10) return issues;
|
|
38964
38972
|
if (h > 1.5) return issues;
|
|
38965
|
-
const anchor = flatClassNames(facts.v2)[0];
|
|
38973
|
+
const anchor = flatClassNames(facts.v2)[0] ?? { line: 1, column: 1 };
|
|
38966
38974
|
issues.push({
|
|
38967
38975
|
ruleId: "visual/math-spacing-entropy",
|
|
38968
38976
|
category: "visual",
|
package/dist/index.cjs
CHANGED
|
@@ -30242,7 +30242,7 @@ var init_math_element_uniformity = __esm({
|
|
|
30242
30242
|
if (!anchor) anchor = { line: el.line, column: el.column };
|
|
30243
30243
|
}
|
|
30244
30244
|
}
|
|
30245
|
-
const values = [counts.button, counts.input, counts.select].filter((v) => v > 0);
|
|
30245
|
+
const values = [counts.button, counts.input, counts.select].filter((v) => typeof v === "number" && v > 0);
|
|
30246
30246
|
if (values.length < 2) return issues;
|
|
30247
30247
|
const max = Math.max(...values);
|
|
30248
30248
|
const min = Math.min(...values);
|
|
@@ -30300,7 +30300,7 @@ var init_math_grid_uniformity = __esm({
|
|
|
30300
30300
|
const { h, vocab, total } = shannonEntropy(counts);
|
|
30301
30301
|
if (total < 4) return issues;
|
|
30302
30302
|
if (h > 1) return issues;
|
|
30303
|
-
const anchor = facts.v2 ? flatClassNames(facts.v2)[0] : { line: 1, column: 1 };
|
|
30303
|
+
const anchor = facts.v2 ? flatClassNames(facts.v2)[0] ?? { line: 1, column: 1 } : { line: 1, column: 1 };
|
|
30304
30304
|
issues.push({
|
|
30305
30305
|
ruleId: "layout/math-grid-uniformity",
|
|
30306
30306
|
category: "layout",
|
|
@@ -34733,59 +34733,77 @@ __export(dist_exports, {
|
|
|
34733
34733
|
writeCacheFromInventory: () => writeCacheFromInventory,
|
|
34734
34734
|
writeJsonAtomic: () => writeJsonAtomic
|
|
34735
34735
|
});
|
|
34736
|
+
function isRecord(v) {
|
|
34737
|
+
return typeof v === "object" && v !== null && !Array.isArray(v);
|
|
34738
|
+
}
|
|
34739
|
+
function isStringArray(v) {
|
|
34740
|
+
return Array.isArray(v) && v.every((i) => typeof i === "string");
|
|
34741
|
+
}
|
|
34742
|
+
function isNumber(v) {
|
|
34743
|
+
return typeof v === "number" && Number.isFinite(v);
|
|
34744
|
+
}
|
|
34736
34745
|
function isStructurePattern(value) {
|
|
34737
|
-
if (
|
|
34738
|
-
|
|
34739
|
-
return typeof v.category === "string" && typeof v.name === "string" && Array.isArray(v.imports) && v.imports.every((i) => typeof i === "string") && typeof v.fileCount === "number";
|
|
34746
|
+
if (!isRecord(value)) return false;
|
|
34747
|
+
return typeof value.category === "string" && typeof value.name === "string" && isStringArray(value.imports) && isNumber(value.fileCount);
|
|
34740
34748
|
}
|
|
34741
34749
|
function isComponentFingerprint(value) {
|
|
34742
|
-
if (
|
|
34743
|
-
|
|
34744
|
-
|
|
34750
|
+
if (!isRecord(value)) return false;
|
|
34751
|
+
return typeof value.name === "string" && isStringArray(value.files) && typeof value.fingerprint === "string" && isStringArray(value.hooks) && isStringArray(value.props) && isNumber(value.line) && isNumber(value.endLine);
|
|
34752
|
+
}
|
|
34753
|
+
function isVersion3(value) {
|
|
34754
|
+
return value === STRUCTURE_SCHEMA_VERSION;
|
|
34745
34755
|
}
|
|
34746
34756
|
function isInventoryFile(value) {
|
|
34747
|
-
if (
|
|
34748
|
-
|
|
34749
|
-
|
|
34757
|
+
if (!isRecord(value)) return false;
|
|
34758
|
+
if (!isVersion3(value.version)) return false;
|
|
34759
|
+
if (typeof value.generatedAt !== "string") return false;
|
|
34760
|
+
if (typeof value.workspace !== "string") return false;
|
|
34761
|
+
if (!isNumber(value.scannedFiles)) return false;
|
|
34762
|
+
if (!isNumber(value.scanDurationMs)) return false;
|
|
34763
|
+
if (!Array.isArray(value.patterns) || !value.patterns.every(isStructurePattern)) return false;
|
|
34764
|
+
if (!Array.isArray(value.components) || !value.components.every(isComponentFingerprint)) return false;
|
|
34765
|
+
return true;
|
|
34750
34766
|
}
|
|
34751
34767
|
function isConstitutionFile(value) {
|
|
34752
|
-
if (
|
|
34753
|
-
|
|
34754
|
-
|
|
34768
|
+
if (!isRecord(value)) return false;
|
|
34769
|
+
if (!isVersion3(value.version)) return false;
|
|
34770
|
+
if (typeof value.generatedAt !== "string") return false;
|
|
34771
|
+
if (typeof value.workspace !== "string") return false;
|
|
34772
|
+
if (!isRecord(value.declared)) return false;
|
|
34773
|
+
if (!isStringArray(value.forbidden)) return false;
|
|
34774
|
+
if (!isStringArray(value.forbiddenPrefixes)) return false;
|
|
34775
|
+
return true;
|
|
34755
34776
|
}
|
|
34756
34777
|
function isFileMtimeEntry(value) {
|
|
34757
|
-
if (
|
|
34758
|
-
|
|
34759
|
-
return typeof v.file === "string" && typeof v.mtimeMs === "number" && typeof v.hash === "string";
|
|
34778
|
+
if (!isRecord(value)) return false;
|
|
34779
|
+
return typeof value.file === "string" && isNumber(value.mtimeMs) && typeof value.hash === "string";
|
|
34760
34780
|
}
|
|
34761
34781
|
function isHealthFile(value) {
|
|
34762
|
-
if (
|
|
34763
|
-
|
|
34764
|
-
if (
|
|
34765
|
-
if (typeof
|
|
34766
|
-
if (
|
|
34767
|
-
if (
|
|
34768
|
-
if (
|
|
34769
|
-
if (
|
|
34770
|
-
if (
|
|
34771
|
-
|
|
34772
|
-
|
|
34773
|
-
if (
|
|
34774
|
-
if (
|
|
34775
|
-
if (
|
|
34776
|
-
if (
|
|
34777
|
-
|
|
34778
|
-
|
|
34779
|
-
|
|
34780
|
-
|
|
34781
|
-
|
|
34782
|
-
|
|
34783
|
-
if (
|
|
34784
|
-
|
|
34785
|
-
|
|
34786
|
-
|
|
34787
|
-
}
|
|
34788
|
-
if (v.scanDurationMs !== void 0 && typeof v.scanDurationMs !== "number") return false;
|
|
34782
|
+
if (!isRecord(value)) return false;
|
|
34783
|
+
if (!isVersion3(value.version)) return false;
|
|
34784
|
+
if (typeof value.generatedAt !== "string") return false;
|
|
34785
|
+
if (typeof value.workspace !== "string") return false;
|
|
34786
|
+
if (!isNumber(value.aiQuality)) return false;
|
|
34787
|
+
if (!isNumber(value.engineeringHygiene)) return false;
|
|
34788
|
+
if (!isNumber(value.security)) return false;
|
|
34789
|
+
if (!isNumber(value.repositoryHealth)) return false;
|
|
34790
|
+
if (!isRecord(value.issueCounts)) return false;
|
|
34791
|
+
const counts = value.issueCounts;
|
|
34792
|
+
if (!isNumber(counts.high)) return false;
|
|
34793
|
+
if (!isNumber(counts.medium)) return false;
|
|
34794
|
+
if (!isNumber(counts.low)) return false;
|
|
34795
|
+
if (value.slopIndex !== void 0 && !isNumber(value.slopIndex)) return false;
|
|
34796
|
+
if (value.categoryScores !== void 0) {
|
|
34797
|
+
if (!isRecord(value.categoryScores)) return false;
|
|
34798
|
+
for (const score of Object.values(value.categoryScores)) {
|
|
34799
|
+
if (!isNumber(score)) return false;
|
|
34800
|
+
}
|
|
34801
|
+
}
|
|
34802
|
+
if (value.constitutionDrift !== void 0 && !isNumber(value.constitutionDrift)) return false;
|
|
34803
|
+
if (value.topOffenseIds !== void 0) {
|
|
34804
|
+
if (!isStringArray(value.topOffenseIds)) return false;
|
|
34805
|
+
}
|
|
34806
|
+
if (value.scanDurationMs !== void 0 && !isNumber(value.scanDurationMs)) return false;
|
|
34789
34807
|
return true;
|
|
34790
34808
|
}
|
|
34791
34809
|
function inventoryPath(workspaceDir) {
|
|
@@ -34945,7 +34963,13 @@ var init_dist = __esm({
|
|
|
34945
34963
|
verdict: external_exports.enum(VERDICTS),
|
|
34946
34964
|
// defaultOff is opt-in per-rule. Absent = the rule follows
|
|
34947
34965
|
// isDefaultOff(verdict). Present (true or false) = user override.
|
|
34948
|
-
defaultOff: external_exports.boolean().optional()
|
|
34966
|
+
defaultOff: external_exports.boolean().optional(),
|
|
34967
|
+
// v0.17.3 (B5): mark rules whose signal is specific to AI
|
|
34968
|
+
// generation. Without this field, the composite scoring pipeline
|
|
34969
|
+
// can't distinguish "this rule fires on AI slop" from "this rule
|
|
34970
|
+
// fires on sloppy code in general" — and gives zero weight to
|
|
34971
|
+
// both. See packages/engine/src/composite-scoring.ts:136,164.
|
|
34972
|
+
aiSpecific: external_exports.boolean().optional()
|
|
34949
34973
|
})
|
|
34950
34974
|
);
|
|
34951
34975
|
}
|
|
@@ -35133,11 +35157,6 @@ function syntaxCandidates(filePath, source) {
|
|
|
35133
35157
|
{ syntax: "typescript", jsx: true },
|
|
35134
35158
|
{ syntax: "typescript", jsx: false, tsx: false }
|
|
35135
35159
|
];
|
|
35136
|
-
case "mjs":
|
|
35137
|
-
return [
|
|
35138
|
-
{ syntax: "ecmascript", jsx: true },
|
|
35139
|
-
{ syntax: "ecmascript", jsx: false }
|
|
35140
|
-
];
|
|
35141
35160
|
default:
|
|
35142
35161
|
return [
|
|
35143
35162
|
{ syntax: "typescript", jsx: false, tsx: true },
|
|
@@ -36800,6 +36819,7 @@ var init_dist2 = __esm({
|
|
|
36800
36819
|
import_path3 = require("path");
|
|
36801
36820
|
import_crypto2 = require("crypto");
|
|
36802
36821
|
init_dist();
|
|
36822
|
+
init_dist();
|
|
36803
36823
|
import_crypto3 = require("crypto");
|
|
36804
36824
|
import_promises2 = require("fs/promises");
|
|
36805
36825
|
import_path4 = require("path");
|
|
@@ -36811,7 +36831,11 @@ var init_dist2 = __esm({
|
|
|
36811
36831
|
RECALL_FLOOR = 1e-6;
|
|
36812
36832
|
LLR_CAP = 13.8;
|
|
36813
36833
|
DEFAULT_PRIOR_PREVALENCE = 0.3;
|
|
36814
|
-
ELIGIBLE_VERDICTS =
|
|
36834
|
+
ELIGIBLE_VERDICTS = new Set(
|
|
36835
|
+
["USEFUL", "OK", "NOISY", "INVERTED", "HYGIENE", "DORMANT"].filter(
|
|
36836
|
+
(v) => v !== "HYGIENE" && !isDefaultOff(v)
|
|
36837
|
+
)
|
|
36838
|
+
);
|
|
36815
36839
|
SUFFIXES_TO_STRIP = [
|
|
36816
36840
|
"RepositoryClient",
|
|
36817
36841
|
"ServiceFactory",
|
|
@@ -37651,7 +37675,7 @@ var init_math_gini_class_usage = __esm({
|
|
|
37651
37675
|
if (g < 0.5) return issues;
|
|
37652
37676
|
const sorted = [...counts.entries()].sort((a, b) => b[1] - a[1]).slice(0, 3);
|
|
37653
37677
|
const topStr = sorted.map(([k, v]) => `${k}\xD7${v}`).join(", ");
|
|
37654
|
-
const anchor = facts.v2 ? flatClassNames(facts.v2)[0] : { line: 1, column: 1 };
|
|
37678
|
+
const anchor = facts.v2 ? flatClassNames(facts.v2)[0] ?? { line: 1, column: 1 } : { line: 1, column: 1 };
|
|
37655
37679
|
issues.push({
|
|
37656
37680
|
ruleId: "logic/math-gini-class-usage",
|
|
37657
37681
|
category: "logic",
|
|
@@ -39911,11 +39935,11 @@ function coveredFunctionNames(names, testFileSources, cwd) {
|
|
|
39911
39935
|
}
|
|
39912
39936
|
return covered;
|
|
39913
39937
|
}
|
|
39914
|
-
var
|
|
39938
|
+
var import_core4, import_node_fs10, MAX_PER_FILE, missingEdgeCaseRule;
|
|
39915
39939
|
var init_missing_edge_case = __esm({
|
|
39916
39940
|
"src/rules/test/missing-edge-case.ts"() {
|
|
39917
39941
|
"use strict";
|
|
39918
|
-
|
|
39942
|
+
import_core4 = require("@swc/core");
|
|
39919
39943
|
import_node_fs10 = require("fs");
|
|
39920
39944
|
init_rule();
|
|
39921
39945
|
MAX_PER_FILE = 20;
|
|
@@ -39960,7 +39984,7 @@ var init_missing_edge_case = __esm({
|
|
|
39960
39984
|
if (!source) return issues;
|
|
39961
39985
|
let ast;
|
|
39962
39986
|
try {
|
|
39963
|
-
ast = (0,
|
|
39987
|
+
ast = (0, import_core4.parseSync)(source, {
|
|
39964
39988
|
syntax: "typescript",
|
|
39965
39989
|
tsx: filePath.endsWith("tsx") || filePath.endsWith("jsx"),
|
|
39966
39990
|
target: "es2022"
|
|
@@ -40954,7 +40978,7 @@ var init_math_font_entropy = __esm({
|
|
|
40954
40978
|
const { h, vocab, total } = shannonEntropy(counts);
|
|
40955
40979
|
if (total < 6) return issues;
|
|
40956
40980
|
if (h > 1.4) return issues;
|
|
40957
|
-
const anchor = flatClassNames(facts.v2)[0];
|
|
40981
|
+
const anchor = flatClassNames(facts.v2)[0] ?? { line: 1, column: 1 };
|
|
40958
40982
|
issues.push({
|
|
40959
40983
|
ruleId: "visual/math-font-entropy",
|
|
40960
40984
|
category: "visual",
|
|
@@ -41094,7 +41118,7 @@ var init_math_rounded_entropy = __esm({
|
|
|
41094
41118
|
const { h, vocab, total } = shannonEntropy(counts);
|
|
41095
41119
|
if (total < 6) return issues;
|
|
41096
41120
|
if (h > 1.8) return issues;
|
|
41097
|
-
const anchor = flatClassNames(facts.v2)[0];
|
|
41121
|
+
const anchor = flatClassNames(facts.v2)[0] ?? { line: 1, column: 1 };
|
|
41098
41122
|
issues.push({
|
|
41099
41123
|
ruleId: "visual/math-rounded-entropy",
|
|
41100
41124
|
category: "visual",
|
|
@@ -41142,7 +41166,7 @@ var init_math_spacing_entropy = __esm({
|
|
|
41142
41166
|
const { h, vocab, total } = shannonEntropy(counts);
|
|
41143
41167
|
if (total < 10) return issues;
|
|
41144
41168
|
if (h > 1.5) return issues;
|
|
41145
|
-
const anchor = flatClassNames(facts.v2)[0];
|
|
41169
|
+
const anchor = flatClassNames(facts.v2)[0] ?? { line: 1, column: 1 };
|
|
41146
41170
|
issues.push({
|
|
41147
41171
|
ruleId: "visual/math-spacing-entropy",
|
|
41148
41172
|
category: "visual",
|
|
@@ -48205,7 +48229,7 @@ function confirmMagicRateLiteral(line) {
|
|
|
48205
48229
|
const probe = `let __probe = (${line});`;
|
|
48206
48230
|
let ast;
|
|
48207
48231
|
try {
|
|
48208
|
-
ast = (0,
|
|
48232
|
+
ast = (0, import_core6.parseSync)(probe, { syntax: "ecmascript", target: "es2022" });
|
|
48209
48233
|
} catch {
|
|
48210
48234
|
return true;
|
|
48211
48235
|
}
|
|
@@ -48484,11 +48508,11 @@ function extractIdentifier(line) {
|
|
|
48484
48508
|
const m = line.match(/Math\.round\s*\(\s*([A-Za-z_$][\w$.]*)/);
|
|
48485
48509
|
return m ? m[1] ?? "" : "<expr>";
|
|
48486
48510
|
}
|
|
48487
|
-
var
|
|
48511
|
+
var import_core6, BUSINESS_LOGIC_WEIGHTS, CURRENCY_IDENTIFIERS, COMMON_RATE_LITERALS, MATH_ROUND_CENTS, MAGIC_RATE_DECIMAL, HARDCODED_CURRENCY_SYMBOL, SOURCE_EXTENSION, ZOD_STRING, ZOD_STRING_CALL, REQUIRED_ERROR, INVALID_TYPE_ERROR, HARDCODED_ISO_DATE, LOCALE_STRING_NO_OPTIONS, RAW_CURRENCY_IN_TEMPLATE;
|
|
48488
48512
|
var init_business_logic = __esm({
|
|
48489
48513
|
"src/engine/business-logic.ts"() {
|
|
48490
48514
|
"use strict";
|
|
48491
|
-
|
|
48515
|
+
import_core6 = require("@swc/core");
|
|
48492
48516
|
BUSINESS_LOGIC_WEIGHTS = {
|
|
48493
48517
|
pricing: 3,
|
|
48494
48518
|
validation: 2,
|
|
@@ -49859,6 +49883,13 @@ function mergeComponentsByName(components) {
|
|
|
49859
49883
|
}
|
|
49860
49884
|
byName.set(c.name, {
|
|
49861
49885
|
...c,
|
|
49886
|
+
// All visitors (rust.ts, php.ts, go.ts, …) push Components with
|
|
49887
|
+
// `files: [filePath]` — non-empty by construction. The JSON
|
|
49888
|
+
// Schema (inventory.schema.json) requires `files` to be
|
|
49889
|
+
// `[string, ...string[]]` (at least 1); the cast is safe under
|
|
49890
|
+
// the visitor invariant. If a future visitor ever produces an
|
|
49891
|
+
// empty files array, the runtime validator
|
|
49892
|
+
// (`isInventoryFile`) will reject the artifact at write time.
|
|
49862
49893
|
files: c.files.slice(),
|
|
49863
49894
|
hooks: c.hooks.slice(),
|
|
49864
49895
|
props: c.props.slice()
|
|
@@ -55052,7 +55083,7 @@ function promptMultiSelect(rl, question, options, defaultValue) {
|
|
|
55052
55083
|
resolve18([]);
|
|
55053
55084
|
return;
|
|
55054
55085
|
}
|
|
55055
|
-
const selected = [...new Set(numbers.map((n) => options[n - 2]))];
|
|
55086
|
+
const selected = [...new Set(numbers.map((n) => options[n - 2]).filter((v) => v !== void 0))];
|
|
55056
55087
|
resolve18(selected);
|
|
55057
55088
|
});
|
|
55058
55089
|
}
|
package/dist/index.js
CHANGED
|
@@ -30235,7 +30235,7 @@ var init_math_element_uniformity = __esm({
|
|
|
30235
30235
|
if (!anchor) anchor = { line: el.line, column: el.column };
|
|
30236
30236
|
}
|
|
30237
30237
|
}
|
|
30238
|
-
const values = [counts.button, counts.input, counts.select].filter((v) => v > 0);
|
|
30238
|
+
const values = [counts.button, counts.input, counts.select].filter((v) => typeof v === "number" && v > 0);
|
|
30239
30239
|
if (values.length < 2) return issues;
|
|
30240
30240
|
const max = Math.max(...values);
|
|
30241
30241
|
const min = Math.min(...values);
|
|
@@ -30293,7 +30293,7 @@ var init_math_grid_uniformity = __esm({
|
|
|
30293
30293
|
const { h, vocab, total } = shannonEntropy(counts);
|
|
30294
30294
|
if (total < 4) return issues;
|
|
30295
30295
|
if (h > 1) return issues;
|
|
30296
|
-
const anchor = facts.v2 ? flatClassNames(facts.v2)[0] : { line: 1, column: 1 };
|
|
30296
|
+
const anchor = facts.v2 ? flatClassNames(facts.v2)[0] ?? { line: 1, column: 1 } : { line: 1, column: 1 };
|
|
30297
30297
|
issues.push({
|
|
30298
30298
|
ruleId: "layout/math-grid-uniformity",
|
|
30299
30299
|
category: "layout",
|
|
@@ -34728,59 +34728,77 @@ __export(dist_exports, {
|
|
|
34728
34728
|
});
|
|
34729
34729
|
import { writeFileSync, renameSync, existsSync as existsSync8, readFileSync as readFileSync9, statSync as statSync4, mkdirSync } from "fs";
|
|
34730
34730
|
import { join as join9, dirname as dirname5 } from "path";
|
|
34731
|
+
function isRecord(v) {
|
|
34732
|
+
return typeof v === "object" && v !== null && !Array.isArray(v);
|
|
34733
|
+
}
|
|
34734
|
+
function isStringArray(v) {
|
|
34735
|
+
return Array.isArray(v) && v.every((i) => typeof i === "string");
|
|
34736
|
+
}
|
|
34737
|
+
function isNumber(v) {
|
|
34738
|
+
return typeof v === "number" && Number.isFinite(v);
|
|
34739
|
+
}
|
|
34731
34740
|
function isStructurePattern(value) {
|
|
34732
|
-
if (
|
|
34733
|
-
|
|
34734
|
-
return typeof v.category === "string" && typeof v.name === "string" && Array.isArray(v.imports) && v.imports.every((i) => typeof i === "string") && typeof v.fileCount === "number";
|
|
34741
|
+
if (!isRecord(value)) return false;
|
|
34742
|
+
return typeof value.category === "string" && typeof value.name === "string" && isStringArray(value.imports) && isNumber(value.fileCount);
|
|
34735
34743
|
}
|
|
34736
34744
|
function isComponentFingerprint(value) {
|
|
34737
|
-
if (
|
|
34738
|
-
|
|
34739
|
-
|
|
34745
|
+
if (!isRecord(value)) return false;
|
|
34746
|
+
return typeof value.name === "string" && isStringArray(value.files) && typeof value.fingerprint === "string" && isStringArray(value.hooks) && isStringArray(value.props) && isNumber(value.line) && isNumber(value.endLine);
|
|
34747
|
+
}
|
|
34748
|
+
function isVersion3(value) {
|
|
34749
|
+
return value === STRUCTURE_SCHEMA_VERSION;
|
|
34740
34750
|
}
|
|
34741
34751
|
function isInventoryFile(value) {
|
|
34742
|
-
if (
|
|
34743
|
-
|
|
34744
|
-
|
|
34752
|
+
if (!isRecord(value)) return false;
|
|
34753
|
+
if (!isVersion3(value.version)) return false;
|
|
34754
|
+
if (typeof value.generatedAt !== "string") return false;
|
|
34755
|
+
if (typeof value.workspace !== "string") return false;
|
|
34756
|
+
if (!isNumber(value.scannedFiles)) return false;
|
|
34757
|
+
if (!isNumber(value.scanDurationMs)) return false;
|
|
34758
|
+
if (!Array.isArray(value.patterns) || !value.patterns.every(isStructurePattern)) return false;
|
|
34759
|
+
if (!Array.isArray(value.components) || !value.components.every(isComponentFingerprint)) return false;
|
|
34760
|
+
return true;
|
|
34745
34761
|
}
|
|
34746
34762
|
function isConstitutionFile(value) {
|
|
34747
|
-
if (
|
|
34748
|
-
|
|
34749
|
-
|
|
34763
|
+
if (!isRecord(value)) return false;
|
|
34764
|
+
if (!isVersion3(value.version)) return false;
|
|
34765
|
+
if (typeof value.generatedAt !== "string") return false;
|
|
34766
|
+
if (typeof value.workspace !== "string") return false;
|
|
34767
|
+
if (!isRecord(value.declared)) return false;
|
|
34768
|
+
if (!isStringArray(value.forbidden)) return false;
|
|
34769
|
+
if (!isStringArray(value.forbiddenPrefixes)) return false;
|
|
34770
|
+
return true;
|
|
34750
34771
|
}
|
|
34751
34772
|
function isFileMtimeEntry(value) {
|
|
34752
|
-
if (
|
|
34753
|
-
|
|
34754
|
-
return typeof v.file === "string" && typeof v.mtimeMs === "number" && typeof v.hash === "string";
|
|
34773
|
+
if (!isRecord(value)) return false;
|
|
34774
|
+
return typeof value.file === "string" && isNumber(value.mtimeMs) && typeof value.hash === "string";
|
|
34755
34775
|
}
|
|
34756
34776
|
function isHealthFile(value) {
|
|
34757
|
-
if (
|
|
34758
|
-
|
|
34759
|
-
if (
|
|
34760
|
-
if (typeof
|
|
34761
|
-
if (
|
|
34762
|
-
if (
|
|
34763
|
-
if (
|
|
34764
|
-
if (
|
|
34765
|
-
if (
|
|
34766
|
-
|
|
34767
|
-
|
|
34768
|
-
if (
|
|
34769
|
-
if (
|
|
34770
|
-
if (
|
|
34771
|
-
if (
|
|
34772
|
-
|
|
34773
|
-
|
|
34774
|
-
|
|
34775
|
-
|
|
34776
|
-
|
|
34777
|
-
|
|
34778
|
-
if (
|
|
34779
|
-
|
|
34780
|
-
|
|
34781
|
-
|
|
34782
|
-
}
|
|
34783
|
-
if (v.scanDurationMs !== void 0 && typeof v.scanDurationMs !== "number") return false;
|
|
34777
|
+
if (!isRecord(value)) return false;
|
|
34778
|
+
if (!isVersion3(value.version)) return false;
|
|
34779
|
+
if (typeof value.generatedAt !== "string") return false;
|
|
34780
|
+
if (typeof value.workspace !== "string") return false;
|
|
34781
|
+
if (!isNumber(value.aiQuality)) return false;
|
|
34782
|
+
if (!isNumber(value.engineeringHygiene)) return false;
|
|
34783
|
+
if (!isNumber(value.security)) return false;
|
|
34784
|
+
if (!isNumber(value.repositoryHealth)) return false;
|
|
34785
|
+
if (!isRecord(value.issueCounts)) return false;
|
|
34786
|
+
const counts = value.issueCounts;
|
|
34787
|
+
if (!isNumber(counts.high)) return false;
|
|
34788
|
+
if (!isNumber(counts.medium)) return false;
|
|
34789
|
+
if (!isNumber(counts.low)) return false;
|
|
34790
|
+
if (value.slopIndex !== void 0 && !isNumber(value.slopIndex)) return false;
|
|
34791
|
+
if (value.categoryScores !== void 0) {
|
|
34792
|
+
if (!isRecord(value.categoryScores)) return false;
|
|
34793
|
+
for (const score of Object.values(value.categoryScores)) {
|
|
34794
|
+
if (!isNumber(score)) return false;
|
|
34795
|
+
}
|
|
34796
|
+
}
|
|
34797
|
+
if (value.constitutionDrift !== void 0 && !isNumber(value.constitutionDrift)) return false;
|
|
34798
|
+
if (value.topOffenseIds !== void 0) {
|
|
34799
|
+
if (!isStringArray(value.topOffenseIds)) return false;
|
|
34800
|
+
}
|
|
34801
|
+
if (value.scanDurationMs !== void 0 && !isNumber(value.scanDurationMs)) return false;
|
|
34784
34802
|
return true;
|
|
34785
34803
|
}
|
|
34786
34804
|
function inventoryPath(workspaceDir) {
|
|
@@ -34938,7 +34956,13 @@ var init_dist = __esm({
|
|
|
34938
34956
|
verdict: external_exports.enum(VERDICTS),
|
|
34939
34957
|
// defaultOff is opt-in per-rule. Absent = the rule follows
|
|
34940
34958
|
// isDefaultOff(verdict). Present (true or false) = user override.
|
|
34941
|
-
defaultOff: external_exports.boolean().optional()
|
|
34959
|
+
defaultOff: external_exports.boolean().optional(),
|
|
34960
|
+
// v0.17.3 (B5): mark rules whose signal is specific to AI
|
|
34961
|
+
// generation. Without this field, the composite scoring pipeline
|
|
34962
|
+
// can't distinguish "this rule fires on AI slop" from "this rule
|
|
34963
|
+
// fires on sloppy code in general" — and gives zero weight to
|
|
34964
|
+
// both. See packages/engine/src/composite-scoring.ts:136,164.
|
|
34965
|
+
aiSpecific: external_exports.boolean().optional()
|
|
34942
34966
|
})
|
|
34943
34967
|
);
|
|
34944
34968
|
}
|
|
@@ -35135,11 +35159,6 @@ function syntaxCandidates(filePath, source) {
|
|
|
35135
35159
|
{ syntax: "typescript", jsx: true },
|
|
35136
35160
|
{ syntax: "typescript", jsx: false, tsx: false }
|
|
35137
35161
|
];
|
|
35138
|
-
case "mjs":
|
|
35139
|
-
return [
|
|
35140
|
-
{ syntax: "ecmascript", jsx: true },
|
|
35141
|
-
{ syntax: "ecmascript", jsx: false }
|
|
35142
|
-
];
|
|
35143
35162
|
default:
|
|
35144
35163
|
return [
|
|
35145
35164
|
{ syntax: "typescript", jsx: false, tsx: true },
|
|
@@ -36796,6 +36815,7 @@ var init_dist2 = __esm({
|
|
|
36796
36815
|
"../engine/dist/index.js"() {
|
|
36797
36816
|
"use strict";
|
|
36798
36817
|
init_dist();
|
|
36818
|
+
init_dist();
|
|
36799
36819
|
SMOOTHING = 0.5;
|
|
36800
36820
|
DEFAULT_PRIOR = { pAI: 0.5, pHuman: 0.5 };
|
|
36801
36821
|
TELEMETRY_FILE = join22(".slopbrick", "structure.json");
|
|
@@ -36804,7 +36824,11 @@ var init_dist2 = __esm({
|
|
|
36804
36824
|
RECALL_FLOOR = 1e-6;
|
|
36805
36825
|
LLR_CAP = 13.8;
|
|
36806
36826
|
DEFAULT_PRIOR_PREVALENCE = 0.3;
|
|
36807
|
-
ELIGIBLE_VERDICTS =
|
|
36827
|
+
ELIGIBLE_VERDICTS = new Set(
|
|
36828
|
+
["USEFUL", "OK", "NOISY", "INVERTED", "HYGIENE", "DORMANT"].filter(
|
|
36829
|
+
(v) => v !== "HYGIENE" && !isDefaultOff(v)
|
|
36830
|
+
)
|
|
36831
|
+
);
|
|
36808
36832
|
SUFFIXES_TO_STRIP = [
|
|
36809
36833
|
"RepositoryClient",
|
|
36810
36834
|
"ServiceFactory",
|
|
@@ -37644,7 +37668,7 @@ var init_math_gini_class_usage = __esm({
|
|
|
37644
37668
|
if (g < 0.5) return issues;
|
|
37645
37669
|
const sorted = [...counts.entries()].sort((a, b) => b[1] - a[1]).slice(0, 3);
|
|
37646
37670
|
const topStr = sorted.map(([k, v]) => `${k}\xD7${v}`).join(", ");
|
|
37647
|
-
const anchor = facts.v2 ? flatClassNames(facts.v2)[0] : { line: 1, column: 1 };
|
|
37671
|
+
const anchor = facts.v2 ? flatClassNames(facts.v2)[0] ?? { line: 1, column: 1 } : { line: 1, column: 1 };
|
|
37648
37672
|
issues.push({
|
|
37649
37673
|
ruleId: "logic/math-gini-class-usage",
|
|
37650
37674
|
category: "logic",
|
|
@@ -40947,7 +40971,7 @@ var init_math_font_entropy = __esm({
|
|
|
40947
40971
|
const { h, vocab, total } = shannonEntropy(counts);
|
|
40948
40972
|
if (total < 6) return issues;
|
|
40949
40973
|
if (h > 1.4) return issues;
|
|
40950
|
-
const anchor = flatClassNames(facts.v2)[0];
|
|
40974
|
+
const anchor = flatClassNames(facts.v2)[0] ?? { line: 1, column: 1 };
|
|
40951
40975
|
issues.push({
|
|
40952
40976
|
ruleId: "visual/math-font-entropy",
|
|
40953
40977
|
category: "visual",
|
|
@@ -41087,7 +41111,7 @@ var init_math_rounded_entropy = __esm({
|
|
|
41087
41111
|
const { h, vocab, total } = shannonEntropy(counts);
|
|
41088
41112
|
if (total < 6) return issues;
|
|
41089
41113
|
if (h > 1.8) return issues;
|
|
41090
|
-
const anchor = flatClassNames(facts.v2)[0];
|
|
41114
|
+
const anchor = flatClassNames(facts.v2)[0] ?? { line: 1, column: 1 };
|
|
41091
41115
|
issues.push({
|
|
41092
41116
|
ruleId: "visual/math-rounded-entropy",
|
|
41093
41117
|
category: "visual",
|
|
@@ -41135,7 +41159,7 @@ var init_math_spacing_entropy = __esm({
|
|
|
41135
41159
|
const { h, vocab, total } = shannonEntropy(counts);
|
|
41136
41160
|
if (total < 10) return issues;
|
|
41137
41161
|
if (h > 1.5) return issues;
|
|
41138
|
-
const anchor = flatClassNames(facts.v2)[0];
|
|
41162
|
+
const anchor = flatClassNames(facts.v2)[0] ?? { line: 1, column: 1 };
|
|
41139
41163
|
issues.push({
|
|
41140
41164
|
ruleId: "visual/math-spacing-entropy",
|
|
41141
41165
|
category: "visual",
|
|
@@ -49858,6 +49882,13 @@ function mergeComponentsByName(components) {
|
|
|
49858
49882
|
}
|
|
49859
49883
|
byName.set(c.name, {
|
|
49860
49884
|
...c,
|
|
49885
|
+
// All visitors (rust.ts, php.ts, go.ts, …) push Components with
|
|
49886
|
+
// `files: [filePath]` — non-empty by construction. The JSON
|
|
49887
|
+
// Schema (inventory.schema.json) requires `files` to be
|
|
49888
|
+
// `[string, ...string[]]` (at least 1); the cast is safe under
|
|
49889
|
+
// the visitor invariant. If a future visitor ever produces an
|
|
49890
|
+
// empty files array, the runtime validator
|
|
49891
|
+
// (`isInventoryFile`) will reject the artifact at write time.
|
|
49861
49892
|
files: c.files.slice(),
|
|
49862
49893
|
hooks: c.hooks.slice(),
|
|
49863
49894
|
props: c.props.slice()
|
|
@@ -54971,7 +55002,7 @@ function promptMultiSelect(rl, question, options, defaultValue) {
|
|
|
54971
55002
|
resolve18([]);
|
|
54972
55003
|
return;
|
|
54973
55004
|
}
|
|
54974
|
-
const selected = [...new Set(numbers.map((n) => options[n - 2]))];
|
|
55005
|
+
const selected = [...new Set(numbers.map((n) => options[n - 2]).filter((v) => v !== void 0))];
|
|
54975
55006
|
resolve18(selected);
|
|
54976
55007
|
});
|
|
54977
55008
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "slopbrick",
|
|
3
|
-
"version": "0.17.
|
|
3
|
+
"version": "0.17.4",
|
|
4
4
|
"description": "Discovered, modeled, and governed repository structure. SlopBrick scans source code, classifies it against 95 rules in 15 categories, computes 4 scores (aiQuality, engineeringHygiene, security, repositoryHealth), and persists the structure for AI agents and CI.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"bin": {
|