slopbrick 0.11.0 → 0.11.2
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/index.cjs +309 -122
- package/dist/index.d.cts +1 -3
- package/dist/index.d.ts +1 -3
- package/dist/index.js +439 -273
- package/package.json +17 -13
package/dist/index.cjs
CHANGED
|
@@ -36,7 +36,7 @@ var VERSION, AI_SECURITY_NUMERIC, REPOSITORY_HEALTH_WEIGHTS;
|
|
|
36
36
|
var init_types = __esm({
|
|
37
37
|
"src/types.ts"() {
|
|
38
38
|
"use strict";
|
|
39
|
-
VERSION = "0.
|
|
39
|
+
VERSION = "0.11.2";
|
|
40
40
|
AI_SECURITY_NUMERIC = {
|
|
41
41
|
low: 100,
|
|
42
42
|
medium: 75,
|
|
@@ -3486,7 +3486,7 @@ function discoverTestFiles(cwd) {
|
|
|
3486
3486
|
}
|
|
3487
3487
|
return found;
|
|
3488
3488
|
}
|
|
3489
|
-
function walk(dir, out, readdirSync6,
|
|
3489
|
+
function walk(dir, out, readdirSync6, statSync8) {
|
|
3490
3490
|
let entries;
|
|
3491
3491
|
try {
|
|
3492
3492
|
entries = readdirSync6(dir);
|
|
@@ -3498,12 +3498,12 @@ function walk(dir, out, readdirSync6, statSync7) {
|
|
|
3498
3498
|
const full = `${dir}/${entry}`;
|
|
3499
3499
|
let stat;
|
|
3500
3500
|
try {
|
|
3501
|
-
stat =
|
|
3501
|
+
stat = statSync8(full);
|
|
3502
3502
|
} catch {
|
|
3503
3503
|
continue;
|
|
3504
3504
|
}
|
|
3505
3505
|
if (stat.isDirectory()) {
|
|
3506
|
-
walk(full, out, readdirSync6,
|
|
3506
|
+
walk(full, out, readdirSync6, statSync8);
|
|
3507
3507
|
} else if (stat.isFile()) {
|
|
3508
3508
|
if (/\.(test|spec)\.[jt]sx?$/.test(entry) || /\.stories\.[jt]sx?$/.test(entry)) {
|
|
3509
3509
|
out.push(full);
|
|
@@ -9412,8 +9412,8 @@ function hasExtendedSibling(filePath) {
|
|
|
9412
9412
|
const base = (0, import_node_path7.basename)(filePath);
|
|
9413
9413
|
for (const ext of SOURCE_EXTENSIONS) {
|
|
9414
9414
|
try {
|
|
9415
|
-
const { statSync:
|
|
9416
|
-
|
|
9415
|
+
const { statSync: statSync8 } = require("fs");
|
|
9416
|
+
statSync8((0, import_node_path7.join)(dir, base + ext));
|
|
9417
9417
|
return true;
|
|
9418
9418
|
} catch {
|
|
9419
9419
|
}
|
|
@@ -9571,8 +9571,8 @@ var init_git = __esm({
|
|
|
9571
9571
|
});
|
|
9572
9572
|
|
|
9573
9573
|
// src/engine/cache-incremental.ts
|
|
9574
|
-
function loadCache(
|
|
9575
|
-
const abs = (0, import_node_path8.isAbsolute)(
|
|
9574
|
+
function loadCache(cachePath4) {
|
|
9575
|
+
const abs = (0, import_node_path8.isAbsolute)(cachePath4) ? cachePath4 : (0, import_node_path8.resolve)(process.cwd(), cachePath4);
|
|
9576
9576
|
if (!(0, import_node_fs9.existsSync)(abs)) return void 0;
|
|
9577
9577
|
try {
|
|
9578
9578
|
const raw = (0, import_node_fs9.readFileSync)(abs, "utf-8");
|
|
@@ -9583,8 +9583,8 @@ function loadCache(cachePath6) {
|
|
|
9583
9583
|
return void 0;
|
|
9584
9584
|
}
|
|
9585
9585
|
}
|
|
9586
|
-
function saveCache(
|
|
9587
|
-
const abs = (0, import_node_path8.isAbsolute)(
|
|
9586
|
+
function saveCache(cachePath4, cache) {
|
|
9587
|
+
const abs = (0, import_node_path8.isAbsolute)(cachePath4) ? cachePath4 : (0, import_node_path8.resolve)(process.cwd(), cachePath4);
|
|
9588
9588
|
(0, import_node_fs9.mkdirSync)((0, import_node_path8.dirname)(abs), { recursive: true });
|
|
9589
9589
|
const tmp = abs + ".tmp";
|
|
9590
9590
|
if ((0, import_node_fs9.existsSync)(tmp)) {
|
|
@@ -12889,12 +12889,41 @@ var init_heatmap = __esm({
|
|
|
12889
12889
|
}
|
|
12890
12890
|
});
|
|
12891
12891
|
|
|
12892
|
-
//
|
|
12893
|
-
|
|
12894
|
-
|
|
12895
|
-
|
|
12896
|
-
|
|
12892
|
+
// ../core/dist/index.js
|
|
12893
|
+
function inventoryPath(workspaceDir) {
|
|
12894
|
+
return (0, import_path.join)(workspaceDir, ".slopbrick", INVENTORY_FILENAME);
|
|
12895
|
+
}
|
|
12896
|
+
function constitutionPath(workspaceDir) {
|
|
12897
|
+
return (0, import_path.join)(workspaceDir, ".slopbrick", CONSTITUTION_FILENAME);
|
|
12898
|
+
}
|
|
12899
|
+
function ensureSlopbrickDir(workspaceDir) {
|
|
12900
|
+
(0, import_fs.mkdirSync)((0, import_path.join)(workspaceDir, ".slopbrick"), { recursive: true });
|
|
12901
|
+
}
|
|
12902
|
+
function writeJsonAtomic(filePath, payload) {
|
|
12903
|
+
ensureSlopbrickDir((0, import_path.dirname)(filePath));
|
|
12904
|
+
const tmp = `${filePath}.tmp`;
|
|
12905
|
+
(0, import_fs.writeFileSync)(tmp, JSON.stringify(payload, null, 2), "utf-8");
|
|
12906
|
+
(0, import_fs.renameSync)(tmp, filePath);
|
|
12907
|
+
}
|
|
12908
|
+
function saveInventory(workspaceDir, inventory) {
|
|
12909
|
+
writeJsonAtomic(inventoryPath(workspaceDir), inventory);
|
|
12897
12910
|
}
|
|
12911
|
+
function saveConstitution(workspaceDir, constitution) {
|
|
12912
|
+
writeJsonAtomic(constitutionPath(workspaceDir), constitution);
|
|
12913
|
+
}
|
|
12914
|
+
var import_fs, import_path, MEMORY_SCHEMA_VERSION, INVENTORY_FILENAME, CONSTITUTION_FILENAME;
|
|
12915
|
+
var init_dist = __esm({
|
|
12916
|
+
"../core/dist/index.js"() {
|
|
12917
|
+
"use strict";
|
|
12918
|
+
import_fs = require("fs");
|
|
12919
|
+
import_path = require("path");
|
|
12920
|
+
MEMORY_SCHEMA_VERSION = "2";
|
|
12921
|
+
INVENTORY_FILENAME = "inventory.json";
|
|
12922
|
+
CONSTITUTION_FILENAME = "constitution.json";
|
|
12923
|
+
}
|
|
12924
|
+
});
|
|
12925
|
+
|
|
12926
|
+
// src/engine/memory.ts
|
|
12898
12927
|
function telemetryPath(cwd) {
|
|
12899
12928
|
return (0, import_node_path17.join)(cwd, TELEMETRY_FILE);
|
|
12900
12929
|
}
|
|
@@ -12969,7 +12998,7 @@ async function buildInventoryFromScan(scanResult, config, durationMs) {
|
|
|
12969
12998
|
);
|
|
12970
12999
|
const components = buildComponentFingerprints(scanResult.results);
|
|
12971
13000
|
return {
|
|
12972
|
-
version:
|
|
13001
|
+
version: MEMORY_SCHEMA_VERSION,
|
|
12973
13002
|
generatedAt: (/* @__PURE__ */ new Date()).toISOString(),
|
|
12974
13003
|
workspace: scanResult.cwd,
|
|
12975
13004
|
scannedFiles: inventory.scannedFiles,
|
|
@@ -13004,7 +13033,7 @@ function buildConstitutionFromConfig(config, workspace) {
|
|
|
13004
13033
|
const forbidden = forbiddenList.filter((e) => !e.endsWith("/"));
|
|
13005
13034
|
const forbiddenPrefixes = forbiddenList.filter((e) => e.endsWith("/"));
|
|
13006
13035
|
return {
|
|
13007
|
-
version:
|
|
13036
|
+
version: MEMORY_SCHEMA_VERSION,
|
|
13008
13037
|
generatedAt: (/* @__PURE__ */ new Date()).toISOString(),
|
|
13009
13038
|
workspace,
|
|
13010
13039
|
declared,
|
|
@@ -13050,7 +13079,7 @@ function buildComponentFingerprints(results) {
|
|
|
13050
13079
|
}
|
|
13051
13080
|
return [...byName.values()].sort((a, b) => a.name.localeCompare(b.name));
|
|
13052
13081
|
}
|
|
13053
|
-
var import_node_fs16, import_node_path17, import_node_crypto6,
|
|
13082
|
+
var import_node_fs16, import_node_path17, import_node_crypto6, TELEMETRY_FILE, MAX_RUNS;
|
|
13054
13083
|
var init_memory = __esm({
|
|
13055
13084
|
"src/engine/memory.ts"() {
|
|
13056
13085
|
"use strict";
|
|
@@ -13060,8 +13089,7 @@ var init_memory = __esm({
|
|
|
13060
13089
|
init_types();
|
|
13061
13090
|
init_patterns();
|
|
13062
13091
|
init_cache_incremental();
|
|
13063
|
-
|
|
13064
|
-
import_core5 = require("@usebrick/core");
|
|
13092
|
+
init_dist();
|
|
13065
13093
|
TELEMETRY_FILE = (0, import_node_path17.join)(".slopbrick", "memory.json");
|
|
13066
13094
|
MAX_RUNS = 1e3;
|
|
13067
13095
|
}
|
|
@@ -15508,8 +15536,8 @@ async function runScan(options, explicitPaths) {
|
|
|
15508
15536
|
}
|
|
15509
15537
|
let incrementalSummary;
|
|
15510
15538
|
if (options.incremental) {
|
|
15511
|
-
const
|
|
15512
|
-
const existing = loadCache(
|
|
15539
|
+
const cachePath4 = options.cachePath ?? ".slopbrick-cache.json";
|
|
15540
|
+
const existing = loadCache(cachePath4);
|
|
15513
15541
|
const { toScan, unchanged } = partitionByCache(files, existing);
|
|
15514
15542
|
files = toScan;
|
|
15515
15543
|
incrementalSummary = { skipped: unchanged.length, rescanned: toScan.length };
|
|
@@ -15928,8 +15956,8 @@ async function runScan(options, explicitPaths) {
|
|
|
15928
15956
|
appendRun(cwd, report, thresholdExceeded(report, config));
|
|
15929
15957
|
}
|
|
15930
15958
|
if (options.incremental) {
|
|
15931
|
-
const
|
|
15932
|
-
const existing = loadCache(
|
|
15959
|
+
const cachePath4 = options.cachePath ?? ".slopbrick-cache.json";
|
|
15960
|
+
const existing = loadCache(cachePath4) ?? emptyCache();
|
|
15933
15961
|
const next = { ...existing, generatedAt: (/* @__PURE__ */ new Date()).toISOString() };
|
|
15934
15962
|
for (const result of results) {
|
|
15935
15963
|
try {
|
|
@@ -15943,7 +15971,7 @@ async function runScan(options, explicitPaths) {
|
|
|
15943
15971
|
} catch {
|
|
15944
15972
|
}
|
|
15945
15973
|
}
|
|
15946
|
-
saveCache(
|
|
15974
|
+
saveCache(cachePath4, next);
|
|
15947
15975
|
if (incrementalSummary && !options.quiet) {
|
|
15948
15976
|
logger.info(
|
|
15949
15977
|
`Incremental: re-scanned ${incrementalSummary.rescanned}, skipped ${incrementalSummary.skipped} (unchanged).`
|
|
@@ -15995,7 +16023,7 @@ async function runScan(options, explicitPaths) {
|
|
|
15995
16023
|
);
|
|
15996
16024
|
await saveInventory(cwd, inventory);
|
|
15997
16025
|
const constitution = buildConstitutionFromConfig(config, cwd);
|
|
15998
|
-
await
|
|
16026
|
+
await saveConstitution(cwd, constitution);
|
|
15999
16027
|
if (!options.quiet && !machineReadableStdout) {
|
|
16000
16028
|
logger.info(`Memory persisted to .slopbrick/ (${inventory.patterns.length} patterns, ${inventory.components.length} components).`);
|
|
16001
16029
|
}
|
|
@@ -16313,6 +16341,7 @@ var init_scan = __esm({
|
|
|
16313
16341
|
init_unified_diff();
|
|
16314
16342
|
init_heatmap();
|
|
16315
16343
|
init_memory();
|
|
16344
|
+
init_dist();
|
|
16316
16345
|
init_telemetry();
|
|
16317
16346
|
init_flywheel();
|
|
16318
16347
|
init_logger();
|
|
@@ -16764,14 +16793,14 @@ async function runBusinessLogicScore(args, ctx) {
|
|
|
16764
16793
|
const maxFiles = typeof maxFilesRaw === "number" && Number.isFinite(maxFilesRaw) && maxFilesRaw > 0 ? Math.min(2e3, Math.floor(maxFilesRaw)) : 500;
|
|
16765
16794
|
try {
|
|
16766
16795
|
const { discoverFiles: discoverFiles2 } = await Promise.resolve().then(() => (init_discover(), discover_exports));
|
|
16767
|
-
const { readFileSync:
|
|
16796
|
+
const { readFileSync: readFileSync39 } = await import("fs");
|
|
16768
16797
|
const allFiles = await discoverFiles2(ctx.cwd, ctx.config);
|
|
16769
16798
|
const limited = allFiles.slice(0, maxFiles);
|
|
16770
16799
|
const issues = [];
|
|
16771
16800
|
for (const absPath of limited) {
|
|
16772
16801
|
let source;
|
|
16773
16802
|
try {
|
|
16774
|
-
source =
|
|
16803
|
+
source = readFileSync39(absPath, "utf-8");
|
|
16775
16804
|
} catch {
|
|
16776
16805
|
continue;
|
|
16777
16806
|
}
|
|
@@ -17038,21 +17067,189 @@ var init_tools = __esm({
|
|
|
17038
17067
|
}
|
|
17039
17068
|
});
|
|
17040
17069
|
|
|
17070
|
+
// src/cli/migrate.ts
|
|
17071
|
+
var migrate_exports = {};
|
|
17072
|
+
__export(migrate_exports, {
|
|
17073
|
+
applyMigration: () => applyMigration,
|
|
17074
|
+
formatMigrate: () => formatMigrate,
|
|
17075
|
+
isAlreadyMigrated: () => isAlreadyMigrated,
|
|
17076
|
+
logger: () => logger,
|
|
17077
|
+
planMigration: () => planMigration,
|
|
17078
|
+
runMigrate: () => runMigrate
|
|
17079
|
+
});
|
|
17080
|
+
function planMigration(workspaceDir) {
|
|
17081
|
+
const moves = [];
|
|
17082
|
+
const rewrites = [];
|
|
17083
|
+
const gitignoreEdits = [];
|
|
17084
|
+
const oldDir = (0, import_node_path38.join)(workspaceDir, ".slop-audit");
|
|
17085
|
+
const newDir = (0, import_node_path38.join)(workspaceDir, ".slopbrick");
|
|
17086
|
+
if ((0, import_node_fs39.existsSync)(oldDir)) {
|
|
17087
|
+
moves.push({ from: oldDir, to: newDir, kind: "dir" });
|
|
17088
|
+
rewrites.push({
|
|
17089
|
+
path: (0, import_node_path38.join)(newDir, "inventory.json"),
|
|
17090
|
+
field: "version",
|
|
17091
|
+
from: '"1"',
|
|
17092
|
+
to: '"2"'
|
|
17093
|
+
});
|
|
17094
|
+
rewrites.push({
|
|
17095
|
+
path: (0, import_node_path38.join)(newDir, "constitution.json"),
|
|
17096
|
+
field: "version",
|
|
17097
|
+
from: '"1"',
|
|
17098
|
+
to: '"2"'
|
|
17099
|
+
});
|
|
17100
|
+
}
|
|
17101
|
+
const oldCache = (0, import_node_path38.join)(workspaceDir, ".slop-audit-cache.json");
|
|
17102
|
+
const newCache = (0, import_node_path38.join)(workspaceDir, ".slopbrick-cache.json");
|
|
17103
|
+
if ((0, import_node_fs39.existsSync)(oldCache)) {
|
|
17104
|
+
moves.push({ from: oldCache, to: newCache, kind: "file" });
|
|
17105
|
+
}
|
|
17106
|
+
for (const ext of ["mjs", "cjs", "js"]) {
|
|
17107
|
+
const oldCfg = (0, import_node_path38.join)(workspaceDir, `slop-audit.config.${ext}`);
|
|
17108
|
+
const newCfg = (0, import_node_path38.join)(workspaceDir, `slopbrick.config.${ext}`);
|
|
17109
|
+
if ((0, import_node_fs39.existsSync)(oldCfg)) {
|
|
17110
|
+
moves.push({ from: oldCfg, to: newCfg, kind: "config" });
|
|
17111
|
+
}
|
|
17112
|
+
}
|
|
17113
|
+
const gi = (0, import_node_path38.join)(workspaceDir, ".gitignore");
|
|
17114
|
+
if ((0, import_node_fs39.existsSync)(gi)) {
|
|
17115
|
+
const content = (0, import_node_fs39.readFileSync)(gi, "utf-8");
|
|
17116
|
+
if (content.includes(".slop-audit/")) {
|
|
17117
|
+
gitignoreEdits.push({
|
|
17118
|
+
path: gi,
|
|
17119
|
+
from: ".slop-audit/",
|
|
17120
|
+
to: ".slopbrick/"
|
|
17121
|
+
});
|
|
17122
|
+
}
|
|
17123
|
+
if (content.includes(".slop-audit-cache.json")) {
|
|
17124
|
+
gitignoreEdits.push({
|
|
17125
|
+
path: gi,
|
|
17126
|
+
from: ".slop-audit-cache.json",
|
|
17127
|
+
to: ".slopbrick-cache.json"
|
|
17128
|
+
});
|
|
17129
|
+
}
|
|
17130
|
+
}
|
|
17131
|
+
return { moves, rewrites, gitignoreEdits };
|
|
17132
|
+
}
|
|
17133
|
+
function isAlreadyMigrated(workspaceDir) {
|
|
17134
|
+
return (0, import_node_fs39.existsSync)((0, import_node_path38.join)(workspaceDir, ".slopbrick")) && !(0, import_node_fs39.existsSync)((0, import_node_path38.join)(workspaceDir, ".slop-audit"));
|
|
17135
|
+
}
|
|
17136
|
+
function applyMigration(plan, options = {}) {
|
|
17137
|
+
if (options.dryRun) return;
|
|
17138
|
+
for (const m of plan.moves) {
|
|
17139
|
+
(0, import_node_fs39.renameSync)(m.from, m.to);
|
|
17140
|
+
}
|
|
17141
|
+
for (const r of plan.rewrites) {
|
|
17142
|
+
if (!(0, import_node_fs39.existsSync)(r.path)) continue;
|
|
17143
|
+
const content = (0, import_node_fs39.readFileSync)(r.path, "utf-8");
|
|
17144
|
+
const next = content.replace(`"version": ${r.from}`, `"version": ${r.to}`);
|
|
17145
|
+
(0, import_node_fs39.writeFileSync)(r.path, next);
|
|
17146
|
+
}
|
|
17147
|
+
for (const g of plan.gitignoreEdits) {
|
|
17148
|
+
const content = (0, import_node_fs39.readFileSync)(g.path, "utf-8");
|
|
17149
|
+
const next = content.replaceAll(g.from, g.to);
|
|
17150
|
+
(0, import_node_fs39.writeFileSync)(g.path, next);
|
|
17151
|
+
}
|
|
17152
|
+
}
|
|
17153
|
+
function runMigrate(options) {
|
|
17154
|
+
const { workspace, dryRun = false, force = false } = options;
|
|
17155
|
+
if (!(0, import_node_fs39.existsSync)(workspace)) {
|
|
17156
|
+
return {
|
|
17157
|
+
ok: false,
|
|
17158
|
+
alreadyMigrated: false,
|
|
17159
|
+
planned: { moves: [], rewrites: [], gitignoreEdits: [] },
|
|
17160
|
+
applied: false,
|
|
17161
|
+
reason: `Workspace ${workspace} does not exist`
|
|
17162
|
+
};
|
|
17163
|
+
}
|
|
17164
|
+
const alreadyMigrated = isAlreadyMigrated(workspace);
|
|
17165
|
+
const newDir = (0, import_node_path38.join)(workspace, ".slopbrick");
|
|
17166
|
+
const oldDir = (0, import_node_path38.join)(workspace, ".slop-audit");
|
|
17167
|
+
if ((0, import_node_fs39.existsSync)(newDir) && (0, import_node_fs39.existsSync)(oldDir) && !force) {
|
|
17168
|
+
return {
|
|
17169
|
+
ok: false,
|
|
17170
|
+
alreadyMigrated: false,
|
|
17171
|
+
planned: { moves: [], rewrites: [], gitignoreEdits: [] },
|
|
17172
|
+
applied: false,
|
|
17173
|
+
reason: `Both .slopbrick/ and .slop-audit/ exist. Use --force to overwrite the .slopbrick/ directory, or manually resolve the conflict.`
|
|
17174
|
+
};
|
|
17175
|
+
}
|
|
17176
|
+
const planned = planMigration(workspace);
|
|
17177
|
+
const nothingToDo = planned.moves.length === 0 && planned.rewrites.length === 0 && planned.gitignoreEdits.length === 0;
|
|
17178
|
+
if (nothingToDo) {
|
|
17179
|
+
return {
|
|
17180
|
+
ok: true,
|
|
17181
|
+
alreadyMigrated,
|
|
17182
|
+
planned,
|
|
17183
|
+
applied: false
|
|
17184
|
+
};
|
|
17185
|
+
}
|
|
17186
|
+
applyMigration(planned, { dryRun });
|
|
17187
|
+
return {
|
|
17188
|
+
ok: true,
|
|
17189
|
+
alreadyMigrated: false,
|
|
17190
|
+
planned,
|
|
17191
|
+
applied: !dryRun
|
|
17192
|
+
};
|
|
17193
|
+
}
|
|
17194
|
+
function formatMigrate(result) {
|
|
17195
|
+
const lines = [];
|
|
17196
|
+
if (result.alreadyMigrated) {
|
|
17197
|
+
lines.push("Already migrated to v2 (no work needed).");
|
|
17198
|
+
return lines.join("\n");
|
|
17199
|
+
}
|
|
17200
|
+
if (!result.ok) {
|
|
17201
|
+
lines.push(`ERROR: ${result.reason ?? "unknown failure"}`);
|
|
17202
|
+
return lines.join("\n");
|
|
17203
|
+
}
|
|
17204
|
+
if (result.planned.moves.length === 0 && result.planned.gitignoreEdits.length === 0) {
|
|
17205
|
+
lines.push("Nothing to migrate \u2014 workspace is already on slopbrick v0.11.0+.");
|
|
17206
|
+
}
|
|
17207
|
+
if (result.planned.moves.length > 0) {
|
|
17208
|
+
lines.push("Moves:");
|
|
17209
|
+
for (const m of result.planned.moves) {
|
|
17210
|
+
lines.push(` ${m.from}`);
|
|
17211
|
+
lines.push(` \u2192 ${m.to} (${m.kind})`);
|
|
17212
|
+
}
|
|
17213
|
+
}
|
|
17214
|
+
if (result.planned.rewrites.length > 0) {
|
|
17215
|
+
lines.push("Schema version bumps:");
|
|
17216
|
+
for (const r of result.planned.rewrites) {
|
|
17217
|
+
lines.push(` ${r.path} ${r.field}: ${r.from} \u2192 ${r.to}`);
|
|
17218
|
+
}
|
|
17219
|
+
}
|
|
17220
|
+
if (result.planned.gitignoreEdits.length > 0) {
|
|
17221
|
+
lines.push(".gitignore edits:");
|
|
17222
|
+
for (const g of result.planned.gitignoreEdits) {
|
|
17223
|
+
lines.push(` ${g.path}: ${g.from} \u2192 ${g.to}`);
|
|
17224
|
+
}
|
|
17225
|
+
}
|
|
17226
|
+
lines.push("");
|
|
17227
|
+
if (result.applied) {
|
|
17228
|
+
lines.push("Migration applied. Run `slopbrick scan` to regenerate inventory at v2.");
|
|
17229
|
+
} else {
|
|
17230
|
+
lines.push("DRY RUN \u2014 no files were changed. Re-run without --dry-run to apply.");
|
|
17231
|
+
}
|
|
17232
|
+
return lines.join("\n");
|
|
17233
|
+
}
|
|
17234
|
+
var import_node_fs39, import_node_path38;
|
|
17235
|
+
var init_migrate = __esm({
|
|
17236
|
+
"src/cli/migrate.ts"() {
|
|
17237
|
+
"use strict";
|
|
17238
|
+
import_node_fs39 = require("fs");
|
|
17239
|
+
import_node_path38 = require("path");
|
|
17240
|
+
init_logger();
|
|
17241
|
+
}
|
|
17242
|
+
});
|
|
17243
|
+
|
|
17041
17244
|
// src/index.ts
|
|
17042
17245
|
var src_exports = {};
|
|
17043
17246
|
__export(src_exports, {
|
|
17044
17247
|
AI_SECURITY_NUMERIC: () => AI_SECURITY_NUMERIC,
|
|
17045
|
-
CACHE_FILENAME: () => import_core6.CACHE_FILENAME,
|
|
17046
|
-
CONSTITUTION_FILENAME: () => import_core6.CONSTITUTION_FILENAME,
|
|
17047
17248
|
DEFAULT_CONFIG: () => DEFAULT_CONFIG,
|
|
17048
|
-
INVENTORY_FILENAME: () => import_core6.INVENTORY_FILENAME,
|
|
17049
|
-
MEMORY_SCHEMA_VERSION: () => import_core6.MEMORY_SCHEMA_VERSION,
|
|
17050
17249
|
REPOSITORY_HEALTH_WEIGHTS: () => REPOSITORY_HEALTH_WEIGHTS,
|
|
17051
17250
|
VERSION: () => VERSION,
|
|
17052
17251
|
baselineStatusMessage: () => baselineStatusMessage,
|
|
17053
|
-
cachePath: () => import_core6.cachePath,
|
|
17054
17252
|
colorForSlop: () => colorForSlop,
|
|
17055
|
-
constitutionPath: () => import_core6.constitutionPath,
|
|
17056
17253
|
extractSignatures: () => extractSignatures,
|
|
17057
17254
|
failedThresholdCount: () => failedThresholdCount,
|
|
17058
17255
|
filterByDisabledDirectives: () => filterByDisabledDirectives,
|
|
@@ -17062,22 +17259,10 @@ __export(src_exports, {
|
|
|
17062
17259
|
formatBadge: () => formatBadge,
|
|
17063
17260
|
formatReportFromFile: () => formatReportFromFile,
|
|
17064
17261
|
formatSparkline: () => formatSparkline,
|
|
17065
|
-
invalidateFile: () => import_core6.invalidateFile,
|
|
17066
|
-
inventoryPath: () => import_core6.inventoryPath,
|
|
17067
|
-
isComponentFingerprint: () => import_core6.isComponentFingerprint,
|
|
17068
|
-
isConstitutionFile: () => import_core6.isConstitutionFile,
|
|
17069
|
-
isFileMtimeEntry: () => import_core6.isFileMtimeEntry,
|
|
17070
|
-
isInventoryFile: () => import_core6.isInventoryFile,
|
|
17071
|
-
isInventoryFresh: () => import_core6.isInventoryFresh,
|
|
17072
|
-
isMemoryPattern: () => import_core6.isMemoryPattern,
|
|
17073
17262
|
loadConfig: () => loadConfig,
|
|
17074
|
-
loadConstitution: () => import_core6.loadConstitution,
|
|
17075
|
-
loadInventory: () => import_core6.loadInventory,
|
|
17076
17263
|
readReportFile: () => readReportFile,
|
|
17077
17264
|
runCli: () => runCli,
|
|
17078
17265
|
runInitWizard: () => runInitWizard,
|
|
17079
|
-
saveConstitution: () => import_core6.saveConstitution,
|
|
17080
|
-
saveInventory: () => import_core6.saveInventory,
|
|
17081
17266
|
scanProject: () => scanProject,
|
|
17082
17267
|
serializeConfig: () => serializeConfig,
|
|
17083
17268
|
signatureSimilarity: () => signatureSimilarity,
|
|
@@ -17089,8 +17274,8 @@ init_types();
|
|
|
17089
17274
|
init_config();
|
|
17090
17275
|
|
|
17091
17276
|
// src/cli/program.ts
|
|
17092
|
-
var
|
|
17093
|
-
var
|
|
17277
|
+
var import_node_fs40 = require("fs");
|
|
17278
|
+
var import_node_path39 = require("path");
|
|
17094
17279
|
var import_node_perf_hooks = require("perf_hooks");
|
|
17095
17280
|
var import_commander2 = require("commander");
|
|
17096
17281
|
|
|
@@ -18500,11 +18685,11 @@ var shadcn_registry_default = {
|
|
|
18500
18685
|
// src/rules/registry-loader.ts
|
|
18501
18686
|
var REGISTRY_URL = "https://ui.shadcn.com/registry.json";
|
|
18502
18687
|
var BUNDLED_REGISTRY_VERSION = shadcn_registry_default.version;
|
|
18503
|
-
function
|
|
18688
|
+
function cachePath3(cwd) {
|
|
18504
18689
|
return (0, import_node_path28.join)(cwd, ".slopbrick", "cache", "registry-snapshot.json");
|
|
18505
18690
|
}
|
|
18506
18691
|
function ensureCacheDir(cwd) {
|
|
18507
|
-
const dir = (0, import_node_path28.dirname)(
|
|
18692
|
+
const dir = (0, import_node_path28.dirname)(cachePath3(cwd));
|
|
18508
18693
|
if (!(0, import_node_fs27.existsSync)(dir)) {
|
|
18509
18694
|
(0, import_node_fs27.mkdirSync)(dir, { recursive: true });
|
|
18510
18695
|
}
|
|
@@ -18517,7 +18702,7 @@ function isValidSnapshot(value) {
|
|
|
18517
18702
|
return true;
|
|
18518
18703
|
}
|
|
18519
18704
|
function isRegistryFresh(cwd) {
|
|
18520
|
-
const cached =
|
|
18705
|
+
const cached = cachePath3(cwd);
|
|
18521
18706
|
if (!(0, import_node_fs27.existsSync)(cached)) return false;
|
|
18522
18707
|
try {
|
|
18523
18708
|
const parsed = JSON.parse((0, import_node_fs27.readFileSync)(cached, "utf8"));
|
|
@@ -18554,7 +18739,7 @@ async function refreshRegistrySnapshot(cwd, url = REGISTRY_URL, timeoutMs = 5e3)
|
|
|
18554
18739
|
};
|
|
18555
18740
|
}
|
|
18556
18741
|
ensureCacheDir(cwd);
|
|
18557
|
-
(0, import_node_fs27.writeFileSync)(
|
|
18742
|
+
(0, import_node_fs27.writeFileSync)(cachePath3(cwd), JSON.stringify(fetched, null, 2));
|
|
18558
18743
|
const fresh = fetched.version === BUNDLED_REGISTRY_VERSION;
|
|
18559
18744
|
return {
|
|
18560
18745
|
ok: true,
|
|
@@ -18564,7 +18749,7 @@ async function refreshRegistrySnapshot(cwd, url = REGISTRY_URL, timeoutMs = 5e3)
|
|
|
18564
18749
|
}
|
|
18565
18750
|
function copyBundledSnapshotToCache(cwd) {
|
|
18566
18751
|
ensureCacheDir(cwd);
|
|
18567
|
-
(0, import_node_fs27.writeFileSync)(
|
|
18752
|
+
(0, import_node_fs27.writeFileSync)(cachePath3(cwd), JSON.stringify(shadcn_registry_default, null, 2));
|
|
18568
18753
|
}
|
|
18569
18754
|
|
|
18570
18755
|
// src/cli/init.ts
|
|
@@ -20634,13 +20819,13 @@ async function runCli({ start }) {
|
|
|
20634
20819
|
logger.info(renderMatrix());
|
|
20635
20820
|
process.exit(0);
|
|
20636
20821
|
}
|
|
20637
|
-
const cwd = (0,
|
|
20638
|
-
const configPath = (0,
|
|
20822
|
+
const cwd = (0, import_node_path39.resolve)(options.workspace ?? process.cwd());
|
|
20823
|
+
const configPath = (0, import_node_path39.join)(cwd, "slopbrick.config.mjs");
|
|
20639
20824
|
const detected = detectStack(cwd);
|
|
20640
20825
|
const fallbackConfig = { ...DEFAULT_CONFIG, ...detected };
|
|
20641
20826
|
const proposed = serializeConfig(fallbackConfig);
|
|
20642
|
-
if ((0,
|
|
20643
|
-
const current = (0,
|
|
20827
|
+
if ((0, import_node_fs40.existsSync)(configPath) && !cmdOptions.yes) {
|
|
20828
|
+
const current = (0, import_node_fs40.readFileSync)(configPath, "utf8");
|
|
20644
20829
|
logger.error(`A config file already exists at ${configPath}.`);
|
|
20645
20830
|
logger.error("To overwrite it with defaults, run `slopbrick init --yes`.");
|
|
20646
20831
|
logger.error("");
|
|
@@ -20661,7 +20846,7 @@ async function runCli({ start }) {
|
|
|
20661
20846
|
config = buildInitConfig(detected, answers);
|
|
20662
20847
|
usedWizard = true;
|
|
20663
20848
|
}
|
|
20664
|
-
(0,
|
|
20849
|
+
(0, import_node_fs40.writeFileSync)(configPath, serializeConfig(config));
|
|
20665
20850
|
appendGitignore(cwd);
|
|
20666
20851
|
const refresh = await refreshRegistrySnapshot(cwd);
|
|
20667
20852
|
if (!refresh.ok) {
|
|
@@ -20691,21 +20876,21 @@ async function runCli({ start }) {
|
|
|
20691
20876
|
return Boolean(opts[t.flag]);
|
|
20692
20877
|
});
|
|
20693
20878
|
for (const target of targetsToWrite) {
|
|
20694
|
-
const snippetPath = (0,
|
|
20695
|
-
(0,
|
|
20879
|
+
const snippetPath = (0, import_node_path39.join)(cwd, resolveTargetPath(target));
|
|
20880
|
+
(0, import_node_fs40.mkdirSync)((0, import_node_path39.dirname)(snippetPath), { recursive: true });
|
|
20696
20881
|
const generated = target.generator(builtinRules);
|
|
20697
|
-
if (!target.isFolder && (0,
|
|
20698
|
-
const existing = (0,
|
|
20882
|
+
if (!target.isFolder && (0, import_node_fs40.existsSync)(snippetPath)) {
|
|
20883
|
+
const existing = (0, import_node_fs40.readFileSync)(snippetPath, "utf8");
|
|
20699
20884
|
if (existing.includes("<!-- slopbrick:begin -->")) {
|
|
20700
20885
|
const updated = existing.replace(
|
|
20701
20886
|
/<!-- slopbrick:begin -->[\s\S]*?<!-- slopbrick:end -->/,
|
|
20702
20887
|
"<!-- slopbrick:begin -->\n" + generated + "<!-- slopbrick:end -->"
|
|
20703
20888
|
);
|
|
20704
|
-
(0,
|
|
20889
|
+
(0, import_node_fs40.writeFileSync)(snippetPath, updated, "utf8");
|
|
20705
20890
|
if (!options.quiet) logger.info(`Updated ${snippetPath}`);
|
|
20706
20891
|
continue;
|
|
20707
20892
|
}
|
|
20708
|
-
(0,
|
|
20893
|
+
(0, import_node_fs40.writeFileSync)(
|
|
20709
20894
|
snippetPath,
|
|
20710
20895
|
existing + (existing.endsWith("\n") ? "\n" : "\n\n") + generated,
|
|
20711
20896
|
"utf8"
|
|
@@ -20713,7 +20898,7 @@ async function runCli({ start }) {
|
|
|
20713
20898
|
if (!options.quiet) logger.info(`Wrote ${snippetPath}`);
|
|
20714
20899
|
continue;
|
|
20715
20900
|
}
|
|
20716
|
-
(0,
|
|
20901
|
+
(0, import_node_fs40.writeFileSync)(snippetPath, generated, "utf8");
|
|
20717
20902
|
if (!options.quiet) logger.info(`Wrote ${snippetPath}`);
|
|
20718
20903
|
}
|
|
20719
20904
|
if (options.baseline) {
|
|
@@ -20730,7 +20915,7 @@ async function runCli({ start }) {
|
|
|
20730
20915
|
});
|
|
20731
20916
|
program.command("install").description("install the git pre-commit hook").action(async (_cmdOptions, command) => {
|
|
20732
20917
|
const options = command.optsWithGlobals();
|
|
20733
|
-
const cwd = (0,
|
|
20918
|
+
const cwd = (0, import_node_path39.resolve)(options.workspace ?? process.cwd());
|
|
20734
20919
|
const root = getGitRoot(cwd);
|
|
20735
20920
|
if (!root) {
|
|
20736
20921
|
logger.error("Not a Git repository. Run `git init` first, or remove --staged from your command.");
|
|
@@ -20744,7 +20929,7 @@ async function runCli({ start }) {
|
|
|
20744
20929
|
});
|
|
20745
20930
|
program.command("uninstall").description("uninstall the git pre-commit hook").action(async (_cmdOptions, command) => {
|
|
20746
20931
|
const options = command.optsWithGlobals();
|
|
20747
|
-
const cwd = (0,
|
|
20932
|
+
const cwd = (0, import_node_path39.resolve)(options.workspace ?? process.cwd());
|
|
20748
20933
|
const root = getGitRoot(cwd);
|
|
20749
20934
|
if (!root) {
|
|
20750
20935
|
logger.error("Not a Git repository. Run `git init` first, or remove --staged from your command.");
|
|
@@ -20765,7 +20950,7 @@ async function runCli({ start }) {
|
|
|
20765
20950
|
program.command("suggest").description("print remediation advice").action(async (_cmdOptions, command) => {
|
|
20766
20951
|
const options = command.optsWithGlobals();
|
|
20767
20952
|
const { report } = await runScan(options);
|
|
20768
|
-
const cwd = (0,
|
|
20953
|
+
const cwd = (0, import_node_path39.resolve)(options.workspace ?? process.cwd());
|
|
20769
20954
|
logger.info(formatAdvice(report));
|
|
20770
20955
|
const diff = formatUnifiedDiff(report, cwd);
|
|
20771
20956
|
if (diff) logger.info(diff);
|
|
@@ -20773,7 +20958,7 @@ async function runCli({ start }) {
|
|
|
20773
20958
|
});
|
|
20774
20959
|
program.command("flywheel").description("summarize aggregated scan telemetry").option("--format <pretty|json>", "output format", "pretty").option("--export <path>", "write summary as JSON to <path>").action(async (cmdOptions, command) => {
|
|
20775
20960
|
const options = command.optsWithGlobals();
|
|
20776
|
-
const cwd = (0,
|
|
20961
|
+
const cwd = (0, import_node_path39.resolve)(options.workspace ?? process.cwd());
|
|
20777
20962
|
const payloads = readTelemetry(cwd);
|
|
20778
20963
|
if (payloads.length === 0) {
|
|
20779
20964
|
logger.info("No flywheel telemetry found. Run a scan first.");
|
|
@@ -20781,9 +20966,9 @@ async function runCli({ start }) {
|
|
|
20781
20966
|
}
|
|
20782
20967
|
const summary = summarizeTelemetry(payloads);
|
|
20783
20968
|
if (cmdOptions.export) {
|
|
20784
|
-
const exportPath = (0,
|
|
20785
|
-
(0,
|
|
20786
|
-
(0,
|
|
20969
|
+
const exportPath = (0, import_node_path39.resolve)(cmdOptions.export);
|
|
20970
|
+
(0, import_node_fs40.mkdirSync)((0, import_node_path39.dirname)(exportPath), { recursive: true });
|
|
20971
|
+
(0, import_node_fs40.writeFileSync)(exportPath, JSON.stringify(summary, null, 2), "utf-8");
|
|
20787
20972
|
logger.info(`Wrote flywheel summary to ${exportPath}`);
|
|
20788
20973
|
process.exit(0);
|
|
20789
20974
|
}
|
|
@@ -20806,7 +20991,7 @@ async function runCli({ start }) {
|
|
|
20806
20991
|
logger.error("--heatmap and --suggest can't be used together. Pick one: a heatmap of severity, or text advice.");
|
|
20807
20992
|
process.exit(2);
|
|
20808
20993
|
}
|
|
20809
|
-
const cwd = (0,
|
|
20994
|
+
const cwd = (0, import_node_path39.resolve)(options.workspace ?? process.cwd());
|
|
20810
20995
|
if (options.trend !== void 0) {
|
|
20811
20996
|
const runs = readRuns(cwd);
|
|
20812
20997
|
if (runs.length === 0) {
|
|
@@ -20839,7 +21024,7 @@ async function runCli({ start }) {
|
|
|
20839
21024
|
const scanElapsed = Math.round(import_node_perf_hooks.performance.now() - scanStart);
|
|
20840
21025
|
const totalElapsed = Math.round(import_node_perf_hooks.performance.now() - start);
|
|
20841
21026
|
if (options.baseline) {
|
|
20842
|
-
const cwd2 = (0,
|
|
21027
|
+
const cwd2 = (0, import_node_path39.resolve)(options.workspace ?? process.cwd());
|
|
20843
21028
|
const configHash = hashConfig(config);
|
|
20844
21029
|
const gitHead = await getGitHead(cwd2) ?? "unknown";
|
|
20845
21030
|
const cache = buildBaselineCache(report, configHash, gitHead, cwd2);
|
|
@@ -20933,24 +21118,24 @@ async function runCli({ start }) {
|
|
|
20933
21118
|
framework: cmdOptions.framework,
|
|
20934
21119
|
componentType: cmdOptions.componentType,
|
|
20935
21120
|
provider,
|
|
20936
|
-
outputDir: (0,
|
|
21121
|
+
outputDir: (0, import_node_path39.resolve)(cmdOptions.outputDir),
|
|
20937
21122
|
temperature: cmdOptions.temperature
|
|
20938
21123
|
});
|
|
20939
21124
|
logger.info(`Generated ${samples.length} samples in ${cmdOptions.outputDir}`);
|
|
20940
21125
|
});
|
|
20941
21126
|
research.command("analyze").description("analyze generated samples and report coverage").requiredOption("--input-dir <path>", "directory with generated samples containing metadata.json").option("--output <path>", "analysis output path", ".slopbrick/flywheel/analysis.json").option("--config <path>", "slopbrick config path").option("--framework <name>", "framework multiplier to apply", "react").action(async (cmdOptions) => {
|
|
20942
21127
|
try {
|
|
20943
|
-
const metadataPath = (0,
|
|
20944
|
-
if (!(0,
|
|
21128
|
+
const metadataPath = (0, import_node_path39.resolve)(cmdOptions.inputDir, "metadata.json");
|
|
21129
|
+
if (!(0, import_node_fs40.existsSync)(metadataPath)) {
|
|
20945
21130
|
logger.error(`No metadata.json found in ${cmdOptions.inputDir}`);
|
|
20946
21131
|
process.exit(2);
|
|
20947
21132
|
}
|
|
20948
|
-
const samples = JSON.parse((0,
|
|
21133
|
+
const samples = JSON.parse((0, import_node_fs40.readFileSync)(metadataPath, "utf8"));
|
|
20949
21134
|
const config = cmdOptions.config ? await loadConfig(cmdOptions.config) : { ...DEFAULT_CONFIG, framework: cmdOptions.framework };
|
|
20950
21135
|
const analysis = await analyzeSamples(samples, config);
|
|
20951
|
-
const outputPath = (0,
|
|
20952
|
-
(0,
|
|
20953
|
-
(0,
|
|
21136
|
+
const outputPath = (0, import_node_path39.resolve)(cmdOptions.output);
|
|
21137
|
+
(0, import_node_fs40.mkdirSync)((0, import_node_path39.dirname)(outputPath), { recursive: true });
|
|
21138
|
+
(0, import_node_fs40.writeFileSync)(outputPath, JSON.stringify(analysis, null, 2), "utf8");
|
|
20954
21139
|
logger.info(`Analyzed ${analysis.summary.total} samples; coverage: ${analysis.summary.coverage}%`);
|
|
20955
21140
|
logger.info(`Wrote analysis to ${outputPath}`);
|
|
20956
21141
|
} catch (error) {
|
|
@@ -20960,12 +21145,12 @@ async function runCli({ start }) {
|
|
|
20960
21145
|
});
|
|
20961
21146
|
research.command("candidates").description("extract patterns from generated samples and emit candidate rules").requiredOption("--input-dir <path>", "directory with generated samples containing metadata.json").option("--output <path>", "output path", ".slopbrick/flywheel/rule-candidates.json").option("--config <path>", "slopbrick config path").option("--framework <name>", "framework multiplier to apply", "react").option("--min-frequency <n>", "minimum cluster frequency", parseCount, 2).option("--include-covered", "include samples already covered by AI-specific rules").action(async (cmdOptions) => {
|
|
20962
21147
|
try {
|
|
20963
|
-
const metadataPath = (0,
|
|
20964
|
-
if (!(0,
|
|
21148
|
+
const metadataPath = (0, import_node_path39.resolve)(cmdOptions.inputDir, "metadata.json");
|
|
21149
|
+
if (!(0, import_node_fs40.existsSync)(metadataPath)) {
|
|
20965
21150
|
logger.error(`No metadata.json found in ${cmdOptions.inputDir}`);
|
|
20966
21151
|
process.exit(2);
|
|
20967
21152
|
}
|
|
20968
|
-
const samples = JSON.parse((0,
|
|
21153
|
+
const samples = JSON.parse((0, import_node_fs40.readFileSync)(metadataPath, "utf8"));
|
|
20969
21154
|
const config = cmdOptions.config ? await loadConfig(cmdOptions.config) : { ...DEFAULT_CONFIG, framework: cmdOptions.framework };
|
|
20970
21155
|
const analysis = await analyzeSamples(samples, config);
|
|
20971
21156
|
const extraction = extractAndCluster(analysis.samples, {
|
|
@@ -20975,8 +21160,8 @@ async function runCli({ start }) {
|
|
|
20975
21160
|
const candidates = clustersToCandidates(extraction.clusters, {
|
|
20976
21161
|
minFrequency: cmdOptions.minFrequency
|
|
20977
21162
|
});
|
|
20978
|
-
const outputPath = (0,
|
|
20979
|
-
(0,
|
|
21163
|
+
const outputPath = (0, import_node_path39.resolve)(cmdOptions.output);
|
|
21164
|
+
(0, import_node_fs40.mkdirSync)((0, import_node_path39.dirname)(outputPath), { recursive: true });
|
|
20980
21165
|
const payload = {
|
|
20981
21166
|
generatedAt: (/* @__PURE__ */ new Date()).toISOString(),
|
|
20982
21167
|
sampleCount: analysis.summary.total,
|
|
@@ -20984,7 +21169,7 @@ async function runCli({ start }) {
|
|
|
20984
21169
|
fingerprintCount: extraction.total,
|
|
20985
21170
|
candidates
|
|
20986
21171
|
};
|
|
20987
|
-
(0,
|
|
21172
|
+
(0, import_node_fs40.writeFileSync)(outputPath, JSON.stringify(payload, null, 2), "utf8");
|
|
20988
21173
|
logger.info(`Extracted ${extraction.total} fingerprints across ${analysis.summary.total} samples`);
|
|
20989
21174
|
logger.info(`Wrote ${candidates.length} candidate rule(s) to ${outputPath}`);
|
|
20990
21175
|
} catch (error) {
|
|
@@ -21001,9 +21186,9 @@ async function runCli({ start }) {
|
|
|
21001
21186
|
positiveLimit: cmdOptions.positiveLimit,
|
|
21002
21187
|
negativeLimit: cmdOptions.negativeLimit
|
|
21003
21188
|
});
|
|
21004
|
-
const outputPath = cmdOptions.output ? (0,
|
|
21005
|
-
(0,
|
|
21006
|
-
(0,
|
|
21189
|
+
const outputPath = cmdOptions.output ? (0, import_node_path39.resolve)(cwd, cmdOptions.output) : (0, import_node_path39.resolve)(cwd, "corpus", "calibration-empirical.md");
|
|
21190
|
+
(0, import_node_fs40.mkdirSync)((0, import_node_path39.dirname)(outputPath), { recursive: true });
|
|
21191
|
+
(0, import_node_fs40.writeFileSync)(outputPath, reportToMarkdown(report), "utf8");
|
|
21007
21192
|
logger.info(
|
|
21008
21193
|
"Calibrated " + report.rules.length + " rules across " + report.positiveFileCount + " positive + " + report.negativeFileCount + " negative files."
|
|
21009
21194
|
);
|
|
@@ -21041,7 +21226,7 @@ async function runCli({ start }) {
|
|
|
21041
21226
|
const options = command.optsWithGlobals();
|
|
21042
21227
|
const rawFormat = options.format ?? cmdOptions.format ?? "pretty";
|
|
21043
21228
|
const format = rawFormat === "json" || rawFormat === "pretty" ? rawFormat : "pretty";
|
|
21044
|
-
const cwd = (0,
|
|
21229
|
+
const cwd = (0, import_node_path39.resolve)(options.workspace ?? process.cwd());
|
|
21045
21230
|
const { config } = await runScan({ ...options, workspace: cwd });
|
|
21046
21231
|
const result = await runDrift(cwd, config, { maxFiles: cmdOptions.maxFiles });
|
|
21047
21232
|
logger.info(formatDrift(result, { json: format === "json" }));
|
|
@@ -21058,7 +21243,7 @@ async function runCli({ start }) {
|
|
|
21058
21243
|
async (cmdOptions, command) => {
|
|
21059
21244
|
try {
|
|
21060
21245
|
const options = command.optsWithGlobals();
|
|
21061
|
-
const cwd = (0,
|
|
21246
|
+
const cwd = (0, import_node_path39.resolve)(options.workspace ?? process.cwd());
|
|
21062
21247
|
const rawFormat = options.format ?? cmdOptions.format ?? "text";
|
|
21063
21248
|
const format = rawFormat === "json" || rawFormat === "markdown" || rawFormat === "text" ? rawFormat : "text";
|
|
21064
21249
|
const { config } = await runScan({ ...options, workspace: cwd });
|
|
@@ -21085,7 +21270,7 @@ async function runCli({ start }) {
|
|
|
21085
21270
|
const options = command.optsWithGlobals();
|
|
21086
21271
|
const rawFormat = options.format ?? cmdOptions.format ?? "pretty";
|
|
21087
21272
|
const format = rawFormat === "json" || rawFormat === "pretty" ? rawFormat : "pretty";
|
|
21088
|
-
const cwd = (0,
|
|
21273
|
+
const cwd = (0, import_node_path39.resolve)(options.workspace ?? process.cwd());
|
|
21089
21274
|
const { report } = await runScan({ ...options, workspace: cwd });
|
|
21090
21275
|
const securityIssues = report.issues.filter((i) => i.category === "security");
|
|
21091
21276
|
const { risk, findings } = computeAiSecurityRisk(securityIssues);
|
|
@@ -21136,7 +21321,7 @@ async function runCli({ start }) {
|
|
|
21136
21321
|
const options = command.optsWithGlobals();
|
|
21137
21322
|
const rawFormat = options.format ?? cmdOptions.format ?? "pretty";
|
|
21138
21323
|
const format = rawFormat === "json" || rawFormat === "pretty" ? rawFormat : "pretty";
|
|
21139
|
-
const cwd = (0,
|
|
21324
|
+
const cwd = (0, import_node_path39.resolve)(options.workspace ?? process.cwd());
|
|
21140
21325
|
const { config } = await runScan({ ...options, workspace: cwd });
|
|
21141
21326
|
const { result } = await runTestScan(cwd, config, { strict: options.strict });
|
|
21142
21327
|
logger.info(formatTestReport(result, { json: format === "json" }));
|
|
@@ -21155,7 +21340,7 @@ async function runCli({ start }) {
|
|
|
21155
21340
|
const options = command.optsWithGlobals();
|
|
21156
21341
|
const rawFormat = options.format ?? cmdOptions.format ?? "pretty";
|
|
21157
21342
|
const format = rawFormat === "json" || rawFormat === "pretty" ? rawFormat : "pretty";
|
|
21158
|
-
const cwd = (0,
|
|
21343
|
+
const cwd = (0, import_node_path39.resolve)(options.workspace ?? process.cwd());
|
|
21159
21344
|
const { config } = await runScan({ ...options, workspace: cwd });
|
|
21160
21345
|
const score = await buildArchitectureScore(cwd, config, cmdOptions.maxFiles);
|
|
21161
21346
|
const out = format === "json" ? JSON.stringify(score, null, 2) : formatArchitectureScore(score);
|
|
@@ -21175,7 +21360,7 @@ async function runCli({ start }) {
|
|
|
21175
21360
|
const options = command.optsWithGlobals();
|
|
21176
21361
|
const rawFormat = options.format ?? cmdOptions.format ?? "text";
|
|
21177
21362
|
const format = rawFormat === "json" || rawFormat === "markdown" || rawFormat === "text" ? rawFormat : "text";
|
|
21178
|
-
const cwd = (0,
|
|
21363
|
+
const cwd = (0, import_node_path39.resolve)(options.workspace ?? process.cwd());
|
|
21179
21364
|
const { config } = await runScan({ ...options, workspace: cwd });
|
|
21180
21365
|
const result = await runBusinessLogicScan(cwd, config, {
|
|
21181
21366
|
maxFiles: cmdOptions.maxFiles
|
|
@@ -21197,7 +21382,7 @@ async function runCli({ start }) {
|
|
|
21197
21382
|
const rawFormat = options.format ?? cmdOptions.format ?? "text";
|
|
21198
21383
|
const format = rawFormat === "json" || rawFormat === "text" ? rawFormat : "text";
|
|
21199
21384
|
const strict = options.strict ?? cmdOptions.strict ?? false;
|
|
21200
|
-
const cwd = (0,
|
|
21385
|
+
const cwd = (0, import_node_path39.resolve)(options.workspace ?? process.cwd());
|
|
21201
21386
|
const { config } = await runScan({ ...options, workspace: cwd });
|
|
21202
21387
|
const result = await runMaintenanceCostScan(cwd, config, {
|
|
21203
21388
|
maxFiles: cmdOptions.maxFiles,
|
|
@@ -21220,7 +21405,7 @@ async function runCli({ start }) {
|
|
|
21220
21405
|
const rawFormat = options.format ?? cmdOptions.format ?? "text";
|
|
21221
21406
|
const format = rawFormat === "json" || rawFormat === "markdown" || rawFormat === "text" ? rawFormat : "text";
|
|
21222
21407
|
const strict = options.strict ?? cmdOptions.strict ?? false;
|
|
21223
|
-
const cwd = (0,
|
|
21408
|
+
const cwd = (0, import_node_path39.resolve)(options.workspace ?? process.cwd());
|
|
21224
21409
|
const { config } = await runScan({ ...options, workspace: cwd });
|
|
21225
21410
|
const result = await runDocsScan(cwd, config, {
|
|
21226
21411
|
maxDocFiles: cmdOptions.maxFiles,
|
|
@@ -21248,7 +21433,7 @@ async function runCli({ start }) {
|
|
|
21248
21433
|
const rawFormat = options.format ?? cmdOptions.format ?? "text";
|
|
21249
21434
|
const format = rawFormat === "json" || rawFormat === "markdown" || rawFormat === "text" ? rawFormat : "text";
|
|
21250
21435
|
const strict = options.strict ?? cmdOptions.strict ?? false;
|
|
21251
|
-
const cwd = (0,
|
|
21436
|
+
const cwd = (0, import_node_path39.resolve)(options.workspace ?? process.cwd());
|
|
21252
21437
|
const { config } = await runScan({ ...options, workspace: cwd });
|
|
21253
21438
|
const result = await runDbScan(cwd, config, {
|
|
21254
21439
|
maxFiles: cmdOptions.maxFiles,
|
|
@@ -21275,7 +21460,7 @@ async function runCli({ start }) {
|
|
|
21275
21460
|
const options = command.optsWithGlobals();
|
|
21276
21461
|
const rawFormat = options.format ?? cmdOptions.format ?? "text";
|
|
21277
21462
|
const format = rawFormat === "json" || rawFormat === "markdown" || rawFormat === "text" ? rawFormat : "text";
|
|
21278
|
-
const cwd = (0,
|
|
21463
|
+
const cwd = (0, import_node_path39.resolve)(options.workspace ?? process.cwd());
|
|
21279
21464
|
const { config } = await runScan({ ...options, workspace: cwd });
|
|
21280
21465
|
const result = await runPatternsScan(cwd, config, {
|
|
21281
21466
|
maxFiles: cmdOptions.maxFiles,
|
|
@@ -21299,6 +21484,27 @@ async function runCli({ start }) {
|
|
|
21299
21484
|
const exitCode = await runDoctor(process.cwd());
|
|
21300
21485
|
if (exitCode !== 0) process.exit(exitCode);
|
|
21301
21486
|
});
|
|
21487
|
+
program.command("migrate").description(
|
|
21488
|
+
"Migrate from slop-audit v0.10.x (.slop-audit/) to slopbrick v0.11.0+ (.slopbrick/). Renames artifact dir + cache + config file + bumps schema to v2 + updates .gitignore. Idempotent. Pass --dry-run to preview."
|
|
21489
|
+
).option("--dry-run", "print the planned changes without touching the filesystem").option("--force", "overwrite .slopbrick/ if both old and new artifacts exist").option("--workspace <path>", "workspace directory", process.cwd()).option("--format <pretty|json>", "output format", "pretty").action(
|
|
21490
|
+
(cmdOptions, command) => {
|
|
21491
|
+
const globals = command.optsWithGlobals();
|
|
21492
|
+
const format = (cmdOptions.format ?? globals.format) === "json" ? "json" : "pretty";
|
|
21493
|
+
const cwd = (0, import_node_path39.resolve)(cmdOptions.workspace ?? process.cwd());
|
|
21494
|
+
const { runMigrate: runMigrate2, formatMigrate: formatMigrate2 } = (init_migrate(), __toCommonJS(migrate_exports));
|
|
21495
|
+
const result = runMigrate2({
|
|
21496
|
+
workspace: cwd,
|
|
21497
|
+
dryRun: cmdOptions.dryRun,
|
|
21498
|
+
force: cmdOptions.force
|
|
21499
|
+
});
|
|
21500
|
+
if (format === "json") {
|
|
21501
|
+
logger.info(JSON.stringify(result, null, 2));
|
|
21502
|
+
} else {
|
|
21503
|
+
logger.info(formatMigrate2(result));
|
|
21504
|
+
}
|
|
21505
|
+
process.exit(result.ok ? 0 : 1);
|
|
21506
|
+
}
|
|
21507
|
+
);
|
|
21302
21508
|
program.command("rules").description("list all built-in rules with their categories, severities, and descriptions").option("--category <name>", "filter to a single category (visual, typo, layout, etc.)").option("--ai-only", "only show AI-specific rules").option("--json", "emit JSON instead of a pretty table").option("--show-signal-strength", "print per-rule precision/recall table").action((cmdOptions, command) => {
|
|
21303
21509
|
const globals = command.optsWithGlobals();
|
|
21304
21510
|
const wantJson = Boolean(cmdOptions.json || globals.json);
|
|
@@ -21385,13 +21591,13 @@ async function runCli({ start }) {
|
|
|
21385
21591
|
if ("error" in result) process.exit(2);
|
|
21386
21592
|
});
|
|
21387
21593
|
program.command("validate-config [path]").description("Statically validate a slopbrick.config.mjs without scanning").action(async (configPath) => {
|
|
21388
|
-
const path = configPath ? (0,
|
|
21389
|
-
if (!(0,
|
|
21594
|
+
const path = configPath ? (0, import_node_path39.resolve)(configPath) : (0, import_node_path39.resolve)(process.cwd(), "slopbrick.config.mjs");
|
|
21595
|
+
if (!(0, import_node_fs40.existsSync)(path)) {
|
|
21390
21596
|
logger.error(`Error: config file not found: ${path}`);
|
|
21391
21597
|
process.exit(2);
|
|
21392
21598
|
}
|
|
21393
21599
|
try {
|
|
21394
|
-
const mod = (0,
|
|
21600
|
+
const mod = (0, import_node_path39.extname)(path) === ".cjs" ? require(path) : await import(path);
|
|
21395
21601
|
const userConfig = mod.default ?? mod;
|
|
21396
21602
|
const result = validateConfig(userConfig);
|
|
21397
21603
|
if (result.errors.length === 0) {
|
|
@@ -21462,7 +21668,6 @@ ${formatMarkdown3(result.report)}`);
|
|
|
21462
21668
|
init_threshold();
|
|
21463
21669
|
init_render();
|
|
21464
21670
|
init_find_similar();
|
|
21465
|
-
var import_core6 = require("@usebrick/core");
|
|
21466
21671
|
process.on("uncaughtException", (err) => {
|
|
21467
21672
|
const { logger: logger6 } = (init_logger(), __toCommonJS(logger_exports));
|
|
21468
21673
|
logger6.error(`Unexpected error: ${err.message}`);
|
|
@@ -21471,17 +21676,11 @@ process.on("uncaughtException", (err) => {
|
|
|
21471
21676
|
// Annotate the CommonJS export names for ESM import in node:
|
|
21472
21677
|
0 && (module.exports = {
|
|
21473
21678
|
AI_SECURITY_NUMERIC,
|
|
21474
|
-
CACHE_FILENAME,
|
|
21475
|
-
CONSTITUTION_FILENAME,
|
|
21476
21679
|
DEFAULT_CONFIG,
|
|
21477
|
-
INVENTORY_FILENAME,
|
|
21478
|
-
MEMORY_SCHEMA_VERSION,
|
|
21479
21680
|
REPOSITORY_HEALTH_WEIGHTS,
|
|
21480
21681
|
VERSION,
|
|
21481
21682
|
baselineStatusMessage,
|
|
21482
|
-
cachePath,
|
|
21483
21683
|
colorForSlop,
|
|
21484
|
-
constitutionPath,
|
|
21485
21684
|
extractSignatures,
|
|
21486
21685
|
failedThresholdCount,
|
|
21487
21686
|
filterByDisabledDirectives,
|
|
@@ -21491,22 +21690,10 @@ process.on("uncaughtException", (err) => {
|
|
|
21491
21690
|
formatBadge,
|
|
21492
21691
|
formatReportFromFile,
|
|
21493
21692
|
formatSparkline,
|
|
21494
|
-
invalidateFile,
|
|
21495
|
-
inventoryPath,
|
|
21496
|
-
isComponentFingerprint,
|
|
21497
|
-
isConstitutionFile,
|
|
21498
|
-
isFileMtimeEntry,
|
|
21499
|
-
isInventoryFile,
|
|
21500
|
-
isInventoryFresh,
|
|
21501
|
-
isMemoryPattern,
|
|
21502
21693
|
loadConfig,
|
|
21503
|
-
loadConstitution,
|
|
21504
|
-
loadInventory,
|
|
21505
21694
|
readReportFile,
|
|
21506
21695
|
runCli,
|
|
21507
21696
|
runInitWizard,
|
|
21508
|
-
saveConstitution,
|
|
21509
|
-
saveInventory,
|
|
21510
21697
|
scanProject,
|
|
21511
21698
|
serializeConfig,
|
|
21512
21699
|
signatureSimilarity,
|