slopbrick 0.18.2 → 0.18.3
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 +24 -14
- package/dist/engine/worker.js +24 -14
- package/dist/index.cjs +241 -231
- package/dist/index.js +104 -94
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -35275,10 +35275,10 @@ function parseSvelte(source) {
|
|
|
35275
35275
|
const ast = parseScriptContent(script.content, isTypeScriptScript(script.openTag));
|
|
35276
35276
|
return { ast, source };
|
|
35277
35277
|
}
|
|
35278
|
-
function
|
|
35278
|
+
function legacyCacheEnabled() {
|
|
35279
35279
|
return process.env.SLOP_AUDIT_CACHE === "1" || process.env.SLOP_AUDIT_CACHE === "true";
|
|
35280
35280
|
}
|
|
35281
|
-
function
|
|
35281
|
+
function legacyCacheRoot() {
|
|
35282
35282
|
const override = process.env.SLOP_AUDIT_CACHE_ROOT;
|
|
35283
35283
|
if (override) return override;
|
|
35284
35284
|
return join10(process.cwd(), ".slopbrick", "cache", "ast");
|
|
@@ -35286,11 +35286,11 @@ function cacheRoot() {
|
|
|
35286
35286
|
function hashContent(content) {
|
|
35287
35287
|
return createHash("md5").update(content, "utf-8").digest("hex");
|
|
35288
35288
|
}
|
|
35289
|
-
function
|
|
35290
|
-
return join10(
|
|
35289
|
+
function cachePathWithRoot(content, root) {
|
|
35290
|
+
return join10(root, `${hashContent(content)}.json`);
|
|
35291
35291
|
}
|
|
35292
|
-
async function
|
|
35293
|
-
const path =
|
|
35292
|
+
async function readCacheWithRoot(filePath, content, root) {
|
|
35293
|
+
const path = cachePathWithRoot(content, root);
|
|
35294
35294
|
try {
|
|
35295
35295
|
await access(path);
|
|
35296
35296
|
const raw = await readFile(path, "utf8");
|
|
@@ -35303,8 +35303,8 @@ async function readCache2(filePath, content) {
|
|
|
35303
35303
|
}
|
|
35304
35304
|
return void 0;
|
|
35305
35305
|
}
|
|
35306
|
-
async function
|
|
35307
|
-
const path =
|
|
35306
|
+
async function writeCacheWithRoot(content, result, root) {
|
|
35307
|
+
const path = cachePathWithRoot(content, root);
|
|
35308
35308
|
await mkdir(dirname6(path), { recursive: true });
|
|
35309
35309
|
await writeFile(path, JSON.stringify(result), "utf8");
|
|
35310
35310
|
}
|
|
@@ -35335,15 +35335,17 @@ function parseSource(source, filePath) {
|
|
|
35335
35335
|
return parseWithSwc(source, filePath);
|
|
35336
35336
|
}
|
|
35337
35337
|
}
|
|
35338
|
-
async function parseFile(filePath) {
|
|
35338
|
+
async function parseFile(filePath, opts) {
|
|
35339
35339
|
const source = await readFile(filePath, "utf-8");
|
|
35340
|
-
|
|
35341
|
-
|
|
35340
|
+
const useCache = opts?.cache?.enabled ?? legacyCacheEnabled();
|
|
35341
|
+
const cacheDir = opts?.cache?.root ?? legacyCacheRoot();
|
|
35342
|
+
if (useCache) {
|
|
35343
|
+
const cached = await readCacheWithRoot(filePath, source, cacheDir);
|
|
35342
35344
|
if (cached) return cached;
|
|
35343
35345
|
}
|
|
35344
35346
|
const result = parseSource(source, filePath);
|
|
35345
|
-
if (
|
|
35346
|
-
await
|
|
35347
|
+
if (useCache) {
|
|
35348
|
+
await writeCacheWithRoot(source, result, cacheDir);
|
|
35347
35349
|
}
|
|
35348
35350
|
return result;
|
|
35349
35351
|
}
|
|
@@ -45773,8 +45775,8 @@ var init_git = __esm({
|
|
|
45773
45775
|
import { createHash as createHash5 } from "crypto";
|
|
45774
45776
|
import { existsSync as existsSync12, readFileSync as readFileSync13, writeFileSync as writeFileSync3, renameSync as renameSync2, mkdirSync as mkdirSync2, unlinkSync } from "fs";
|
|
45775
45777
|
import { dirname as dirname8, isAbsolute, resolve as resolve8 } from "path";
|
|
45776
|
-
function loadCache(
|
|
45777
|
-
const abs = isAbsolute(
|
|
45778
|
+
function loadCache(cachePath3) {
|
|
45779
|
+
const abs = isAbsolute(cachePath3) ? cachePath3 : resolve8(process.cwd(), cachePath3);
|
|
45778
45780
|
if (!existsSync12(abs)) return void 0;
|
|
45779
45781
|
try {
|
|
45780
45782
|
const raw = readFileSync13(abs, "utf-8");
|
|
@@ -45785,8 +45787,8 @@ function loadCache(cachePath4) {
|
|
|
45785
45787
|
return void 0;
|
|
45786
45788
|
}
|
|
45787
45789
|
}
|
|
45788
|
-
function saveCache(
|
|
45789
|
-
const abs = isAbsolute(
|
|
45790
|
+
function saveCache(cachePath3, cache) {
|
|
45791
|
+
const abs = isAbsolute(cachePath3) ? cachePath3 : resolve8(process.cwd(), cachePath3);
|
|
45790
45792
|
mkdirSync2(dirname8(abs), { recursive: true });
|
|
45791
45793
|
const tmp = abs + ".tmp";
|
|
45792
45794
|
if (existsSync12(tmp)) {
|
|
@@ -47128,6 +47130,13 @@ var init_signal_strength2 = __esm({
|
|
|
47128
47130
|
// src/engine/worker.ts
|
|
47129
47131
|
import { isMainThread, parentPort, workerData } from "worker_threads";
|
|
47130
47132
|
import { extname as extname6 } from "path";
|
|
47133
|
+
import { join as join13 } from "path";
|
|
47134
|
+
function buildParserCacheConfig(cwd) {
|
|
47135
|
+
const envVal = process.env.SLOP_AUDIT_CACHE;
|
|
47136
|
+
const enabled = envVal === "1" || envVal === "true";
|
|
47137
|
+
const root = process.env.SLOP_AUDIT_CACHE_ROOT ?? join13(cwd, ".slopbrick", "cache", "ast");
|
|
47138
|
+
return { enabled, root };
|
|
47139
|
+
}
|
|
47131
47140
|
function applyRuleOverrides(issues, rules) {
|
|
47132
47141
|
const result = [];
|
|
47133
47142
|
for (const issue of issues) {
|
|
@@ -47142,6 +47151,7 @@ function applyRuleOverrides(issues, rules) {
|
|
|
47142
47151
|
return result;
|
|
47143
47152
|
}
|
|
47144
47153
|
async function scanFile(filePath, config, registry, cwd = process.cwd()) {
|
|
47154
|
+
const cache = buildParserCacheConfig(cwd);
|
|
47145
47155
|
const ext = extname6(filePath).toLowerCase();
|
|
47146
47156
|
const UNSUPPORTED_LANGS = /* @__PURE__ */ new Set([
|
|
47147
47157
|
".swift",
|
|
@@ -47172,7 +47182,7 @@ async function scanFile(filePath, config, registry, cwd = process.cwd()) {
|
|
|
47172
47182
|
};
|
|
47173
47183
|
}
|
|
47174
47184
|
try {
|
|
47175
|
-
const { ast, source } = await parseFile(filePath);
|
|
47185
|
+
const { ast, source } = await parseFile(filePath, { cache });
|
|
47176
47186
|
const facts = extractFacts(filePath, ast, source, config.supportsRsc ?? true, config.framework ?? "react", config);
|
|
47177
47187
|
const activeRegistry = registry ?? new RuleRegistry();
|
|
47178
47188
|
if (!registry) {
|
|
@@ -47281,7 +47291,7 @@ var init_worker = __esm({
|
|
|
47281
47291
|
// src/engine/flywheel.ts
|
|
47282
47292
|
import { createHash as createHash6 } from "crypto";
|
|
47283
47293
|
import { existsSync as existsSync14, mkdirSync as mkdirSync3, readFileSync as readFileSync14, writeFileSync as writeFileSync4 } from "fs";
|
|
47284
|
-
import { join as
|
|
47294
|
+
import { join as join14 } from "path";
|
|
47285
47295
|
function severityBump(severity) {
|
|
47286
47296
|
const order = ["low", "medium", "high"];
|
|
47287
47297
|
const idx = order.indexOf(severity);
|
|
@@ -47382,7 +47392,7 @@ function migrateFlywheelState(state) {
|
|
|
47382
47392
|
};
|
|
47383
47393
|
}
|
|
47384
47394
|
function loadFlywheelState(cwd) {
|
|
47385
|
-
const path =
|
|
47395
|
+
const path = join14(cwd, FLYWHEEL_DIR, STATE_FILE);
|
|
47386
47396
|
if (!existsSync14(path)) {
|
|
47387
47397
|
return migrateFlywheelState({});
|
|
47388
47398
|
}
|
|
@@ -47394,9 +47404,9 @@ function loadFlywheelState(cwd) {
|
|
|
47394
47404
|
}
|
|
47395
47405
|
}
|
|
47396
47406
|
function loadResearchMetricsFromDisk(cwd) {
|
|
47397
|
-
const flywheelDir =
|
|
47398
|
-
const analysisPath =
|
|
47399
|
-
const candidatesPath =
|
|
47407
|
+
const flywheelDir = join14(cwd, FLYWHEEL_DIR);
|
|
47408
|
+
const analysisPath = join14(flywheelDir, "analysis.json");
|
|
47409
|
+
const candidatesPath = join14(flywheelDir, "rule-candidates.json");
|
|
47400
47410
|
const hasAnalysis = existsSync14(analysisPath);
|
|
47401
47411
|
const hasCandidates = existsSync14(candidatesPath);
|
|
47402
47412
|
if (!hasAnalysis && !hasCandidates) return void 0;
|
|
@@ -47426,9 +47436,9 @@ function loadResearchMetricsFromDisk(cwd) {
|
|
|
47426
47436
|
};
|
|
47427
47437
|
}
|
|
47428
47438
|
function saveFlywheelState(cwd, state) {
|
|
47429
|
-
const dir =
|
|
47439
|
+
const dir = join14(cwd, FLYWHEEL_DIR);
|
|
47430
47440
|
if (!existsSync14(dir)) mkdirSync3(dir, { recursive: true });
|
|
47431
|
-
writeFileSync4(
|
|
47441
|
+
writeFileSync4(join14(dir, STATE_FILE), JSON.stringify(state, null, 2));
|
|
47432
47442
|
}
|
|
47433
47443
|
function hashFile(filePath) {
|
|
47434
47444
|
return createHash6("sha256").update(filePath).digest("hex").slice(0, 16);
|
|
@@ -47784,7 +47794,7 @@ var init_metrics = __esm({
|
|
|
47784
47794
|
// src/engine/cache.ts
|
|
47785
47795
|
import { createHash as createHash7 } from "crypto";
|
|
47786
47796
|
import { existsSync as existsSync15, mkdirSync as mkdirSync4, readFileSync as readFileSync15, writeFileSync as writeFileSync5 } from "fs";
|
|
47787
|
-
import { join as
|
|
47797
|
+
import { join as join15 } from "path";
|
|
47788
47798
|
function parseVersion(version) {
|
|
47789
47799
|
const parts = version.split(".").map((part) => parseInt(part, 10));
|
|
47790
47800
|
return [parts[0] ?? 0, parts[1] ?? 0, parts[2] ?? 0];
|
|
@@ -47859,7 +47869,7 @@ function hashConfig(config) {
|
|
|
47859
47869
|
return createHash7("sha256").update(JSON.stringify(sanitizeForHash(pickBaselineConfig(config)))).digest("hex");
|
|
47860
47870
|
}
|
|
47861
47871
|
function baselinePath(projectPath) {
|
|
47862
|
-
return
|
|
47872
|
+
return join15(projectPath, ".slopbrick", "cache", "baseline.json");
|
|
47863
47873
|
}
|
|
47864
47874
|
function isBaselineCache(value) {
|
|
47865
47875
|
if (!value || typeof value !== "object") return false;
|
|
@@ -47902,7 +47912,7 @@ function loadBaseline(projectPath) {
|
|
|
47902
47912
|
}
|
|
47903
47913
|
function saveBaseline(projectPath, cache) {
|
|
47904
47914
|
const path = baselinePath(projectPath);
|
|
47905
|
-
mkdirSync4(
|
|
47915
|
+
mkdirSync4(join15(projectPath, ".slopbrick", "cache"), { recursive: true });
|
|
47906
47916
|
writeFileSync5(path, JSON.stringify(cache, null, 2));
|
|
47907
47917
|
}
|
|
47908
47918
|
function tightenBaseline(cache) {
|
|
@@ -49816,9 +49826,9 @@ import {
|
|
|
49816
49826
|
statSync as statSync6
|
|
49817
49827
|
} from "fs";
|
|
49818
49828
|
import { createHash as createHash8 } from "crypto";
|
|
49819
|
-
import { dirname as dirname11, join as
|
|
49829
|
+
import { dirname as dirname11, join as join17, relative as relative8 } from "path";
|
|
49820
49830
|
function telemetryPath2(cwd) {
|
|
49821
|
-
return
|
|
49831
|
+
return join17(cwd, TELEMETRY_DIR, TELEMETRY_FILE2);
|
|
49822
49832
|
}
|
|
49823
49833
|
function hashString(input) {
|
|
49824
49834
|
return createHash8("sha256").update(input).digest("hex").slice(0, 16);
|
|
@@ -49880,21 +49890,21 @@ function rotateTelemetry(cwd) {
|
|
|
49880
49890
|
}
|
|
49881
49891
|
const dir = dirname11(path);
|
|
49882
49892
|
const timestamp = (/* @__PURE__ */ new Date()).toISOString().replace(/[:.]/g, "-");
|
|
49883
|
-
renameSync3(path,
|
|
49884
|
-
const rotated = readdirSync6(dir).filter(isTelemetryFile).map((name) => ({ name, mtime: statSync6(
|
|
49893
|
+
renameSync3(path, join17(dir, `scans-${timestamp}.jsonl`));
|
|
49894
|
+
const rotated = readdirSync6(dir).filter(isTelemetryFile).map((name) => ({ name, mtime: statSync6(join17(dir, name)).mtimeMs })).sort((a, b) => a.mtime - b.mtime);
|
|
49885
49895
|
while (rotated.length > MAX_ROTATED_FILES) {
|
|
49886
49896
|
const oldest = rotated.shift();
|
|
49887
49897
|
if (oldest) {
|
|
49888
|
-
rmSync(
|
|
49898
|
+
rmSync(join17(dir, oldest.name), { force: true });
|
|
49889
49899
|
}
|
|
49890
49900
|
}
|
|
49891
49901
|
}
|
|
49892
49902
|
function readTelemetry(cwd) {
|
|
49893
|
-
const dir =
|
|
49903
|
+
const dir = join17(cwd, TELEMETRY_DIR);
|
|
49894
49904
|
if (!existsSync16(dir)) {
|
|
49895
49905
|
return [];
|
|
49896
49906
|
}
|
|
49897
|
-
const files = readdirSync6(dir).filter(isTelemetryFile).sort().map((name) =>
|
|
49907
|
+
const files = readdirSync6(dir).filter(isTelemetryFile).sort().map((name) => join17(dir, name));
|
|
49898
49908
|
const payloads = [];
|
|
49899
49909
|
for (const file of files) {
|
|
49900
49910
|
const raw = readFileSync19(file, "utf-8");
|
|
@@ -49945,7 +49955,7 @@ var TELEMETRY_DIR, TELEMETRY_FILE2, MAX_TELEMETRY_BYTES, MAX_ROTATED_FILES;
|
|
|
49945
49955
|
var init_telemetry = __esm({
|
|
49946
49956
|
"src/engine/telemetry.ts"() {
|
|
49947
49957
|
"use strict";
|
|
49948
|
-
TELEMETRY_DIR =
|
|
49958
|
+
TELEMETRY_DIR = join17(".slopbrick", "flywheel");
|
|
49949
49959
|
TELEMETRY_FILE2 = "scans.jsonl";
|
|
49950
49960
|
MAX_TELEMETRY_BYTES = 10 * 1024 * 1024;
|
|
49951
49961
|
MAX_ROTATED_FILES = 5;
|
|
@@ -49960,7 +49970,7 @@ __export(structure_md_exports, {
|
|
|
49960
49970
|
writeStructureMarkdown: () => writeStructureMarkdown
|
|
49961
49971
|
});
|
|
49962
49972
|
import { existsSync as existsSync17, mkdirSync as mkdirSync6, readFileSync as readFileSync20, writeFileSync as writeFileSync6 } from "fs";
|
|
49963
|
-
import { dirname as dirname12, join as
|
|
49973
|
+
import { dirname as dirname12, join as join18 } from "path";
|
|
49964
49974
|
function formatDuration(ms) {
|
|
49965
49975
|
if (!Number.isFinite(ms) || ms < 0) return "unknown";
|
|
49966
49976
|
if (ms < 1e3) return `${Math.round(ms)}ms`;
|
|
@@ -50103,7 +50113,7 @@ function renderStructureMarkdown(inventory, constitution) {
|
|
|
50103
50113
|
async function writeStructureMarkdown(workspaceDir, md) {
|
|
50104
50114
|
await new Promise((resolve42, reject) => {
|
|
50105
50115
|
try {
|
|
50106
|
-
const path =
|
|
50116
|
+
const path = join18(workspaceDir, STRUCTURE_MD_FILE);
|
|
50107
50117
|
mkdirSync6(dirname12(path), { recursive: true });
|
|
50108
50118
|
writeFileSync6(path, md, "utf-8");
|
|
50109
50119
|
resolve42();
|
|
@@ -50115,7 +50125,7 @@ async function writeStructureMarkdown(workspaceDir, md) {
|
|
|
50115
50125
|
async function readStructureMarkdown(workspaceDir) {
|
|
50116
50126
|
return new Promise((resolve42) => {
|
|
50117
50127
|
try {
|
|
50118
|
-
const path =
|
|
50128
|
+
const path = join18(workspaceDir, STRUCTURE_MD_FILE);
|
|
50119
50129
|
if (!existsSync17(path)) {
|
|
50120
50130
|
resolve42(null);
|
|
50121
50131
|
return;
|
|
@@ -50131,7 +50141,7 @@ var STRUCTURE_MD_FILE, CATEGORY_LABELS, CATEGORY_ORDER, DECLARED_FIELDS;
|
|
|
50131
50141
|
var init_structure_md = __esm({
|
|
50132
50142
|
"src/engine/structure-md.ts"() {
|
|
50133
50143
|
"use strict";
|
|
50134
|
-
STRUCTURE_MD_FILE =
|
|
50144
|
+
STRUCTURE_MD_FILE = join18(".slopbrick", "structure.md");
|
|
50135
50145
|
CATEGORY_LABELS = {
|
|
50136
50146
|
stateManagement: "State management",
|
|
50137
50147
|
dataFetching: "Data fetching",
|
|
@@ -50173,7 +50183,7 @@ var init_structure_md = __esm({
|
|
|
50173
50183
|
|
|
50174
50184
|
// src/cli/report/persistRun.ts
|
|
50175
50185
|
import { existsSync as existsSync18, writeFileSync as writeFileSync7, mkdirSync as mkdirSync7 } from "fs";
|
|
50176
|
-
import { join as
|
|
50186
|
+
import { join as join19, relative as relative9 } from "path";
|
|
50177
50187
|
async function persistRun(input) {
|
|
50178
50188
|
const {
|
|
50179
50189
|
cwd,
|
|
@@ -50207,8 +50217,8 @@ async function persistRun(input) {
|
|
|
50207
50217
|
);
|
|
50208
50218
|
}
|
|
50209
50219
|
if (options.incremental) {
|
|
50210
|
-
const
|
|
50211
|
-
const existing = loadCache(
|
|
50220
|
+
const cachePath3 = options.cachePath ?? ".slopbrick-cache.json";
|
|
50221
|
+
const existing = loadCache(cachePath3) ?? emptyCache();
|
|
50212
50222
|
const next = { ...existing, generatedAt: (/* @__PURE__ */ new Date()).toISOString() };
|
|
50213
50223
|
for (const result of results) {
|
|
50214
50224
|
try {
|
|
@@ -50222,7 +50232,7 @@ async function persistRun(input) {
|
|
|
50222
50232
|
} catch {
|
|
50223
50233
|
}
|
|
50224
50234
|
}
|
|
50225
|
-
saveCache(
|
|
50235
|
+
saveCache(cachePath3, next);
|
|
50226
50236
|
if (incrementalSummary && !options.quiet) {
|
|
50227
50237
|
logger.info(
|
|
50228
50238
|
`Incremental: re-scanned ${incrementalSummary.rescanned}, skipped ${incrementalSummary.skipped} (unchanged).`
|
|
@@ -50254,10 +50264,10 @@ async function persistRun(input) {
|
|
|
50254
50264
|
report.research = state.research;
|
|
50255
50265
|
}
|
|
50256
50266
|
if (flywheelOutput.suggestions.length > 0) {
|
|
50257
|
-
const suggestionsDir =
|
|
50267
|
+
const suggestionsDir = join19(cwd, ".slopbrick", "flywheel");
|
|
50258
50268
|
if (!existsSync18(suggestionsDir)) mkdirSync7(suggestionsDir, { recursive: true });
|
|
50259
50269
|
writeFileSync7(
|
|
50260
|
-
|
|
50270
|
+
join19(suggestionsDir, "rule-suggestions.json"),
|
|
50261
50271
|
JSON.stringify(flywheelOutput.suggestions, null, 2)
|
|
50262
50272
|
);
|
|
50263
50273
|
}
|
|
@@ -52467,8 +52477,8 @@ async function runScan(options, explicitPaths) {
|
|
|
52467
52477
|
}
|
|
52468
52478
|
let incrementalSummary;
|
|
52469
52479
|
if (options.incremental) {
|
|
52470
|
-
const
|
|
52471
|
-
const existing = loadCache(
|
|
52480
|
+
const cachePath3 = options.cachePath ?? ".slopbrick-cache.json";
|
|
52481
|
+
const existing = loadCache(cachePath3);
|
|
52472
52482
|
const { toScan, unchanged } = partitionByCache(files, existing);
|
|
52473
52483
|
files = toScan;
|
|
52474
52484
|
incrementalSummary = { skipped: unchanged.length, rescanned: toScan.length };
|
|
@@ -53273,12 +53283,12 @@ init_git();
|
|
|
53273
53283
|
init_cache();
|
|
53274
53284
|
init_logger();
|
|
53275
53285
|
import { writeFileSync as writeFileSync11, mkdirSync as mkdirSync9, rmSync as rmSync2 } from "fs";
|
|
53276
|
-
import { join as
|
|
53286
|
+
import { join as join21, dirname as dirname14 } from "path";
|
|
53277
53287
|
import { createInterface } from "readline";
|
|
53278
53288
|
|
|
53279
53289
|
// src/rules/registry-loader.ts
|
|
53280
53290
|
import { existsSync as existsSync21, mkdirSync as mkdirSync8, readFileSync as readFileSync24, writeFileSync as writeFileSync10 } from "fs";
|
|
53281
|
-
import { dirname as dirname13, join as
|
|
53291
|
+
import { dirname as dirname13, join as join20 } from "path";
|
|
53282
53292
|
|
|
53283
53293
|
// src/data/shadcn-registry.json
|
|
53284
53294
|
var shadcn_registry_default = {
|
|
@@ -53411,11 +53421,11 @@ var shadcn_registry_default = {
|
|
|
53411
53421
|
// src/rules/registry-loader.ts
|
|
53412
53422
|
var REGISTRY_URL = "https://ui.shadcn.com/registry.json";
|
|
53413
53423
|
var BUNDLED_REGISTRY_VERSION = shadcn_registry_default.version;
|
|
53414
|
-
function
|
|
53415
|
-
return
|
|
53424
|
+
function cachePath2(cwd) {
|
|
53425
|
+
return join20(cwd, ".slopbrick", "cache", "registry-snapshot.json");
|
|
53416
53426
|
}
|
|
53417
53427
|
function ensureCacheDir(cwd) {
|
|
53418
|
-
const dir = dirname13(
|
|
53428
|
+
const dir = dirname13(cachePath2(cwd));
|
|
53419
53429
|
if (!existsSync21(dir)) {
|
|
53420
53430
|
mkdirSync8(dir, { recursive: true });
|
|
53421
53431
|
}
|
|
@@ -53428,7 +53438,7 @@ function isValidSnapshot(value) {
|
|
|
53428
53438
|
return true;
|
|
53429
53439
|
}
|
|
53430
53440
|
function isRegistryFresh(cwd) {
|
|
53431
|
-
const cached =
|
|
53441
|
+
const cached = cachePath2(cwd);
|
|
53432
53442
|
if (!existsSync21(cached)) return false;
|
|
53433
53443
|
try {
|
|
53434
53444
|
const parsed = JSON.parse(readFileSync24(cached, "utf8"));
|
|
@@ -53465,7 +53475,7 @@ async function refreshRegistrySnapshot(cwd, url = REGISTRY_URL, timeoutMs = 5e3)
|
|
|
53465
53475
|
};
|
|
53466
53476
|
}
|
|
53467
53477
|
ensureCacheDir(cwd);
|
|
53468
|
-
writeFileSync10(
|
|
53478
|
+
writeFileSync10(cachePath2(cwd), JSON.stringify(fetched, null, 2));
|
|
53469
53479
|
const fresh = fetched.version === BUNDLED_REGISTRY_VERSION;
|
|
53470
53480
|
return {
|
|
53471
53481
|
ok: true,
|
|
@@ -53475,7 +53485,7 @@ async function refreshRegistrySnapshot(cwd, url = REGISTRY_URL, timeoutMs = 5e3)
|
|
|
53475
53485
|
}
|
|
53476
53486
|
function copyBundledSnapshotToCache(cwd) {
|
|
53477
53487
|
ensureCacheDir(cwd);
|
|
53478
|
-
writeFileSync10(
|
|
53488
|
+
writeFileSync10(cachePath2(cwd), JSON.stringify(shadcn_registry_default, null, 2));
|
|
53479
53489
|
}
|
|
53480
53490
|
|
|
53481
53491
|
// src/cli/init.ts
|
|
@@ -53664,7 +53674,7 @@ async function runDoctor(cwd) {
|
|
|
53664
53674
|
}
|
|
53665
53675
|
try {
|
|
53666
53676
|
const { parseFile: tryParse } = await Promise.resolve().then(() => (init_dist2(), dist_exports2));
|
|
53667
|
-
const testFile =
|
|
53677
|
+
const testFile = join21(cwd, ".slopbrick", ".doctor-test.ts");
|
|
53668
53678
|
mkdirSync9(dirname14(testFile), { recursive: true });
|
|
53669
53679
|
writeFileSync11(testFile, "export const x = 1;\n");
|
|
53670
53680
|
await tryParse(testFile);
|
|
@@ -53997,7 +54007,7 @@ import {
|
|
|
53997
54007
|
readFileSync as readFileSync26,
|
|
53998
54008
|
writeFileSync as writeFileSync12
|
|
53999
54009
|
} from "fs";
|
|
54000
|
-
import { dirname as dirname15, join as
|
|
54010
|
+
import { dirname as dirname15, join as join23 } from "path";
|
|
54001
54011
|
var BEGIN_SENTINEL = "# slopbrick-hook-begin";
|
|
54002
54012
|
var END_SENTINEL = "# slopbrick-hook-end";
|
|
54003
54013
|
var SENTINEL_BLOCK = `${BEGIN_SENTINEL}
|
|
@@ -54005,11 +54015,11 @@ npx slopbrick --staged
|
|
|
54005
54015
|
${END_SENTINEL}
|
|
54006
54016
|
`;
|
|
54007
54017
|
function hookPath(gitRoot) {
|
|
54008
|
-
const huskyDir =
|
|
54018
|
+
const huskyDir = join23(gitRoot, ".husky");
|
|
54009
54019
|
if (existsSync23(huskyDir)) {
|
|
54010
|
-
return
|
|
54020
|
+
return join23(huskyDir, "pre-commit");
|
|
54011
54021
|
}
|
|
54012
|
-
return
|
|
54022
|
+
return join23(gitRoot, ".git", "hooks", "pre-commit");
|
|
54013
54023
|
}
|
|
54014
54024
|
function readHookContent(path) {
|
|
54015
54025
|
return readFileSync26(path, "utf8");
|
|
@@ -54427,41 +54437,41 @@ import { resolve as resolve22 } from "path";
|
|
|
54427
54437
|
// src/cli/migrate.ts
|
|
54428
54438
|
init_logger();
|
|
54429
54439
|
import { existsSync as existsSync24, readFileSync as readFileSync28, renameSync as renameSync4, writeFileSync as writeFileSync13 } from "fs";
|
|
54430
|
-
import { join as
|
|
54440
|
+
import { join as join24 } from "path";
|
|
54431
54441
|
function planMigration(workspaceDir) {
|
|
54432
54442
|
const moves = [];
|
|
54433
54443
|
const rewrites = [];
|
|
54434
54444
|
const gitignoreEdits = [];
|
|
54435
|
-
const oldDir =
|
|
54436
|
-
const newDir =
|
|
54445
|
+
const oldDir = join24(workspaceDir, ".slop-audit");
|
|
54446
|
+
const newDir = join24(workspaceDir, ".slopbrick");
|
|
54437
54447
|
if (existsSync24(oldDir)) {
|
|
54438
54448
|
moves.push({ from: oldDir, to: newDir, kind: "dir" });
|
|
54439
54449
|
rewrites.push({
|
|
54440
|
-
path:
|
|
54450
|
+
path: join24(newDir, "inventory.json"),
|
|
54441
54451
|
field: "version",
|
|
54442
54452
|
from: '"1"',
|
|
54443
54453
|
to: '"2"'
|
|
54444
54454
|
});
|
|
54445
54455
|
rewrites.push({
|
|
54446
|
-
path:
|
|
54456
|
+
path: join24(newDir, "constitution.json"),
|
|
54447
54457
|
field: "version",
|
|
54448
54458
|
from: '"1"',
|
|
54449
54459
|
to: '"2"'
|
|
54450
54460
|
});
|
|
54451
54461
|
}
|
|
54452
|
-
const oldCache =
|
|
54453
|
-
const newCache =
|
|
54462
|
+
const oldCache = join24(workspaceDir, ".slop-audit-cache.json");
|
|
54463
|
+
const newCache = join24(workspaceDir, ".slopbrick-cache.json");
|
|
54454
54464
|
if (existsSync24(oldCache)) {
|
|
54455
54465
|
moves.push({ from: oldCache, to: newCache, kind: "file" });
|
|
54456
54466
|
}
|
|
54457
54467
|
for (const ext of ["mjs", "cjs", "js"]) {
|
|
54458
|
-
const oldCfg =
|
|
54459
|
-
const newCfg =
|
|
54468
|
+
const oldCfg = join24(workspaceDir, `slop-audit.config.${ext}`);
|
|
54469
|
+
const newCfg = join24(workspaceDir, `slopbrick.config.${ext}`);
|
|
54460
54470
|
if (existsSync24(oldCfg)) {
|
|
54461
54471
|
moves.push({ from: oldCfg, to: newCfg, kind: "config" });
|
|
54462
54472
|
}
|
|
54463
54473
|
}
|
|
54464
|
-
const gi =
|
|
54474
|
+
const gi = join24(workspaceDir, ".gitignore");
|
|
54465
54475
|
if (existsSync24(gi)) {
|
|
54466
54476
|
const content = readFileSync28(gi, "utf-8");
|
|
54467
54477
|
if (content.includes(".slop-audit/")) {
|
|
@@ -54482,7 +54492,7 @@ function planMigration(workspaceDir) {
|
|
|
54482
54492
|
return { moves, rewrites, gitignoreEdits };
|
|
54483
54493
|
}
|
|
54484
54494
|
function isAlreadyMigrated(workspaceDir) {
|
|
54485
|
-
return existsSync24(
|
|
54495
|
+
return existsSync24(join24(workspaceDir, ".slopbrick")) && !existsSync24(join24(workspaceDir, ".slop-audit"));
|
|
54486
54496
|
}
|
|
54487
54497
|
function applyMigration(plan, options = {}) {
|
|
54488
54498
|
if (options.dryRun) return;
|
|
@@ -54513,8 +54523,8 @@ function runMigrate(options) {
|
|
|
54513
54523
|
};
|
|
54514
54524
|
}
|
|
54515
54525
|
const alreadyMigrated = isAlreadyMigrated(workspace);
|
|
54516
|
-
const newDir =
|
|
54517
|
-
const oldDir =
|
|
54526
|
+
const newDir = join24(workspace, ".slopbrick");
|
|
54527
|
+
const oldDir = join24(workspace, ".slop-audit");
|
|
54518
54528
|
if (existsSync24(newDir) && existsSync24(oldDir) && !force) {
|
|
54519
54529
|
return {
|
|
54520
54530
|
ok: false,
|
|
@@ -54985,7 +54995,7 @@ function createProvider(config) {
|
|
|
54985
54995
|
|
|
54986
54996
|
// src/research/generator.ts
|
|
54987
54997
|
import { mkdirSync as mkdirSync11, writeFileSync as writeFileSync14 } from "fs";
|
|
54988
|
-
import { join as
|
|
54998
|
+
import { join as join25 } from "path";
|
|
54989
54999
|
|
|
54990
55000
|
// src/research/prompts.ts
|
|
54991
55001
|
var DEFAULT_PROMPT_TEMPLATES = [
|
|
@@ -55048,13 +55058,13 @@ async function generateSamples(options) {
|
|
|
55048
55058
|
}
|
|
55049
55059
|
const samples = [];
|
|
55050
55060
|
const ext = extForFramework(framework);
|
|
55051
|
-
const dir =
|
|
55061
|
+
const dir = join25(outputDir, framework, componentType);
|
|
55052
55062
|
mkdirSync11(dir, { recursive: true });
|
|
55053
55063
|
for (let i = 1; i <= count; i += 1) {
|
|
55054
55064
|
const raw = await provider.generateSample(renderPrompt(template), { temperature });
|
|
55055
55065
|
const code = extractCodeFromMarkdown(raw);
|
|
55056
55066
|
const fileName = `sample-${i}${ext}`;
|
|
55057
|
-
const filePath =
|
|
55067
|
+
const filePath = join25(dir, fileName);
|
|
55058
55068
|
writeFileSync14(filePath, code, "utf8");
|
|
55059
55069
|
const sample = {
|
|
55060
55070
|
filePath,
|
|
@@ -55066,7 +55076,7 @@ async function generateSamples(options) {
|
|
|
55066
55076
|
};
|
|
55067
55077
|
samples.push(sample);
|
|
55068
55078
|
}
|
|
55069
|
-
const metadataPath =
|
|
55079
|
+
const metadataPath = join25(dir, "metadata.json");
|
|
55070
55080
|
writeFileSync14(metadataPath, JSON.stringify(samples, null, 2), "utf8");
|
|
55071
55081
|
return samples;
|
|
55072
55082
|
}
|
|
@@ -55274,20 +55284,20 @@ function slugify(value) {
|
|
|
55274
55284
|
// src/research/calibrator.ts
|
|
55275
55285
|
import { execFileSync as execFileSync2 } from "child_process";
|
|
55276
55286
|
import { existsSync as existsSync26, readFileSync as readFileSync29, writeFileSync as writeFileSync15, mkdirSync as mkdirSync12 } from "fs";
|
|
55277
|
-
import { join as
|
|
55287
|
+
import { join as join27, resolve as resolve24 } from "path";
|
|
55278
55288
|
|
|
55279
55289
|
// src/corpus-paths.ts
|
|
55280
|
-
import { join as
|
|
55290
|
+
import { join as join26 } from "path";
|
|
55281
55291
|
var CORPUS_ROOT = process.env["SLOPBRICK_CORPUS_DIR"] ?? "/Users/cheng/corpus-expansion";
|
|
55282
|
-
var POSITIVE_DIR =
|
|
55283
|
-
var NEGATIVE_DIR =
|
|
55284
|
-
var FILELISTS_DIR =
|
|
55292
|
+
var POSITIVE_DIR = join26(CORPUS_ROOT, "positive");
|
|
55293
|
+
var NEGATIVE_DIR = join26(CORPUS_ROOT, "negative");
|
|
55294
|
+
var FILELISTS_DIR = join26(CORPUS_ROOT, "filelists");
|
|
55285
55295
|
|
|
55286
55296
|
// src/research/calibrator.ts
|
|
55287
55297
|
var DEFAULT_POSITIVE = POSITIVE_DIR;
|
|
55288
55298
|
var DEFAULT_NEGATIVE = NEGATIVE_DIR;
|
|
55289
55299
|
function buildFileList(dir, extensions) {
|
|
55290
|
-
const tmpList =
|
|
55300
|
+
const tmpList = join27("/tmp", `cal-build-${Date.now()}-${Math.random().toString(36).slice(2)}.txt`);
|
|
55291
55301
|
const expr = extensions.map((e) => `-name '*.${e}'`).join(" -o ");
|
|
55292
55302
|
execFileSync2("bash", ["-c", `find ${dir} -maxdepth 8 -type f \\( ${expr} \\) -print0 | xargs -0 realpath > ${tmpList}`]);
|
|
55293
55303
|
const out = readFileSync29(tmpList, "utf8");
|
|
@@ -55300,13 +55310,13 @@ function runScan2(fileListPath) {
|
|
|
55300
55310
|
const ruleFires = /* @__PURE__ */ new Map();
|
|
55301
55311
|
const uniqueFilesPerRule = /* @__PURE__ */ new Map();
|
|
55302
55312
|
let fileCount = 0;
|
|
55303
|
-
const tmpOut =
|
|
55313
|
+
const tmpOut = join27("/tmp", `calibrate-${Date.now()}-${Math.random().toString(36).slice(2)}.json`);
|
|
55304
55314
|
for (let i = 0; i < files.length; i += CHUNK) {
|
|
55305
55315
|
const chunk = files.slice(i, i + CHUNK);
|
|
55306
55316
|
try {
|
|
55307
55317
|
execFileSync2(
|
|
55308
55318
|
"node",
|
|
55309
|
-
[
|
|
55319
|
+
[join27(process.cwd(), "bin", "slopbrick.js"), "scan", ...chunk, "--json", tmpOut, "--no-telemetry", "--quiet"],
|
|
55310
55320
|
{ encoding: "utf8", stdio: ["ignore", "pipe", "pipe"] }
|
|
55311
55321
|
);
|
|
55312
55322
|
} catch {
|
|
@@ -55346,8 +55356,8 @@ async function calibrate(cwd, options = {}) {
|
|
|
55346
55356
|
const negativeFiles = buildFileList(negativeDir, ["tsx", "ts"]);
|
|
55347
55357
|
const posSample = options.positiveLimit ? positiveFiles.slice(0, options.positiveLimit) : positiveFiles;
|
|
55348
55358
|
const negSample = options.negativeLimit ? negativeFiles.slice(0, options.negativeLimit) : negativeFiles;
|
|
55349
|
-
const posListPath =
|
|
55350
|
-
const negListPath =
|
|
55359
|
+
const posListPath = join27("/tmp", `cal-pos-${Date.now()}.txt`);
|
|
55360
|
+
const negListPath = join27("/tmp", `cal-neg-${Date.now()}.txt`);
|
|
55351
55361
|
writeFileSync15(posListPath, posSample.join("\n"));
|
|
55352
55362
|
writeFileSync15(negListPath, negSample.join("\n"));
|
|
55353
55363
|
const builtins = await Promise.resolve().then(() => (init_builtins(), builtins_exports));
|
|
@@ -57250,7 +57260,7 @@ function registerResearch(program) {
|
|
|
57250
57260
|
init_logger();
|
|
57251
57261
|
init_builtins();
|
|
57252
57262
|
import { existsSync as existsSync28, mkdirSync as mkdirSync15, readFileSync as readFileSync35, writeFileSync as writeFileSync18 } from "fs";
|
|
57253
|
-
import { dirname as dirname19, join as
|
|
57263
|
+
import { dirname as dirname19, join as join29, resolve as resolve39 } from "path";
|
|
57254
57264
|
init_scan();
|
|
57255
57265
|
init_config();
|
|
57256
57266
|
init_threshold();
|
|
@@ -57258,7 +57268,7 @@ init_git();
|
|
|
57258
57268
|
init_cache();
|
|
57259
57269
|
|
|
57260
57270
|
// src/snippet/targets.ts
|
|
57261
|
-
import { join as
|
|
57271
|
+
import { join as join28 } from "path";
|
|
57262
57272
|
|
|
57263
57273
|
// src/snippet/render.ts
|
|
57264
57274
|
function aiSpecificRules(rules) {
|
|
@@ -57489,7 +57499,7 @@ var SNIPPET_TARGETS = [
|
|
|
57489
57499
|
}
|
|
57490
57500
|
];
|
|
57491
57501
|
function resolveTargetPath(target) {
|
|
57492
|
-
return target.isFolder ?
|
|
57502
|
+
return target.isFolder ? join28(target.path, target.filename) : target.path;
|
|
57493
57503
|
}
|
|
57494
57504
|
function renderMatrix() {
|
|
57495
57505
|
const lines = [];
|
|
@@ -57512,7 +57522,7 @@ function registerInit(program) {
|
|
|
57512
57522
|
process.exit(0);
|
|
57513
57523
|
}
|
|
57514
57524
|
const cwd = resolve39(options.workspace ?? process.cwd());
|
|
57515
|
-
const configPath =
|
|
57525
|
+
const configPath = join29(cwd, "slopbrick.config.mjs");
|
|
57516
57526
|
const detected = detectStack(cwd);
|
|
57517
57527
|
const fallbackConfig = { ...DEFAULT_CONFIG, ...detected };
|
|
57518
57528
|
const proposed = serializeConfig(fallbackConfig);
|
|
@@ -57568,7 +57578,7 @@ function registerInit(program) {
|
|
|
57568
57578
|
return Boolean(opts[t.flag]);
|
|
57569
57579
|
});
|
|
57570
57580
|
for (const target of targetsToWrite) {
|
|
57571
|
-
const snippetPath =
|
|
57581
|
+
const snippetPath = join29(cwd, resolveTargetPath(target));
|
|
57572
57582
|
mkdirSync15(dirname19(snippetPath), { recursive: true });
|
|
57573
57583
|
const generated = target.generator(builtinRules);
|
|
57574
57584
|
if (!target.isFolder && existsSync28(snippetPath)) {
|
|
@@ -57615,7 +57625,7 @@ import { dirname as dirname20, resolve as resolve40 } from "path";
|
|
|
57615
57625
|
|
|
57616
57626
|
// src/report/flywheel.ts
|
|
57617
57627
|
import { existsSync as existsSync29, readFileSync as readFileSync36 } from "fs";
|
|
57618
|
-
import { join as
|
|
57628
|
+
import { join as join30 } from "path";
|
|
57619
57629
|
function average(values) {
|
|
57620
57630
|
if (values.length === 0) return 0;
|
|
57621
57631
|
return values.reduce((a, b) => a + b, 0) / values.length;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "slopbrick",
|
|
3
|
-
"version": "0.18.
|
|
3
|
+
"version": "0.18.3",
|
|
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": {
|