slopbrick 0.11.1 → 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.js CHANGED
@@ -30,7 +30,7 @@ var VERSION, AI_SECURITY_NUMERIC, REPOSITORY_HEALTH_WEIGHTS;
30
30
  var init_types = __esm({
31
31
  "src/types.ts"() {
32
32
  "use strict";
33
- VERSION = "0.11.1";
33
+ VERSION = "0.11.2";
34
34
  AI_SECURITY_NUMERIC = {
35
35
  low: 100,
36
36
  medium: 75,
@@ -3482,7 +3482,7 @@ function discoverTestFiles(cwd) {
3482
3482
  }
3483
3483
  return found;
3484
3484
  }
3485
- function walk(dir, out, readdirSync6, statSync7) {
3485
+ function walk(dir, out, readdirSync6, statSync8) {
3486
3486
  let entries;
3487
3487
  try {
3488
3488
  entries = readdirSync6(dir);
@@ -3494,12 +3494,12 @@ function walk(dir, out, readdirSync6, statSync7) {
3494
3494
  const full = `${dir}/${entry}`;
3495
3495
  let stat;
3496
3496
  try {
3497
- stat = statSync7(full);
3497
+ stat = statSync8(full);
3498
3498
  } catch {
3499
3499
  continue;
3500
3500
  }
3501
3501
  if (stat.isDirectory()) {
3502
- walk(full, out, readdirSync6, statSync7);
3502
+ walk(full, out, readdirSync6, statSync8);
3503
3503
  } else if (stat.isFile()) {
3504
3504
  if (/\.(test|spec)\.[jt]sx?$/.test(entry) || /\.stories\.[jt]sx?$/.test(entry)) {
3505
3505
  out.push(full);
@@ -9408,8 +9408,8 @@ function hasExtendedSibling(filePath) {
9408
9408
  const base = basename(filePath);
9409
9409
  for (const ext of SOURCE_EXTENSIONS) {
9410
9410
  try {
9411
- const { statSync: statSync7 } = __require("fs");
9412
- statSync7(join7(dir, base + ext));
9411
+ const { statSync: statSync8 } = __require("fs");
9412
+ statSync8(join7(dir, base + ext));
9413
9413
  return true;
9414
9414
  } catch {
9415
9415
  }
@@ -9566,8 +9566,8 @@ var init_git = __esm({
9566
9566
  import { createHash as createHash2 } from "crypto";
9567
9567
  import { existsSync as existsSync8, readFileSync as readFileSync9, writeFileSync as writeFileSync2, renameSync, mkdirSync, unlinkSync } from "fs";
9568
9568
  import { dirname as dirname4, isAbsolute, resolve as resolve7 } from "path";
9569
- function loadCache(cachePath6) {
9570
- const abs = isAbsolute(cachePath6) ? cachePath6 : resolve7(process.cwd(), cachePath6);
9569
+ function loadCache(cachePath4) {
9570
+ const abs = isAbsolute(cachePath4) ? cachePath4 : resolve7(process.cwd(), cachePath4);
9571
9571
  if (!existsSync8(abs)) return void 0;
9572
9572
  try {
9573
9573
  const raw = readFileSync9(abs, "utf-8");
@@ -9578,8 +9578,8 @@ function loadCache(cachePath6) {
9578
9578
  return void 0;
9579
9579
  }
9580
9580
  }
9581
- function saveCache(cachePath6, cache) {
9582
- const abs = isAbsolute(cachePath6) ? cachePath6 : resolve7(process.cwd(), cachePath6);
9581
+ function saveCache(cachePath4, cache) {
9582
+ const abs = isAbsolute(cachePath4) ? cachePath4 : resolve7(process.cwd(), cachePath4);
9583
9583
  mkdirSync(dirname4(abs), { recursive: true });
9584
9584
  const tmp = abs + ".tmp";
9585
9585
  if (existsSync8(tmp)) {
@@ -12876,38 +12876,46 @@ var init_heatmap = __esm({
12876
12876
  }
12877
12877
  });
12878
12878
 
12879
+ // ../core/dist/index.js
12880
+ import { writeFileSync as writeFileSync5, renameSync as renameSync2, existsSync as existsSync12, readFileSync as readFileSync15, statSync as statSync5, mkdirSync as mkdirSync3 } from "fs";
12881
+ import { join as join10, dirname as dirname6 } from "path";
12882
+ function inventoryPath(workspaceDir) {
12883
+ return join10(workspaceDir, ".slopbrick", INVENTORY_FILENAME);
12884
+ }
12885
+ function constitutionPath(workspaceDir) {
12886
+ return join10(workspaceDir, ".slopbrick", CONSTITUTION_FILENAME);
12887
+ }
12888
+ function ensureSlopbrickDir(workspaceDir) {
12889
+ mkdirSync3(join10(workspaceDir, ".slopbrick"), { recursive: true });
12890
+ }
12891
+ function writeJsonAtomic(filePath, payload) {
12892
+ ensureSlopbrickDir(dirname6(filePath));
12893
+ const tmp = `${filePath}.tmp`;
12894
+ writeFileSync5(tmp, JSON.stringify(payload, null, 2), "utf-8");
12895
+ renameSync2(tmp, filePath);
12896
+ }
12897
+ function saveInventory(workspaceDir, inventory) {
12898
+ writeJsonAtomic(inventoryPath(workspaceDir), inventory);
12899
+ }
12900
+ function saveConstitution(workspaceDir, constitution) {
12901
+ writeJsonAtomic(constitutionPath(workspaceDir), constitution);
12902
+ }
12903
+ var MEMORY_SCHEMA_VERSION, INVENTORY_FILENAME, CONSTITUTION_FILENAME;
12904
+ var init_dist = __esm({
12905
+ "../core/dist/index.js"() {
12906
+ "use strict";
12907
+ MEMORY_SCHEMA_VERSION = "2";
12908
+ INVENTORY_FILENAME = "inventory.json";
12909
+ CONSTITUTION_FILENAME = "constitution.json";
12910
+ }
12911
+ });
12912
+
12879
12913
  // src/engine/memory.ts
12880
- import { existsSync as existsSync12, mkdirSync as mkdirSync3, readFileSync as readFileSync15, writeFileSync as writeFileSync5 } from "fs";
12881
- import { dirname as dirname6, join as join10 } from "path";
12914
+ import { existsSync as existsSync13, mkdirSync as mkdirSync4, readFileSync as readFileSync16, writeFileSync as writeFileSync6 } from "fs";
12915
+ import { dirname as dirname7, join as join11 } from "path";
12882
12916
  import { createHash as createHash6 } from "crypto";
12883
- import {
12884
- MEMORY_SCHEMA_VERSION,
12885
- writeCacheFromInventory
12886
- } from "@usebrick/core";
12887
- import {
12888
- MEMORY_SCHEMA_VERSION as MEMORY_SCHEMA_VERSION2,
12889
- isMemoryPattern as isMemoryPattern2,
12890
- isComponentFingerprint as isComponentFingerprint2,
12891
- isInventoryFile as isInventoryFile2,
12892
- isConstitutionFile as isConstitutionFile2,
12893
- isFileMtimeEntry as isFileMtimeEntry2,
12894
- inventoryPath as inventoryPath2,
12895
- constitutionPath as constitutionPath2,
12896
- cachePath as cachePath3,
12897
- loadInventory as loadInventory2,
12898
- loadConstitution as loadConstitution2,
12899
- saveConstitution as saveConstitution2,
12900
- readCache as readCache3,
12901
- isInventoryFresh as isInventoryFresh2,
12902
- invalidateFile as invalidateFile2
12903
- } from "@usebrick/core";
12904
- async function saveInventory(workspaceDir, inventory, computeHash = computeFileHash) {
12905
- const { saveInventory: coreSave } = await import("@usebrick/core");
12906
- coreSave(workspaceDir, inventory);
12907
- writeCacheFromInventory(workspaceDir, inventory, computeHash);
12908
- }
12909
12917
  function telemetryPath(cwd) {
12910
- return join10(cwd, TELEMETRY_FILE);
12918
+ return join11(cwd, TELEMETRY_FILE);
12911
12919
  }
12912
12920
  function isSlopAuditRun(value) {
12913
12921
  if (typeof value !== "object" || value === null) return false;
@@ -12916,9 +12924,9 @@ function isSlopAuditRun(value) {
12916
12924
  }
12917
12925
  function readRuns(cwd) {
12918
12926
  const path = telemetryPath(cwd);
12919
- if (!existsSync12(path)) return [];
12927
+ if (!existsSync13(path)) return [];
12920
12928
  try {
12921
- const raw = readFileSync15(path, "utf-8");
12929
+ const raw = readFileSync16(path, "utf-8");
12922
12930
  const parsed = JSON.parse(raw);
12923
12931
  if (!Array.isArray(parsed)) return [];
12924
12932
  return parsed.filter(isSlopAuditRun);
@@ -12948,8 +12956,8 @@ function appendRun(cwd, report, thresholdExceeded2) {
12948
12956
  runs.splice(0, runs.length - MAX_RUNS);
12949
12957
  }
12950
12958
  const path = telemetryPath(cwd);
12951
- mkdirSync3(dirname6(path), { recursive: true });
12952
- writeFileSync5(path, JSON.stringify(runs, null, 2));
12959
+ mkdirSync4(dirname7(path), { recursive: true });
12960
+ writeFileSync6(path, JSON.stringify(runs, null, 2));
12953
12961
  return run2;
12954
12962
  }
12955
12963
  async function buildInventoryFromScan(scanResult, config, durationMs) {
@@ -13068,7 +13076,8 @@ var init_memory = __esm({
13068
13076
  init_types();
13069
13077
  init_patterns();
13070
13078
  init_cache_incremental();
13071
- TELEMETRY_FILE = join10(".slopbrick", "memory.json");
13079
+ init_dist();
13080
+ TELEMETRY_FILE = join11(".slopbrick", "memory.json");
13072
13081
  MAX_RUNS = 1e3;
13073
13082
  }
13074
13083
  });
@@ -13076,18 +13085,18 @@ var init_memory = __esm({
13076
13085
  // src/engine/telemetry.ts
13077
13086
  import {
13078
13087
  appendFileSync,
13079
- existsSync as existsSync13,
13080
- mkdirSync as mkdirSync4,
13081
- readFileSync as readFileSync16,
13088
+ existsSync as existsSync14,
13089
+ mkdirSync as mkdirSync5,
13090
+ readFileSync as readFileSync17,
13082
13091
  readdirSync as readdirSync5,
13083
- renameSync as renameSync2,
13092
+ renameSync as renameSync3,
13084
13093
  rmSync,
13085
- statSync as statSync5
13094
+ statSync as statSync6
13086
13095
  } from "fs";
13087
13096
  import { createHash as createHash7 } from "crypto";
13088
- import { dirname as dirname7, join as join11, relative as relative7 } from "path";
13097
+ import { dirname as dirname8, join as join12, relative as relative7 } from "path";
13089
13098
  function telemetryPath2(cwd) {
13090
- return join11(cwd, TELEMETRY_DIR, TELEMETRY_FILE2);
13099
+ return join12(cwd, TELEMETRY_DIR, TELEMETRY_FILE2);
13091
13100
  }
13092
13101
  function hashString(input) {
13093
13102
  return createHash7("sha256").update(input).digest("hex").slice(0, 16);
@@ -13140,33 +13149,33 @@ function isTelemetryFile(name) {
13140
13149
  }
13141
13150
  function rotateTelemetry(cwd) {
13142
13151
  const path = telemetryPath2(cwd);
13143
- if (!existsSync13(path)) {
13152
+ if (!existsSync14(path)) {
13144
13153
  return;
13145
13154
  }
13146
- const stats = statSync5(path);
13155
+ const stats = statSync6(path);
13147
13156
  if (stats.size < MAX_TELEMETRY_BYTES) {
13148
13157
  return;
13149
13158
  }
13150
- const dir = dirname7(path);
13159
+ const dir = dirname8(path);
13151
13160
  const timestamp = (/* @__PURE__ */ new Date()).toISOString().replace(/[:.]/g, "-");
13152
- renameSync2(path, join11(dir, `scans-${timestamp}.jsonl`));
13153
- const rotated = readdirSync5(dir).filter(isTelemetryFile).map((name) => ({ name, mtime: statSync5(join11(dir, name)).mtimeMs })).sort((a, b) => a.mtime - b.mtime);
13161
+ renameSync3(path, join12(dir, `scans-${timestamp}.jsonl`));
13162
+ const rotated = readdirSync5(dir).filter(isTelemetryFile).map((name) => ({ name, mtime: statSync6(join12(dir, name)).mtimeMs })).sort((a, b) => a.mtime - b.mtime);
13154
13163
  while (rotated.length > MAX_ROTATED_FILES) {
13155
13164
  const oldest = rotated.shift();
13156
13165
  if (oldest) {
13157
- rmSync(join11(dir, oldest.name), { force: true });
13166
+ rmSync(join12(dir, oldest.name), { force: true });
13158
13167
  }
13159
13168
  }
13160
13169
  }
13161
13170
  function readTelemetry(cwd) {
13162
- const dir = join11(cwd, TELEMETRY_DIR);
13163
- if (!existsSync13(dir)) {
13171
+ const dir = join12(cwd, TELEMETRY_DIR);
13172
+ if (!existsSync14(dir)) {
13164
13173
  return [];
13165
13174
  }
13166
- const files = readdirSync5(dir).filter(isTelemetryFile).sort().map((name) => join11(dir, name));
13175
+ const files = readdirSync5(dir).filter(isTelemetryFile).sort().map((name) => join12(dir, name));
13167
13176
  const payloads = [];
13168
13177
  for (const file of files) {
13169
- const raw = readFileSync16(file, "utf-8");
13178
+ const raw = readFileSync17(file, "utf-8");
13170
13179
  for (const line of raw.split("\n")) {
13171
13180
  const trimmed = line.trim();
13172
13181
  if (!trimmed) continue;
@@ -13198,9 +13207,9 @@ function recordTelemetry(cwd, report, results, config) {
13198
13207
  files: buildFileRecords(cwd, report, results)
13199
13208
  };
13200
13209
  const path = telemetryPath2(cwd);
13201
- const dir = dirname7(path);
13202
- if (!existsSync13(dir)) {
13203
- mkdirSync4(dir, { recursive: true });
13210
+ const dir = dirname8(path);
13211
+ if (!existsSync14(dir)) {
13212
+ mkdirSync5(dir, { recursive: true });
13204
13213
  }
13205
13214
  rotateTelemetry(cwd);
13206
13215
  appendFileSync(path, JSON.stringify(payload) + "\n", "utf-8");
@@ -13210,7 +13219,7 @@ var TELEMETRY_DIR, TELEMETRY_FILE2, MAX_TELEMETRY_BYTES, MAX_ROTATED_FILES;
13210
13219
  var init_telemetry = __esm({
13211
13220
  "src/engine/telemetry.ts"() {
13212
13221
  "use strict";
13213
- TELEMETRY_DIR = join11(".slopbrick", "flywheel");
13222
+ TELEMETRY_DIR = join12(".slopbrick", "flywheel");
13214
13223
  TELEMETRY_FILE2 = "scans.jsonl";
13215
13224
  MAX_TELEMETRY_BYTES = 10 * 1024 * 1024;
13216
13225
  MAX_ROTATED_FILES = 5;
@@ -13219,8 +13228,8 @@ var init_telemetry = __esm({
13219
13228
 
13220
13229
  // src/engine/flywheel.ts
13221
13230
  import { createHash as createHash8 } from "crypto";
13222
- import { existsSync as existsSync14, mkdirSync as mkdirSync5, readFileSync as readFileSync17, writeFileSync as writeFileSync6 } from "fs";
13223
- import { join as join12 } from "path";
13231
+ import { existsSync as existsSync15, mkdirSync as mkdirSync6, readFileSync as readFileSync18, writeFileSync as writeFileSync7 } from "fs";
13232
+ import { join as join13 } from "path";
13224
13233
  function severityBump(severity) {
13225
13234
  const order = ["low", "medium", "high"];
13226
13235
  const idx = order.indexOf(severity);
@@ -13321,30 +13330,30 @@ function migrateFlywheelState(state) {
13321
13330
  };
13322
13331
  }
13323
13332
  function loadFlywheelState(cwd) {
13324
- const path = join12(cwd, FLYWHEEL_DIR, STATE_FILE);
13325
- if (!existsSync14(path)) {
13333
+ const path = join13(cwd, FLYWHEEL_DIR, STATE_FILE);
13334
+ if (!existsSync15(path)) {
13326
13335
  return migrateFlywheelState({});
13327
13336
  }
13328
13337
  try {
13329
- const parsed = JSON.parse(readFileSync17(path, "utf-8"));
13338
+ const parsed = JSON.parse(readFileSync18(path, "utf-8"));
13330
13339
  return migrateFlywheelState(parsed);
13331
13340
  } catch {
13332
13341
  return migrateFlywheelState({});
13333
13342
  }
13334
13343
  }
13335
13344
  function loadResearchMetricsFromDisk(cwd) {
13336
- const flywheelDir = join12(cwd, FLYWHEEL_DIR);
13337
- const analysisPath = join12(flywheelDir, "analysis.json");
13338
- const candidatesPath = join12(flywheelDir, "rule-candidates.json");
13339
- const hasAnalysis = existsSync14(analysisPath);
13340
- const hasCandidates = existsSync14(candidatesPath);
13345
+ const flywheelDir = join13(cwd, FLYWHEEL_DIR);
13346
+ const analysisPath = join13(flywheelDir, "analysis.json");
13347
+ const candidatesPath = join13(flywheelDir, "rule-candidates.json");
13348
+ const hasAnalysis = existsSync15(analysisPath);
13349
+ const hasCandidates = existsSync15(candidatesPath);
13341
13350
  if (!hasAnalysis && !hasCandidates) return void 0;
13342
13351
  let generatedSampleCount = 0;
13343
13352
  let generatedRuleCoverage = 0;
13344
13353
  let candidateYield = 0;
13345
13354
  if (hasAnalysis) {
13346
13355
  try {
13347
- const raw = JSON.parse(readFileSync17(analysisPath, "utf8"));
13356
+ const raw = JSON.parse(readFileSync18(analysisPath, "utf8"));
13348
13357
  generatedSampleCount = raw.summary?.total ?? 0;
13349
13358
  generatedRuleCoverage = raw.summary?.coverage ?? 0;
13350
13359
  } catch {
@@ -13352,7 +13361,7 @@ function loadResearchMetricsFromDisk(cwd) {
13352
13361
  }
13353
13362
  if (hasCandidates) {
13354
13363
  try {
13355
- const raw = JSON.parse(readFileSync17(candidatesPath, "utf8"));
13364
+ const raw = JSON.parse(readFileSync18(candidatesPath, "utf8"));
13356
13365
  candidateYield = raw.candidates?.length ?? 0;
13357
13366
  } catch {
13358
13367
  }
@@ -13365,9 +13374,9 @@ function loadResearchMetricsFromDisk(cwd) {
13365
13374
  };
13366
13375
  }
13367
13376
  function saveFlywheelState(cwd, state) {
13368
- const dir = join12(cwd, FLYWHEEL_DIR);
13369
- if (!existsSync14(dir)) mkdirSync5(dir, { recursive: true });
13370
- writeFileSync6(join12(dir, STATE_FILE), JSON.stringify(state, null, 2));
13377
+ const dir = join13(cwd, FLYWHEEL_DIR);
13378
+ if (!existsSync15(dir)) mkdirSync6(dir, { recursive: true });
13379
+ writeFileSync7(join13(dir, STATE_FILE), JSON.stringify(state, null, 2));
13371
13380
  }
13372
13381
  function hashFile(filePath) {
13373
13382
  return createHash8("sha256").update(filePath).digest("hex").slice(0, 16);
@@ -13660,7 +13669,7 @@ var init_signal_strength2 = __esm({
13660
13669
  });
13661
13670
 
13662
13671
  // src/cli/tokens.ts
13663
- import { readFileSync as readFileSync18 } from "fs";
13672
+ import { readFileSync as readFileSync19 } from "fs";
13664
13673
  function parseDtcgTokens(raw) {
13665
13674
  let parsed;
13666
13675
  try {
@@ -13675,7 +13684,7 @@ function parseDtcgTokens(raw) {
13675
13684
  }
13676
13685
  function readDtcgTokensFile(path) {
13677
13686
  try {
13678
- const raw = readFileSync18(path, "utf-8");
13687
+ const raw = readFileSync19(path, "utf-8");
13679
13688
  return parseDtcgTokens(raw);
13680
13689
  } catch (error) {
13681
13690
  return { ok: false, error: `Cannot read ${path}: ${error.message}` };
@@ -14115,8 +14124,8 @@ __export(doc_freshness_exports, {
14115
14124
  extractInlineCodeSpans: () => extractInlineCodeSpans,
14116
14125
  extractMarkdownLinks: () => extractMarkdownLinks
14117
14126
  });
14118
- import { readFileSync as readFileSync19, existsSync as existsSync15 } from "fs";
14119
- import { join as join13, dirname as dirname9, relative as relative8 } from "path";
14127
+ import { readFileSync as readFileSync20, existsSync as existsSync16 } from "fs";
14128
+ import { join as join14, dirname as dirname10, relative as relative8 } from "path";
14120
14129
  import { globby as globby2 } from "globby";
14121
14130
  function extractInlineCodeSpans(source) {
14122
14131
  const hits = [];
@@ -14180,10 +14189,10 @@ function extractMarkdownLinks(source) {
14180
14189
  }
14181
14190
  function declaredPackages(cwd) {
14182
14191
  const out = /* @__PURE__ */ new Set();
14183
- const pkgPath = join13(cwd, "package.json");
14184
- if (!existsSync15(pkgPath)) return out;
14192
+ const pkgPath = join14(cwd, "package.json");
14193
+ if (!existsSync16(pkgPath)) return out;
14185
14194
  try {
14186
- const raw = readFileSync19(pkgPath, "utf-8");
14195
+ const raw = readFileSync20(pkgPath, "utf-8");
14187
14196
  const pkg = JSON.parse(raw);
14188
14197
  for (const k of ["dependencies", "devDependencies", "peerDependencies", "optionalDependencies"]) {
14189
14198
  const v = pkg[k];
@@ -14219,7 +14228,7 @@ async function extractExports(cwd, config, maxFiles = 500) {
14219
14228
  for (const abs of limited) {
14220
14229
  let source;
14221
14230
  try {
14222
- source = readFileSync19(abs, "utf-8");
14231
+ source = readFileSync20(abs, "utf-8");
14223
14232
  } catch {
14224
14233
  continue;
14225
14234
  }
@@ -14318,10 +14327,10 @@ function detectExpiredCodeExamples(source, relPath, cwd, packages) {
14318
14327
  const imports = extractImports(block.body);
14319
14328
  for (const imp of imports) {
14320
14329
  if (imp.startsWith(".") || imp.startsWith("/")) {
14321
- const docDir = dirname9(join13(cwd, relPath));
14322
- const candidate = join13(docDir, imp);
14330
+ const docDir = dirname10(join14(cwd, relPath));
14331
+ const candidate = join14(docDir, imp);
14323
14332
  const exts = ["", ".ts", ".tsx", ".js", ".jsx", "/index.ts", "/index.tsx", "/index.js", "/index.jsx"];
14324
- const found = exts.some((e) => existsSync15(candidate + e));
14333
+ const found = exts.some((e) => existsSync16(candidate + e));
14325
14334
  if (!found) {
14326
14335
  findings.push({
14327
14336
  ruleId: "docs/expired-code-example",
@@ -14360,7 +14369,7 @@ function detectExpiredCodeExamples(source, relPath, cwd, packages) {
14360
14369
  function detectBrokenLinks(source, relPath, cwd) {
14361
14370
  const findings = [];
14362
14371
  const links = extractMarkdownLinks(source);
14363
- const docDir = dirname9(join13(cwd, relPath));
14372
+ const docDir = dirname10(join14(cwd, relPath));
14364
14373
  for (const link of links) {
14365
14374
  const target = link.target;
14366
14375
  if (target.startsWith("http://") || target.startsWith("https://")) continue;
@@ -14368,8 +14377,8 @@ function detectBrokenLinks(source, relPath, cwd) {
14368
14377
  if (target.startsWith("#")) continue;
14369
14378
  if (target.startsWith("//")) continue;
14370
14379
  if (target.startsWith("/")) continue;
14371
- const resolved = join13(docDir, target);
14372
- if (!existsSync15(resolved)) {
14380
+ const resolved = join14(docDir, target);
14381
+ if (!existsSync16(resolved)) {
14373
14382
  findings.push({
14374
14383
  ruleId: "docs/broken-link",
14375
14384
  severity: "low",
@@ -14406,7 +14415,7 @@ async function buildDocFreshness(cwd, config, options = {}) {
14406
14415
  for (const abs of docLimited) {
14407
14416
  let source;
14408
14417
  try {
14409
- source = readFileSync19(abs, "utf-8");
14418
+ source = readFileSync20(abs, "utf-8");
14410
14419
  } catch {
14411
14420
  continue;
14412
14421
  }
@@ -14713,7 +14722,7 @@ __export(db_health_exports, {
14713
14722
  DB_RULE_WEIGHTS: () => DB_RULE_WEIGHTS,
14714
14723
  buildDbHealth: () => buildDbHealth
14715
14724
  });
14716
- import { readFileSync as readFileSync20 } from "fs";
14725
+ import { readFileSync as readFileSync21 } from "fs";
14717
14726
  import { relative as relative9 } from "path";
14718
14727
  import { globby as globby3 } from "globby";
14719
14728
  import { parse as parseSql, loadModule as loadSqlModule } from "pgsql-parser";
@@ -14724,7 +14733,7 @@ function ensureSqlModule() {
14724
14733
  async function parseSqlFile(filePath) {
14725
14734
  let raw;
14726
14735
  try {
14727
- raw = readFileSync20(filePath, "utf-8");
14736
+ raw = readFileSync21(filePath, "utf-8");
14728
14737
  } catch {
14729
14738
  return null;
14730
14739
  }
@@ -14964,7 +14973,7 @@ async function buildDbHealth(cwd, _config, options = {}) {
14964
14973
  for (const abs of tsFiles.slice(0, maxFiles)) {
14965
14974
  let source;
14966
14975
  try {
14967
- source = readFileSync20(abs, "utf-8");
14976
+ source = readFileSync21(abs, "utf-8");
14968
14977
  } catch {
14969
14978
  continue;
14970
14979
  }
@@ -15417,8 +15426,8 @@ __export(scan_exports, {
15417
15426
  scanProject: () => scanProject,
15418
15427
  watchProject: () => watchProject
15419
15428
  });
15420
- import { existsSync as existsSync16, writeFileSync as writeFileSync7, watch, statSync as statSync6, mkdirSync as mkdirSync6, readFileSync as readFileSync21 } from "fs";
15421
- import { resolve as resolve9, join as join15, relative as relative10, extname as extname6, sep as sep2 } from "path";
15429
+ import { existsSync as existsSync17, writeFileSync as writeFileSync8, watch, statSync as statSync7, mkdirSync as mkdirSync7, readFileSync as readFileSync22 } from "fs";
15430
+ import { resolve as resolve9, join as join16, relative as relative10, extname as extname6, sep as sep2 } from "path";
15422
15431
  function buildBaselineCache(report, configHash, gitHead, cwd) {
15423
15432
  const scores = {};
15424
15433
  for (const component of report.components) {
@@ -15441,10 +15450,10 @@ async function runScan(options, explicitPaths) {
15441
15450
  setLoggerQuiet(!!options.quiet);
15442
15451
  const startTime = Date.now();
15443
15452
  const cwd = resolve9(options.workspace ?? process.cwd());
15444
- if (!existsSync16(cwd)) {
15453
+ if (!existsSync17(cwd)) {
15445
15454
  throw new Error(`Workspace not found: ${cwd}`);
15446
15455
  }
15447
- const cwdStat = statSync6(cwd);
15456
+ const cwdStat = statSync7(cwd);
15448
15457
  if (!cwdStat.isDirectory()) {
15449
15458
  throw new Error(`Workspace is not a directory: ${cwd}`);
15450
15459
  }
@@ -15486,8 +15495,8 @@ async function runScan(options, explicitPaths) {
15486
15495
  const resolved = explicitPaths.map((p) => resolve9(cwd, p));
15487
15496
  const expanded = [];
15488
15497
  for (const p of resolved) {
15489
- if (existsSync16(p) && statSync6(p).isDirectory()) {
15490
- const found = await globby4(join15(p, "**/*"), { absolute: true, onlyFiles: true });
15498
+ if (existsSync17(p) && statSync7(p).isDirectory()) {
15499
+ const found = await globby4(join16(p, "**/*"), { absolute: true, onlyFiles: true });
15491
15500
  for (const f of found) {
15492
15501
  if (!ALL_SOURCE_EXTENSIONS.has(extname6(f).toLowerCase())) continue;
15493
15502
  const rel = relative10(cwd, f).split(sep2).join("/");
@@ -15525,8 +15534,8 @@ async function runScan(options, explicitPaths) {
15525
15534
  }
15526
15535
  let incrementalSummary;
15527
15536
  if (options.incremental) {
15528
- const cachePath6 = options.cachePath ?? ".slopbrick-cache.json";
15529
- const existing = loadCache(cachePath6);
15537
+ const cachePath4 = options.cachePath ?? ".slopbrick-cache.json";
15538
+ const existing = loadCache(cachePath4);
15530
15539
  const { toScan, unchanged } = partitionByCache(files, existing);
15531
15540
  files = toScan;
15532
15541
  incrementalSummary = { skipped: unchanged.length, rescanned: toScan.length };
@@ -15631,7 +15640,7 @@ async function runScan(options, explicitPaths) {
15631
15640
  const scannedPaths = new Set(results.map((result) => result.filePath));
15632
15641
  for (const [filePath, cached] of Object.entries(baseline.scores)) {
15633
15642
  if (scannedPaths.has(filePath)) continue;
15634
- if (!existsSync16(filePath)) continue;
15643
+ if (!existsSync17(filePath)) continue;
15635
15644
  scores.push({
15636
15645
  filePath,
15637
15646
  rawScore: 0,
@@ -15945,8 +15954,8 @@ async function runScan(options, explicitPaths) {
15945
15954
  appendRun(cwd, report, thresholdExceeded(report, config));
15946
15955
  }
15947
15956
  if (options.incremental) {
15948
- const cachePath6 = options.cachePath ?? ".slopbrick-cache.json";
15949
- const existing = loadCache(cachePath6) ?? emptyCache();
15957
+ const cachePath4 = options.cachePath ?? ".slopbrick-cache.json";
15958
+ const existing = loadCache(cachePath4) ?? emptyCache();
15950
15959
  const next = { ...existing, generatedAt: (/* @__PURE__ */ new Date()).toISOString() };
15951
15960
  for (const result of results) {
15952
15961
  try {
@@ -15960,7 +15969,7 @@ async function runScan(options, explicitPaths) {
15960
15969
  } catch {
15961
15970
  }
15962
15971
  }
15963
- saveCache(cachePath6, next);
15972
+ saveCache(cachePath4, next);
15964
15973
  if (incrementalSummary && !options.quiet) {
15965
15974
  logger.info(
15966
15975
  `Incremental: re-scanned ${incrementalSummary.rescanned}, skipped ${incrementalSummary.skipped} (unchanged).`
@@ -15992,10 +16001,10 @@ async function runScan(options, explicitPaths) {
15992
16001
  report.research = state.research;
15993
16002
  }
15994
16003
  if (flywheelOutput.suggestions.length > 0) {
15995
- const suggestionsDir = join15(cwd, ".slopbrick", "flywheel");
15996
- if (!existsSync16(suggestionsDir)) mkdirSync6(suggestionsDir, { recursive: true });
15997
- writeFileSync7(
15998
- join15(suggestionsDir, "rule-suggestions.json"),
16004
+ const suggestionsDir = join16(cwd, ".slopbrick", "flywheel");
16005
+ if (!existsSync17(suggestionsDir)) mkdirSync7(suggestionsDir, { recursive: true });
16006
+ writeFileSync8(
16007
+ join16(suggestionsDir, "rule-suggestions.json"),
15999
16008
  JSON.stringify(flywheelOutput.suggestions, null, 2)
16000
16009
  );
16001
16010
  }
@@ -16012,7 +16021,7 @@ async function runScan(options, explicitPaths) {
16012
16021
  );
16013
16022
  await saveInventory(cwd, inventory);
16014
16023
  const constitution = buildConstitutionFromConfig(config, cwd);
16015
- await saveConstitution2(cwd, constitution);
16024
+ await saveConstitution(cwd, constitution);
16016
16025
  if (!options.quiet && !machineReadableStdout) {
16017
16026
  logger.info(`Memory persisted to .slopbrick/ (${inventory.patterns.length} patterns, ${inventory.components.length} components).`);
16018
16027
  }
@@ -16043,7 +16052,7 @@ function collectBusinessLogicIssues(cwd, filePaths) {
16043
16052
  for (const absPath of filePaths) {
16044
16053
  let source;
16045
16054
  try {
16046
- source = readFileSync21(absPath, "utf-8");
16055
+ source = readFileSync22(absPath, "utf-8");
16047
16056
  } catch {
16048
16057
  continue;
16049
16058
  }
@@ -16112,7 +16121,7 @@ function renderOutput(report, options, cwd) {
16112
16121
  if (options.html) {
16113
16122
  const html = formatHtml(report);
16114
16123
  if (typeof options.html === "string") {
16115
- writeFileSync7(resolve9(options.html), html);
16124
+ writeFileSync8(resolve9(options.html), html);
16116
16125
  if (!options.quiet) {
16117
16126
  logger.info(`Wrote HTML report to ${options.html}`);
16118
16127
  }
@@ -16124,7 +16133,7 @@ function renderOutput(report, options, cwd) {
16124
16133
  if (options.json) {
16125
16134
  const json = formatJson(report);
16126
16135
  if (typeof options.json === "string") {
16127
- writeFileSync7(resolve9(options.json), json);
16136
+ writeFileSync8(resolve9(options.json), json);
16128
16137
  if (!options.quiet) {
16129
16138
  logger.info(`Wrote JSON report to ${options.json}`);
16130
16139
  }
@@ -16170,7 +16179,7 @@ async function watchProject(options, cwd, paths) {
16170
16179
  let currentBaseline;
16171
16180
  function getBaselineMtime() {
16172
16181
  try {
16173
- return statSync6(baselinePath(cwd)).mtimeMs;
16182
+ return statSync7(baselinePath(cwd)).mtimeMs;
16174
16183
  } catch {
16175
16184
  return void 0;
16176
16185
  }
@@ -16327,6 +16336,7 @@ var init_scan = __esm({
16327
16336
  init_unified_diff();
16328
16337
  init_heatmap();
16329
16338
  init_memory();
16339
+ init_dist();
16330
16340
  init_telemetry();
16331
16341
  init_flywheel();
16332
16342
  init_logger();
@@ -16340,17 +16350,17 @@ var init_scan = __esm({
16340
16350
  });
16341
16351
 
16342
16352
  // src/engine/memory-md.ts
16343
- import { existsSync as existsSync21, mkdirSync as mkdirSync12, readFileSync as readFileSync30, writeFileSync as writeFileSync13 } from "fs";
16344
- import { dirname as dirname14, join as join21 } from "path";
16353
+ import { existsSync as existsSync22, mkdirSync as mkdirSync13, readFileSync as readFileSync31, writeFileSync as writeFileSync14 } from "fs";
16354
+ import { dirname as dirname15, join as join22 } from "path";
16345
16355
  async function readMemoryMarkdown(workspaceDir) {
16346
16356
  return new Promise((resolve15) => {
16347
16357
  try {
16348
- const path = join21(workspaceDir, MEMORY_MD_FILE);
16349
- if (!existsSync21(path)) {
16358
+ const path = join22(workspaceDir, MEMORY_MD_FILE);
16359
+ if (!existsSync22(path)) {
16350
16360
  resolve15(null);
16351
16361
  return;
16352
16362
  }
16353
- const content = readFileSync30(path, "utf-8");
16363
+ const content = readFileSync31(path, "utf-8");
16354
16364
  resolve15(content);
16355
16365
  } catch {
16356
16366
  resolve15(null);
@@ -16361,7 +16371,7 @@ var MEMORY_MD_FILE;
16361
16371
  var init_memory_md = __esm({
16362
16372
  "src/engine/memory-md.ts"() {
16363
16373
  "use strict";
16364
- MEMORY_MD_FILE = join21(".slopbrick", "memory.md");
16374
+ MEMORY_MD_FILE = join22(".slopbrick", "memory.md");
16365
16375
  }
16366
16376
  });
16367
16377
 
@@ -16574,7 +16584,7 @@ __export(tools_exports, {
16574
16584
  TOOL_DEFINITIONS: () => TOOL_DEFINITIONS,
16575
16585
  handleToolCall: () => handleToolCall
16576
16586
  });
16577
- import { readFileSync as readFileSync31 } from "fs";
16587
+ import { readFileSync as readFileSync32 } from "fs";
16578
16588
  import { resolve as resolve13 } from "path";
16579
16589
  function toolError(message) {
16580
16590
  return {
@@ -16718,7 +16728,7 @@ function runCheckConstitution(args, ctx) {
16718
16728
  const absPath = resolve13(ctx.cwd, path);
16719
16729
  let source;
16720
16730
  try {
16721
- source = readFileSync31(absPath, "utf-8");
16731
+ source = readFileSync32(absPath, "utf-8");
16722
16732
  } catch (err) {
16723
16733
  return toolError(
16724
16734
  `Cannot read file ${absPath}: ${err instanceof Error ? err.message : String(err)}`
@@ -16780,14 +16790,14 @@ async function runBusinessLogicScore(args, ctx) {
16780
16790
  const maxFiles = typeof maxFilesRaw === "number" && Number.isFinite(maxFilesRaw) && maxFilesRaw > 0 ? Math.min(2e3, Math.floor(maxFilesRaw)) : 500;
16781
16791
  try {
16782
16792
  const { discoverFiles: discoverFiles2 } = await Promise.resolve().then(() => (init_discover(), discover_exports));
16783
- const { readFileSync: readFileSync38 } = await import("fs");
16793
+ const { readFileSync: readFileSync39 } = await import("fs");
16784
16794
  const allFiles = await discoverFiles2(ctx.cwd, ctx.config);
16785
16795
  const limited = allFiles.slice(0, maxFiles);
16786
16796
  const issues = [];
16787
16797
  for (const absPath of limited) {
16788
16798
  let source;
16789
16799
  try {
16790
- source = readFileSync38(absPath, "utf-8");
16800
+ source = readFileSync39(absPath, "utf-8");
16791
16801
  } catch {
16792
16802
  continue;
16793
16803
  }
@@ -17062,44 +17072,44 @@ __export(migrate_exports, {
17062
17072
  planMigration: () => planMigration,
17063
17073
  runMigrate: () => runMigrate
17064
17074
  });
17065
- import { existsSync as existsSync24, readFileSync as readFileSync36, renameSync as renameSync3, writeFileSync as writeFileSync17 } from "fs";
17066
- import { join as join25 } from "path";
17075
+ import { existsSync as existsSync25, readFileSync as readFileSync37, renameSync as renameSync4, writeFileSync as writeFileSync18 } from "fs";
17076
+ import { join as join26 } from "path";
17067
17077
  function planMigration(workspaceDir) {
17068
17078
  const moves = [];
17069
17079
  const rewrites = [];
17070
17080
  const gitignoreEdits = [];
17071
- const oldDir = join25(workspaceDir, ".slop-audit");
17072
- const newDir = join25(workspaceDir, ".slopbrick");
17073
- if (existsSync24(oldDir)) {
17081
+ const oldDir = join26(workspaceDir, ".slop-audit");
17082
+ const newDir = join26(workspaceDir, ".slopbrick");
17083
+ if (existsSync25(oldDir)) {
17074
17084
  moves.push({ from: oldDir, to: newDir, kind: "dir" });
17075
17085
  rewrites.push({
17076
- path: join25(newDir, "inventory.json"),
17086
+ path: join26(newDir, "inventory.json"),
17077
17087
  field: "version",
17078
17088
  from: '"1"',
17079
17089
  to: '"2"'
17080
17090
  });
17081
17091
  rewrites.push({
17082
- path: join25(newDir, "constitution.json"),
17092
+ path: join26(newDir, "constitution.json"),
17083
17093
  field: "version",
17084
17094
  from: '"1"',
17085
17095
  to: '"2"'
17086
17096
  });
17087
17097
  }
17088
- const oldCache = join25(workspaceDir, ".slop-audit-cache.json");
17089
- const newCache = join25(workspaceDir, ".slopbrick-cache.json");
17090
- if (existsSync24(oldCache)) {
17098
+ const oldCache = join26(workspaceDir, ".slop-audit-cache.json");
17099
+ const newCache = join26(workspaceDir, ".slopbrick-cache.json");
17100
+ if (existsSync25(oldCache)) {
17091
17101
  moves.push({ from: oldCache, to: newCache, kind: "file" });
17092
17102
  }
17093
17103
  for (const ext of ["mjs", "cjs", "js"]) {
17094
- const oldCfg = join25(workspaceDir, `slop-audit.config.${ext}`);
17095
- const newCfg = join25(workspaceDir, `slopbrick.config.${ext}`);
17096
- if (existsSync24(oldCfg)) {
17104
+ const oldCfg = join26(workspaceDir, `slop-audit.config.${ext}`);
17105
+ const newCfg = join26(workspaceDir, `slopbrick.config.${ext}`);
17106
+ if (existsSync25(oldCfg)) {
17097
17107
  moves.push({ from: oldCfg, to: newCfg, kind: "config" });
17098
17108
  }
17099
17109
  }
17100
- const gi = join25(workspaceDir, ".gitignore");
17101
- if (existsSync24(gi)) {
17102
- const content = readFileSync36(gi, "utf-8");
17110
+ const gi = join26(workspaceDir, ".gitignore");
17111
+ if (existsSync25(gi)) {
17112
+ const content = readFileSync37(gi, "utf-8");
17103
17113
  if (content.includes(".slop-audit/")) {
17104
17114
  gitignoreEdits.push({
17105
17115
  path: gi,
@@ -17118,28 +17128,28 @@ function planMigration(workspaceDir) {
17118
17128
  return { moves, rewrites, gitignoreEdits };
17119
17129
  }
17120
17130
  function isAlreadyMigrated(workspaceDir) {
17121
- return existsSync24(join25(workspaceDir, ".slopbrick")) && !existsSync24(join25(workspaceDir, ".slop-audit"));
17131
+ return existsSync25(join26(workspaceDir, ".slopbrick")) && !existsSync25(join26(workspaceDir, ".slop-audit"));
17122
17132
  }
17123
17133
  function applyMigration(plan, options = {}) {
17124
17134
  if (options.dryRun) return;
17125
17135
  for (const m of plan.moves) {
17126
- renameSync3(m.from, m.to);
17136
+ renameSync4(m.from, m.to);
17127
17137
  }
17128
17138
  for (const r of plan.rewrites) {
17129
- if (!existsSync24(r.path)) continue;
17130
- const content = readFileSync36(r.path, "utf-8");
17139
+ if (!existsSync25(r.path)) continue;
17140
+ const content = readFileSync37(r.path, "utf-8");
17131
17141
  const next = content.replace(`"version": ${r.from}`, `"version": ${r.to}`);
17132
- writeFileSync17(r.path, next);
17142
+ writeFileSync18(r.path, next);
17133
17143
  }
17134
17144
  for (const g of plan.gitignoreEdits) {
17135
- const content = readFileSync36(g.path, "utf-8");
17145
+ const content = readFileSync37(g.path, "utf-8");
17136
17146
  const next = content.replaceAll(g.from, g.to);
17137
- writeFileSync17(g.path, next);
17147
+ writeFileSync18(g.path, next);
17138
17148
  }
17139
17149
  }
17140
17150
  function runMigrate(options) {
17141
17151
  const { workspace, dryRun = false, force = false } = options;
17142
- if (!existsSync24(workspace)) {
17152
+ if (!existsSync25(workspace)) {
17143
17153
  return {
17144
17154
  ok: false,
17145
17155
  alreadyMigrated: false,
@@ -17149,9 +17159,9 @@ function runMigrate(options) {
17149
17159
  };
17150
17160
  }
17151
17161
  const alreadyMigrated = isAlreadyMigrated(workspace);
17152
- const newDir = join25(workspace, ".slopbrick");
17153
- const oldDir = join25(workspace, ".slop-audit");
17154
- if (existsSync24(newDir) && existsSync24(oldDir) && !force) {
17162
+ const newDir = join26(workspace, ".slopbrick");
17163
+ const oldDir = join26(workspace, ".slop-audit");
17164
+ if (existsSync25(newDir) && existsSync25(oldDir) && !force) {
17155
17165
  return {
17156
17166
  ok: false,
17157
17167
  alreadyMigrated: false,
@@ -17230,8 +17240,8 @@ init_types();
17230
17240
  init_config();
17231
17241
 
17232
17242
  // src/cli/program.ts
17233
- import { existsSync as existsSync25, writeFileSync as writeFileSync18, readFileSync as readFileSync37, mkdirSync as mkdirSync13 } from "fs";
17234
- import { resolve as resolve14, join as join26, dirname as dirname15, extname as extname8 } from "path";
17243
+ import { existsSync as existsSync26, writeFileSync as writeFileSync19, readFileSync as readFileSync38, mkdirSync as mkdirSync14 } from "fs";
17244
+ import { resolve as resolve14, join as join27, dirname as dirname16, extname as extname8 } from "path";
17235
17245
  import { performance } from "perf_hooks";
17236
17246
  import { Command } from "commander";
17237
17247
 
@@ -17276,7 +17286,7 @@ init_scan();
17276
17286
  // src/cli/drift.ts
17277
17287
  init_discover();
17278
17288
  init_patterns();
17279
- import { readFileSync as readFileSync22 } from "fs";
17289
+ import { readFileSync as readFileSync23 } from "fs";
17280
17290
  import { basename as basename4, relative as relative11 } from "path";
17281
17291
  async function runDrift(cwd, config, options = {}) {
17282
17292
  const maxFiles = options.maxFiles ?? 1e3;
@@ -17288,7 +17298,7 @@ async function runDrift(cwd, config, options = {}) {
17288
17298
  for (const absPath of limited) {
17289
17299
  let source;
17290
17300
  try {
17291
- source = readFileSync22(absPath, "utf-8");
17301
+ source = readFileSync23(absPath, "utf-8");
17292
17302
  } catch {
17293
17303
  continue;
17294
17304
  }
@@ -17483,7 +17493,7 @@ init_worker();
17483
17493
  init_metrics();
17484
17494
  init_patterns();
17485
17495
  init_discover();
17486
- import { readFileSync as readFileSync23 } from "fs";
17496
+ import { readFileSync as readFileSync24 } from "fs";
17487
17497
  import { extname as extname7, relative as relative12, resolve as resolve11 } from "path";
17488
17498
  import { execFile as execFileCb } from "child_process";
17489
17499
  import { promisify as promisify2 } from "util";
@@ -17556,7 +17566,7 @@ async function runPrScan(cwd, config, options = {}) {
17556
17566
  for (const absPath of candidates) {
17557
17567
  let source;
17558
17568
  try {
17559
- source = readFileSync23(absPath, "utf-8");
17569
+ source = readFileSync24(absPath, "utf-8");
17560
17570
  } catch {
17561
17571
  continue;
17562
17572
  }
@@ -18061,7 +18071,7 @@ function dbExitCode(result, options = {}) {
18061
18071
  // src/cli/business-logic.ts
18062
18072
  init_discover();
18063
18073
  init_business_logic();
18064
- import { readFileSync as readFileSync24 } from "fs";
18074
+ import { readFileSync as readFileSync25 } from "fs";
18065
18075
  import { relative as relative13 } from "path";
18066
18076
  async function runBusinessLogicScan(cwd, config, options = {}) {
18067
18077
  const maxFiles = options.maxFiles ?? 500;
@@ -18072,7 +18082,7 @@ async function runBusinessLogicScan(cwd, config, options = {}) {
18072
18082
  for (const absPath of limited) {
18073
18083
  let source;
18074
18084
  try {
18075
- source = readFileSync24(absPath, "utf-8");
18085
+ source = readFileSync25(absPath, "utf-8");
18076
18086
  } catch {
18077
18087
  continue;
18078
18088
  }
@@ -18177,7 +18187,7 @@ function capitalize(s) {
18177
18187
  // src/engine/patterns.ts
18178
18188
  init_patterns();
18179
18189
  init_discover();
18180
- import { readFileSync as readFileSync25 } from "fs";
18190
+ import { readFileSync as readFileSync26 } from "fs";
18181
18191
  import { basename as basename5, relative as relative14 } from "path";
18182
18192
  var PATTERN_CATEGORIES = [
18183
18193
  "modal",
@@ -18280,7 +18290,7 @@ function detectFormsFromFiles(files) {
18280
18290
  for (const f of files) {
18281
18291
  let source;
18282
18292
  try {
18283
- source = readFileSync25(f, "utf-8");
18293
+ source = readFileSync26(f, "utf-8");
18284
18294
  } catch {
18285
18295
  continue;
18286
18296
  }
@@ -18502,13 +18512,13 @@ init_discover();
18502
18512
  init_git();
18503
18513
  init_cache();
18504
18514
  init_logger();
18505
- import { writeFileSync as writeFileSync9, mkdirSync as mkdirSync8, rmSync as rmSync2 } from "fs";
18506
- import { join as join17, dirname as dirname11 } from "path";
18515
+ import { writeFileSync as writeFileSync10, mkdirSync as mkdirSync9, rmSync as rmSync2 } from "fs";
18516
+ import { join as join18, dirname as dirname12 } from "path";
18507
18517
  import { createInterface } from "readline";
18508
18518
 
18509
18519
  // src/rules/registry-loader.ts
18510
- import { existsSync as existsSync17, mkdirSync as mkdirSync7, readFileSync as readFileSync26, writeFileSync as writeFileSync8 } from "fs";
18511
- import { dirname as dirname10, join as join16 } from "path";
18520
+ import { existsSync as existsSync18, mkdirSync as mkdirSync8, readFileSync as readFileSync27, writeFileSync as writeFileSync9 } from "fs";
18521
+ import { dirname as dirname11, join as join17 } from "path";
18512
18522
 
18513
18523
  // src/data/shadcn-registry.json
18514
18524
  var shadcn_registry_default = {
@@ -18641,13 +18651,13 @@ var shadcn_registry_default = {
18641
18651
  // src/rules/registry-loader.ts
18642
18652
  var REGISTRY_URL = "https://ui.shadcn.com/registry.json";
18643
18653
  var BUNDLED_REGISTRY_VERSION = shadcn_registry_default.version;
18644
- function cachePath4(cwd) {
18645
- return join16(cwd, ".slopbrick", "cache", "registry-snapshot.json");
18654
+ function cachePath3(cwd) {
18655
+ return join17(cwd, ".slopbrick", "cache", "registry-snapshot.json");
18646
18656
  }
18647
18657
  function ensureCacheDir(cwd) {
18648
- const dir = dirname10(cachePath4(cwd));
18649
- if (!existsSync17(dir)) {
18650
- mkdirSync7(dir, { recursive: true });
18658
+ const dir = dirname11(cachePath3(cwd));
18659
+ if (!existsSync18(dir)) {
18660
+ mkdirSync8(dir, { recursive: true });
18651
18661
  }
18652
18662
  }
18653
18663
  function isValidSnapshot(value) {
@@ -18658,10 +18668,10 @@ function isValidSnapshot(value) {
18658
18668
  return true;
18659
18669
  }
18660
18670
  function isRegistryFresh(cwd) {
18661
- const cached = cachePath4(cwd);
18662
- if (!existsSync17(cached)) return false;
18671
+ const cached = cachePath3(cwd);
18672
+ if (!existsSync18(cached)) return false;
18663
18673
  try {
18664
- const parsed = JSON.parse(readFileSync26(cached, "utf8"));
18674
+ const parsed = JSON.parse(readFileSync27(cached, "utf8"));
18665
18675
  if (!isValidSnapshot(parsed)) return false;
18666
18676
  return parsed.version === BUNDLED_REGISTRY_VERSION;
18667
18677
  } catch {
@@ -18695,7 +18705,7 @@ async function refreshRegistrySnapshot(cwd, url = REGISTRY_URL, timeoutMs = 5e3)
18695
18705
  };
18696
18706
  }
18697
18707
  ensureCacheDir(cwd);
18698
- writeFileSync8(cachePath4(cwd), JSON.stringify(fetched, null, 2));
18708
+ writeFileSync9(cachePath3(cwd), JSON.stringify(fetched, null, 2));
18699
18709
  const fresh = fetched.version === BUNDLED_REGISTRY_VERSION;
18700
18710
  return {
18701
18711
  ok: true,
@@ -18705,7 +18715,7 @@ async function refreshRegistrySnapshot(cwd, url = REGISTRY_URL, timeoutMs = 5e3)
18705
18715
  }
18706
18716
  function copyBundledSnapshotToCache(cwd) {
18707
18717
  ensureCacheDir(cwd);
18708
- writeFileSync8(cachePath4(cwd), JSON.stringify(shadcn_registry_default, null, 2));
18718
+ writeFileSync9(cachePath3(cwd), JSON.stringify(shadcn_registry_default, null, 2));
18709
18719
  }
18710
18720
 
18711
18721
  // src/cli/init.ts
@@ -18858,9 +18868,9 @@ async function runDoctor(cwd) {
18858
18868
  }
18859
18869
  try {
18860
18870
  const { parseFile: tryParse } = await Promise.resolve().then(() => (init_parser(), parser_exports));
18861
- const testFile = join17(cwd, ".slopbrick", ".doctor-test.ts");
18862
- mkdirSync8(dirname11(testFile), { recursive: true });
18863
- writeFileSync9(testFile, "export const x = 1;\n");
18871
+ const testFile = join18(cwd, ".slopbrick", ".doctor-test.ts");
18872
+ mkdirSync9(dirname12(testFile), { recursive: true });
18873
+ writeFileSync10(testFile, "export const x = 1;\n");
18864
18874
  await tryParse(testFile);
18865
18875
  rmSync2(testFile, { force: true });
18866
18876
  ok("Parser is working.");
@@ -18919,12 +18929,12 @@ init_git();
18919
18929
  // src/cli/installer.ts
18920
18930
  import {
18921
18931
  chmodSync,
18922
- existsSync as existsSync19,
18923
- mkdirSync as mkdirSync9,
18924
- readFileSync as readFileSync28,
18925
- writeFileSync as writeFileSync10
18932
+ existsSync as existsSync20,
18933
+ mkdirSync as mkdirSync10,
18934
+ readFileSync as readFileSync29,
18935
+ writeFileSync as writeFileSync11
18926
18936
  } from "fs";
18927
- import { dirname as dirname12, join as join18 } from "path";
18937
+ import { dirname as dirname13, join as join19 } from "path";
18928
18938
  var BEGIN_SENTINEL = "# slopbrick-hook-begin";
18929
18939
  var END_SENTINEL = "# slopbrick-hook-end";
18930
18940
  var SENTINEL_BLOCK = `${BEGIN_SENTINEL}
@@ -18932,14 +18942,14 @@ npx slopbrick --staged
18932
18942
  ${END_SENTINEL}
18933
18943
  `;
18934
18944
  function hookPath(gitRoot) {
18935
- const huskyDir = join18(gitRoot, ".husky");
18936
- if (existsSync19(huskyDir)) {
18937
- return join18(huskyDir, "pre-commit");
18945
+ const huskyDir = join19(gitRoot, ".husky");
18946
+ if (existsSync20(huskyDir)) {
18947
+ return join19(huskyDir, "pre-commit");
18938
18948
  }
18939
- return join18(gitRoot, ".git", "hooks", "pre-commit");
18949
+ return join19(gitRoot, ".git", "hooks", "pre-commit");
18940
18950
  }
18941
18951
  function readHookContent(path) {
18942
- return readFileSync28(path, "utf8");
18952
+ return readFileSync29(path, "utf8");
18943
18953
  }
18944
18954
  function sentinelsPresent(content) {
18945
18955
  const lines = content.split(/\r?\n/);
@@ -18961,7 +18971,7 @@ function replaceSentinelBlock(content) {
18961
18971
  }
18962
18972
  function installHook(gitRoot) {
18963
18973
  const path = hookPath(gitRoot);
18964
- if (existsSync19(path)) {
18974
+ if (existsSync20(path)) {
18965
18975
  const content = readHookContent(path);
18966
18976
  const { begin, end } = sentinelsPresent(content);
18967
18977
  if (begin && end) {
@@ -18973,7 +18983,7 @@ function installHook(gitRoot) {
18973
18983
  exitCode: 0
18974
18984
  };
18975
18985
  }
18976
- writeFileSync10(path, replaced.endsWith("\n") ? replaced : `${replaced}
18986
+ writeFileSync11(path, replaced.endsWith("\n") ? replaced : `${replaced}
18977
18987
  `);
18978
18988
  chmodSync(path, 493);
18979
18989
  return {
@@ -18993,7 +19003,7 @@ function installHook(gitRoot) {
18993
19003
  }
18994
19004
  const normalized = content.length > 0 && !content.endsWith("\n") ? `${content}
18995
19005
  ` : content;
18996
- writeFileSync10(path, `${normalized}${SENTINEL_BLOCK}`);
19006
+ writeFileSync11(path, `${normalized}${SENTINEL_BLOCK}`);
18997
19007
  chmodSync(path, 493);
18998
19008
  return {
18999
19009
  ok: true,
@@ -19001,8 +19011,8 @@ function installHook(gitRoot) {
19001
19011
  exitCode: 0
19002
19012
  };
19003
19013
  }
19004
- mkdirSync9(dirname12(path), { recursive: true });
19005
- writeFileSync10(path, SENTINEL_BLOCK, { mode: 493 });
19014
+ mkdirSync10(dirname13(path), { recursive: true });
19015
+ writeFileSync11(path, SENTINEL_BLOCK, { mode: 493 });
19006
19016
  chmodSync(path, 493);
19007
19017
  return {
19008
19018
  ok: true,
@@ -19012,7 +19022,7 @@ function installHook(gitRoot) {
19012
19022
  }
19013
19023
  function uninstallHook(gitRoot) {
19014
19024
  const path = hookPath(gitRoot);
19015
- if (!existsSync19(path)) {
19025
+ if (!existsSync20(path)) {
19016
19026
  return {
19017
19027
  ok: true,
19018
19028
  message: "Hook not installed",
@@ -19048,7 +19058,7 @@ function uninstallHook(gitRoot) {
19048
19058
  }
19049
19059
  const remaining = [...lines.slice(0, start), ...lines.slice(end + 1)];
19050
19060
  const result = remaining.join("\n");
19051
- writeFileSync10(path, result.endsWith("\n") ? result : `${result}
19061
+ writeFileSync11(path, result.endsWith("\n") ? result : `${result}
19052
19062
  `);
19053
19063
  return {
19054
19064
  ok: true,
@@ -19114,8 +19124,8 @@ function createProvider(config) {
19114
19124
  }
19115
19125
 
19116
19126
  // src/research/generator.ts
19117
- import { mkdirSync as mkdirSync10, writeFileSync as writeFileSync11 } from "fs";
19118
- import { join as join19 } from "path";
19127
+ import { mkdirSync as mkdirSync11, writeFileSync as writeFileSync12 } from "fs";
19128
+ import { join as join20 } from "path";
19119
19129
 
19120
19130
  // src/research/prompts.ts
19121
19131
  var DEFAULT_PROMPT_TEMPLATES = [
@@ -19178,14 +19188,14 @@ async function generateSamples(options) {
19178
19188
  }
19179
19189
  const samples = [];
19180
19190
  const ext = extForFramework(framework);
19181
- const dir = join19(outputDir, framework, componentType);
19182
- mkdirSync10(dir, { recursive: true });
19191
+ const dir = join20(outputDir, framework, componentType);
19192
+ mkdirSync11(dir, { recursive: true });
19183
19193
  for (let i = 1; i <= count; i += 1) {
19184
19194
  const raw = await provider.generateSample(renderPrompt(template), { temperature });
19185
19195
  const code = extractCodeFromMarkdown(raw);
19186
19196
  const fileName = `sample-${i}${ext}`;
19187
- const filePath = join19(dir, fileName);
19188
- writeFileSync11(filePath, code, "utf8");
19197
+ const filePath = join20(dir, fileName);
19198
+ writeFileSync12(filePath, code, "utf8");
19189
19199
  const sample = {
19190
19200
  filePath,
19191
19201
  framework,
@@ -19196,8 +19206,8 @@ async function generateSamples(options) {
19196
19206
  };
19197
19207
  samples.push(sample);
19198
19208
  }
19199
- const metadataPath = join19(dir, "metadata.json");
19200
- writeFileSync11(metadataPath, JSON.stringify(samples, null, 2), "utf8");
19209
+ const metadataPath = join20(dir, "metadata.json");
19210
+ writeFileSync12(metadataPath, JSON.stringify(samples, null, 2), "utf8");
19201
19211
  return samples;
19202
19212
  }
19203
19213
 
@@ -19403,37 +19413,37 @@ function slugify(value) {
19403
19413
 
19404
19414
  // src/research/calibrator.ts
19405
19415
  import { execFileSync as execFileSync2 } from "child_process";
19406
- import { existsSync as existsSync20, readFileSync as readFileSync29, writeFileSync as writeFileSync12, mkdirSync as mkdirSync11 } from "fs";
19407
- import { join as join20, resolve as resolve12 } from "path";
19416
+ import { existsSync as existsSync21, readFileSync as readFileSync30, writeFileSync as writeFileSync13, mkdirSync as mkdirSync12 } from "fs";
19417
+ import { join as join21, resolve as resolve12 } from "path";
19408
19418
  var DEFAULT_POSITIVE = "/Users/cheng/ai-slop-baseline/extracted/positive";
19409
19419
  var DEFAULT_NEGATIVE = "/Users/cheng/ai-slop-baseline/extracted/negative";
19410
19420
  function buildFileList(dir, extensions) {
19411
- const tmpList = join20("/tmp", `cal-build-${Date.now()}-${Math.random().toString(36).slice(2)}.txt`);
19421
+ const tmpList = join21("/tmp", `cal-build-${Date.now()}-${Math.random().toString(36).slice(2)}.txt`);
19412
19422
  const expr = extensions.map((e) => `-name '*.${e}'`).join(" -o ");
19413
19423
  execFileSync2("bash", ["-c", `find ${dir} -maxdepth 8 -type f \\( ${expr} \\) -print0 | xargs -0 realpath > ${tmpList}`]);
19414
- const out = readFileSync29(tmpList, "utf8");
19424
+ const out = readFileSync30(tmpList, "utf8");
19415
19425
  execFileSync2("rm", ["-f", tmpList]);
19416
19426
  return out.trim().split("\n").filter(Boolean);
19417
19427
  }
19418
19428
  function runScan2(fileListPath) {
19419
- const files = readFileSync29(fileListPath, "utf8").trim().split("\n").filter(Boolean);
19429
+ const files = readFileSync30(fileListPath, "utf8").trim().split("\n").filter(Boolean);
19420
19430
  const CHUNK = 600;
19421
19431
  const ruleFires = /* @__PURE__ */ new Map();
19422
19432
  const uniqueFilesPerRule = /* @__PURE__ */ new Map();
19423
19433
  let fileCount = 0;
19424
- const tmpOut = join20("/tmp", `calibrate-${Date.now()}-${Math.random().toString(36).slice(2)}.json`);
19434
+ const tmpOut = join21("/tmp", `calibrate-${Date.now()}-${Math.random().toString(36).slice(2)}.json`);
19425
19435
  for (let i = 0; i < files.length; i += CHUNK) {
19426
19436
  const chunk = files.slice(i, i + CHUNK);
19427
19437
  try {
19428
19438
  execFileSync2(
19429
19439
  "node",
19430
- [join20(process.cwd(), "bin", "slopbrick.js"), "scan", ...chunk, "--json", tmpOut, "--no-telemetry", "--quiet"],
19440
+ [join21(process.cwd(), "bin", "slopbrick.js"), "scan", ...chunk, "--json", tmpOut, "--no-telemetry", "--quiet"],
19431
19441
  { encoding: "utf8", stdio: ["ignore", "pipe", "pipe"] }
19432
19442
  );
19433
19443
  } catch {
19434
19444
  }
19435
- if (!existsSync20(tmpOut)) continue;
19436
- const report = JSON.parse(readFileSync29(tmpOut, "utf8"));
19445
+ if (!existsSync21(tmpOut)) continue;
19446
+ const report = JSON.parse(readFileSync30(tmpOut, "utf8"));
19437
19447
  fileCount += report.fileCount;
19438
19448
  for (const issue of report.issues) {
19439
19449
  ruleFires.set(issue.ruleId, (ruleFires.get(issue.ruleId) ?? 0) + 1);
@@ -19461,16 +19471,16 @@ function classify(posFiles, negFiles) {
19461
19471
  async function calibrate(cwd, options = {}) {
19462
19472
  const positiveDir = options.positiveDir ?? DEFAULT_POSITIVE;
19463
19473
  const negativeDir = options.negativeDir ?? DEFAULT_NEGATIVE;
19464
- if (!existsSync20(positiveDir)) throw new Error(`Positive corpus not found: ${positiveDir}`);
19465
- if (!existsSync20(negativeDir)) throw new Error(`Negative corpus not found: ${negativeDir}`);
19474
+ if (!existsSync21(positiveDir)) throw new Error(`Positive corpus not found: ${positiveDir}`);
19475
+ if (!existsSync21(negativeDir)) throw new Error(`Negative corpus not found: ${negativeDir}`);
19466
19476
  const positiveFiles = buildFileList(positiveDir, ["tsx", "ts", "jsx", "js"]);
19467
19477
  const negativeFiles = buildFileList(negativeDir, ["tsx", "ts"]);
19468
19478
  const posSample = options.positiveLimit ? positiveFiles.slice(0, options.positiveLimit) : positiveFiles;
19469
19479
  const negSample = options.negativeLimit ? negativeFiles.slice(0, options.negativeLimit) : negativeFiles;
19470
- const posListPath = join20("/tmp", `cal-pos-${Date.now()}.txt`);
19471
- const negListPath = join20("/tmp", `cal-neg-${Date.now()}.txt`);
19472
- writeFileSync12(posListPath, posSample.join("\n"));
19473
- writeFileSync12(negListPath, negSample.join("\n"));
19480
+ const posListPath = join21("/tmp", `cal-pos-${Date.now()}.txt`);
19481
+ const negListPath = join21("/tmp", `cal-neg-${Date.now()}.txt`);
19482
+ writeFileSync13(posListPath, posSample.join("\n"));
19483
+ writeFileSync13(negListPath, negSample.join("\n"));
19474
19484
  const builtins = await Promise.resolve().then(() => (init_builtins(), builtins_exports));
19475
19485
  const builtinRules2 = builtins.builtinRules ?? [];
19476
19486
  const metaById = /* @__PURE__ */ new Map();
@@ -19879,7 +19889,7 @@ var RULE_HINTS = {
19879
19889
  };
19880
19890
 
19881
19891
  // src/snippet/targets.ts
19882
- import { join as join23 } from "path";
19892
+ import { join as join24 } from "path";
19883
19893
 
19884
19894
  // src/snippet/render.ts
19885
19895
  function aiSpecificRules(rules) {
@@ -20110,7 +20120,7 @@ var SNIPPET_TARGETS = [
20110
20120
  }
20111
20121
  ];
20112
20122
  function resolveTargetPath(target) {
20113
- return target.isFolder ? join23(target.path, target.filename) : target.path;
20123
+ return target.isFolder ? join24(target.path, target.filename) : target.path;
20114
20124
  }
20115
20125
  function renderMatrix() {
20116
20126
  const lines = [];
@@ -20251,8 +20261,8 @@ init_unified_diff();
20251
20261
  init_heatmap();
20252
20262
 
20253
20263
  // src/report/flywheel.ts
20254
- import { existsSync as existsSync22, readFileSync as readFileSync32 } from "fs";
20255
- import { join as join24 } from "path";
20264
+ import { existsSync as existsSync23, readFileSync as readFileSync33 } from "fs";
20265
+ import { join as join25 } from "path";
20256
20266
  function average(values) {
20257
20267
  if (values.length === 0) return 0;
20258
20268
  return values.reduce((a, b) => a + b, 0) / values.length;
@@ -20343,8 +20353,8 @@ init_telemetry();
20343
20353
  init_memory();
20344
20354
 
20345
20355
  // src/fix/focus-ring.ts
20346
- import { existsSync as existsSync23 } from "fs";
20347
- import { readFileSync as readFileSync33, writeFileSync as writeFileSync14 } from "fs";
20356
+ import { existsSync as existsSync24 } from "fs";
20357
+ import { readFileSync as readFileSync34, writeFileSync as writeFileSync15 } from "fs";
20348
20358
  var ANCHOR_START = "/* @slopbrick:v1.0.0:fix:focus-ring */";
20349
20359
  var CSS_BLOCK = `/* @slopbrick:v1.0.0:fix:focus-ring */
20350
20360
  :focus-visible {
@@ -20353,15 +20363,15 @@ var CSS_BLOCK = `/* @slopbrick:v1.0.0:fix:focus-ring */
20353
20363
  }
20354
20364
  /* @slopbrick:v1.0.0:fix:focus-ring-end */`;
20355
20365
  function applyFocusRingFix(targetFile) {
20356
- if (!existsSync23(targetFile)) {
20366
+ if (!existsSync24(targetFile)) {
20357
20367
  return { applied: false, reason: "missing-global-css-target" };
20358
20368
  }
20359
- const content = readFileSync33(targetFile, "utf-8");
20369
+ const content = readFileSync34(targetFile, "utf-8");
20360
20370
  if (content.includes(ANCHOR_START)) {
20361
20371
  return { applied: false, reason: "already-present" };
20362
20372
  }
20363
20373
  const separator = content.endsWith("\n") ? "" : "\n";
20364
- writeFileSync14(targetFile, `${content}${separator}${CSS_BLOCK}
20374
+ writeFileSync15(targetFile, `${content}${separator}${CSS_BLOCK}
20365
20375
  `);
20366
20376
  return { applied: true };
20367
20377
  }
@@ -20370,21 +20380,21 @@ function applyFocusRingFix(targetFile) {
20370
20380
  init_layout_token();
20371
20381
 
20372
20382
  // src/fix/use-client.ts
20373
- import { readFileSync as readFileSync34, writeFileSync as writeFileSync15 } from "fs";
20383
+ import { readFileSync as readFileSync35, writeFileSync as writeFileSync16 } from "fs";
20374
20384
  function applyUseClientFix(filePath) {
20375
- const content = readFileSync34(filePath, "utf-8");
20385
+ const content = readFileSync35(filePath, "utf-8");
20376
20386
  const trimmed = content.trimStart();
20377
20387
  if (trimmed.startsWith("'use client'") || trimmed.startsWith('"use client"')) {
20378
20388
  return { applied: false, reason: "already-present" };
20379
20389
  }
20380
- writeFileSync15(filePath, `"use client";
20390
+ writeFileSync16(filePath, `"use client";
20381
20391
 
20382
20392
  ${content}`);
20383
20393
  return { applied: true };
20384
20394
  }
20385
20395
 
20386
20396
  // src/fix/visual-codemod.ts
20387
- import { readFileSync as readFileSync35, writeFileSync as writeFileSync16 } from "fs";
20397
+ import { readFileSync as readFileSync36, writeFileSync as writeFileSync17 } from "fs";
20388
20398
 
20389
20399
  // src/fix/visual-codemods/tailwind.ts
20390
20400
  var ARBITRARY_ESCAPE_RE = /\b(p|m|px|py|pt|pb|pl|pr|mx|my|mt|mb|ml|mr|gap|space-[xy]|w|h|min-w|max-w|min-h|max-h|text-\w+|leading-\w+|rounded|border)-?\[(-?\d+(?:\.\d+)?)(px|rem|em|%|vh|vw)?\]/g;
@@ -20610,7 +20620,7 @@ var ALL_CODEMODS = [
20610
20620
  { name: "aria-attr-typo", fn: applyAriaAttrTypoCodemod }
20611
20621
  ];
20612
20622
  function applyVisualCodemods(filePath) {
20613
- const original = readFileSync35(filePath, "utf-8");
20623
+ const original = readFileSync36(filePath, "utf-8");
20614
20624
  let content = original;
20615
20625
  const reasons = [];
20616
20626
  const seen = /* @__PURE__ */ new Set();
@@ -20626,7 +20636,7 @@ function applyVisualCodemods(filePath) {
20626
20636
  }
20627
20637
  }
20628
20638
  if (content !== original) {
20629
- writeFileSync16(filePath, content);
20639
+ writeFileSync17(filePath, content);
20630
20640
  }
20631
20641
  return {
20632
20642
  filePath,
@@ -20782,12 +20792,12 @@ async function runCli({ start }) {
20782
20792
  process.exit(0);
20783
20793
  }
20784
20794
  const cwd = resolve14(options.workspace ?? process.cwd());
20785
- const configPath = join26(cwd, "slopbrick.config.mjs");
20795
+ const configPath = join27(cwd, "slopbrick.config.mjs");
20786
20796
  const detected = detectStack(cwd);
20787
20797
  const fallbackConfig = { ...DEFAULT_CONFIG, ...detected };
20788
20798
  const proposed = serializeConfig(fallbackConfig);
20789
- if (existsSync25(configPath) && !cmdOptions.yes) {
20790
- const current = readFileSync37(configPath, "utf8");
20799
+ if (existsSync26(configPath) && !cmdOptions.yes) {
20800
+ const current = readFileSync38(configPath, "utf8");
20791
20801
  logger.error(`A config file already exists at ${configPath}.`);
20792
20802
  logger.error("To overwrite it with defaults, run `slopbrick init --yes`.");
20793
20803
  logger.error("");
@@ -20808,7 +20818,7 @@ async function runCli({ start }) {
20808
20818
  config = buildInitConfig(detected, answers);
20809
20819
  usedWizard = true;
20810
20820
  }
20811
- writeFileSync18(configPath, serializeConfig(config));
20821
+ writeFileSync19(configPath, serializeConfig(config));
20812
20822
  appendGitignore(cwd);
20813
20823
  const refresh = await refreshRegistrySnapshot(cwd);
20814
20824
  if (!refresh.ok) {
@@ -20838,21 +20848,21 @@ async function runCli({ start }) {
20838
20848
  return Boolean(opts[t.flag]);
20839
20849
  });
20840
20850
  for (const target of targetsToWrite) {
20841
- const snippetPath = join26(cwd, resolveTargetPath(target));
20842
- mkdirSync13(dirname15(snippetPath), { recursive: true });
20851
+ const snippetPath = join27(cwd, resolveTargetPath(target));
20852
+ mkdirSync14(dirname16(snippetPath), { recursive: true });
20843
20853
  const generated = target.generator(builtinRules);
20844
- if (!target.isFolder && existsSync25(snippetPath)) {
20845
- const existing = readFileSync37(snippetPath, "utf8");
20854
+ if (!target.isFolder && existsSync26(snippetPath)) {
20855
+ const existing = readFileSync38(snippetPath, "utf8");
20846
20856
  if (existing.includes("<!-- slopbrick:begin -->")) {
20847
20857
  const updated = existing.replace(
20848
20858
  /<!-- slopbrick:begin -->[\s\S]*?<!-- slopbrick:end -->/,
20849
20859
  "<!-- slopbrick:begin -->\n" + generated + "<!-- slopbrick:end -->"
20850
20860
  );
20851
- writeFileSync18(snippetPath, updated, "utf8");
20861
+ writeFileSync19(snippetPath, updated, "utf8");
20852
20862
  if (!options.quiet) logger.info(`Updated ${snippetPath}`);
20853
20863
  continue;
20854
20864
  }
20855
- writeFileSync18(
20865
+ writeFileSync19(
20856
20866
  snippetPath,
20857
20867
  existing + (existing.endsWith("\n") ? "\n" : "\n\n") + generated,
20858
20868
  "utf8"
@@ -20860,7 +20870,7 @@ async function runCli({ start }) {
20860
20870
  if (!options.quiet) logger.info(`Wrote ${snippetPath}`);
20861
20871
  continue;
20862
20872
  }
20863
- writeFileSync18(snippetPath, generated, "utf8");
20873
+ writeFileSync19(snippetPath, generated, "utf8");
20864
20874
  if (!options.quiet) logger.info(`Wrote ${snippetPath}`);
20865
20875
  }
20866
20876
  if (options.baseline) {
@@ -20929,8 +20939,8 @@ async function runCli({ start }) {
20929
20939
  const summary = summarizeTelemetry(payloads);
20930
20940
  if (cmdOptions.export) {
20931
20941
  const exportPath = resolve14(cmdOptions.export);
20932
- mkdirSync13(dirname15(exportPath), { recursive: true });
20933
- writeFileSync18(exportPath, JSON.stringify(summary, null, 2), "utf-8");
20942
+ mkdirSync14(dirname16(exportPath), { recursive: true });
20943
+ writeFileSync19(exportPath, JSON.stringify(summary, null, 2), "utf-8");
20934
20944
  logger.info(`Wrote flywheel summary to ${exportPath}`);
20935
20945
  process.exit(0);
20936
20946
  }
@@ -21088,16 +21098,16 @@ async function runCli({ start }) {
21088
21098
  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) => {
21089
21099
  try {
21090
21100
  const metadataPath = resolve14(cmdOptions.inputDir, "metadata.json");
21091
- if (!existsSync25(metadataPath)) {
21101
+ if (!existsSync26(metadataPath)) {
21092
21102
  logger.error(`No metadata.json found in ${cmdOptions.inputDir}`);
21093
21103
  process.exit(2);
21094
21104
  }
21095
- const samples = JSON.parse(readFileSync37(metadataPath, "utf8"));
21105
+ const samples = JSON.parse(readFileSync38(metadataPath, "utf8"));
21096
21106
  const config = cmdOptions.config ? await loadConfig(cmdOptions.config) : { ...DEFAULT_CONFIG, framework: cmdOptions.framework };
21097
21107
  const analysis = await analyzeSamples(samples, config);
21098
21108
  const outputPath = resolve14(cmdOptions.output);
21099
- mkdirSync13(dirname15(outputPath), { recursive: true });
21100
- writeFileSync18(outputPath, JSON.stringify(analysis, null, 2), "utf8");
21109
+ mkdirSync14(dirname16(outputPath), { recursive: true });
21110
+ writeFileSync19(outputPath, JSON.stringify(analysis, null, 2), "utf8");
21101
21111
  logger.info(`Analyzed ${analysis.summary.total} samples; coverage: ${analysis.summary.coverage}%`);
21102
21112
  logger.info(`Wrote analysis to ${outputPath}`);
21103
21113
  } catch (error) {
@@ -21108,11 +21118,11 @@ async function runCli({ start }) {
21108
21118
  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) => {
21109
21119
  try {
21110
21120
  const metadataPath = resolve14(cmdOptions.inputDir, "metadata.json");
21111
- if (!existsSync25(metadataPath)) {
21121
+ if (!existsSync26(metadataPath)) {
21112
21122
  logger.error(`No metadata.json found in ${cmdOptions.inputDir}`);
21113
21123
  process.exit(2);
21114
21124
  }
21115
- const samples = JSON.parse(readFileSync37(metadataPath, "utf8"));
21125
+ const samples = JSON.parse(readFileSync38(metadataPath, "utf8"));
21116
21126
  const config = cmdOptions.config ? await loadConfig(cmdOptions.config) : { ...DEFAULT_CONFIG, framework: cmdOptions.framework };
21117
21127
  const analysis = await analyzeSamples(samples, config);
21118
21128
  const extraction = extractAndCluster(analysis.samples, {
@@ -21123,7 +21133,7 @@ async function runCli({ start }) {
21123
21133
  minFrequency: cmdOptions.minFrequency
21124
21134
  });
21125
21135
  const outputPath = resolve14(cmdOptions.output);
21126
- mkdirSync13(dirname15(outputPath), { recursive: true });
21136
+ mkdirSync14(dirname16(outputPath), { recursive: true });
21127
21137
  const payload = {
21128
21138
  generatedAt: (/* @__PURE__ */ new Date()).toISOString(),
21129
21139
  sampleCount: analysis.summary.total,
@@ -21131,7 +21141,7 @@ async function runCli({ start }) {
21131
21141
  fingerprintCount: extraction.total,
21132
21142
  candidates
21133
21143
  };
21134
- writeFileSync18(outputPath, JSON.stringify(payload, null, 2), "utf8");
21144
+ writeFileSync19(outputPath, JSON.stringify(payload, null, 2), "utf8");
21135
21145
  logger.info(`Extracted ${extraction.total} fingerprints across ${analysis.summary.total} samples`);
21136
21146
  logger.info(`Wrote ${candidates.length} candidate rule(s) to ${outputPath}`);
21137
21147
  } catch (error) {
@@ -21149,8 +21159,8 @@ async function runCli({ start }) {
21149
21159
  negativeLimit: cmdOptions.negativeLimit
21150
21160
  });
21151
21161
  const outputPath = cmdOptions.output ? resolve14(cwd, cmdOptions.output) : resolve14(cwd, "corpus", "calibration-empirical.md");
21152
- mkdirSync13(dirname15(outputPath), { recursive: true });
21153
- writeFileSync18(outputPath, reportToMarkdown(report), "utf8");
21162
+ mkdirSync14(dirname16(outputPath), { recursive: true });
21163
+ writeFileSync19(outputPath, reportToMarkdown(report), "utf8");
21154
21164
  logger.info(
21155
21165
  "Calibrated " + report.rules.length + " rules across " + report.positiveFileCount + " positive + " + report.negativeFileCount + " negative files."
21156
21166
  );
@@ -21554,7 +21564,7 @@ async function runCli({ start }) {
21554
21564
  });
21555
21565
  program.command("validate-config [path]").description("Statically validate a slopbrick.config.mjs without scanning").action(async (configPath) => {
21556
21566
  const path = configPath ? resolve14(configPath) : resolve14(process.cwd(), "slopbrick.config.mjs");
21557
- if (!existsSync25(path)) {
21567
+ if (!existsSync26(path)) {
21558
21568
  logger.error(`Error: config file not found: ${path}`);
21559
21569
  process.exit(2);
21560
21570
  }
@@ -21630,26 +21640,6 @@ ${formatMarkdown3(result.report)}`);
21630
21640
  init_threshold();
21631
21641
  init_render();
21632
21642
  init_find_similar();
21633
- import {
21634
- MEMORY_SCHEMA_VERSION as MEMORY_SCHEMA_VERSION3,
21635
- loadInventory as loadInventory3,
21636
- saveInventory as saveInventory2,
21637
- loadConstitution as loadConstitution3,
21638
- saveConstitution as saveConstitution3,
21639
- isInventoryFresh as isInventoryFresh3,
21640
- invalidateFile as invalidateFile3,
21641
- inventoryPath as inventoryPath3,
21642
- constitutionPath as constitutionPath3,
21643
- cachePath as cachePath5,
21644
- INVENTORY_FILENAME,
21645
- CONSTITUTION_FILENAME,
21646
- CACHE_FILENAME,
21647
- isMemoryPattern as isMemoryPattern3,
21648
- isComponentFingerprint as isComponentFingerprint3,
21649
- isInventoryFile as isInventoryFile3,
21650
- isConstitutionFile as isConstitutionFile3,
21651
- isFileMtimeEntry as isFileMtimeEntry3
21652
- } from "@usebrick/core";
21653
21643
  process.on("uncaughtException", (err) => {
21654
21644
  const { logger: logger6 } = (init_logger(), __toCommonJS(logger_exports));
21655
21645
  logger6.error(`Unexpected error: ${err.message}`);
@@ -21657,17 +21647,11 @@ process.on("uncaughtException", (err) => {
21657
21647
  });
21658
21648
  export {
21659
21649
  AI_SECURITY_NUMERIC,
21660
- CACHE_FILENAME,
21661
- CONSTITUTION_FILENAME,
21662
21650
  DEFAULT_CONFIG,
21663
- INVENTORY_FILENAME,
21664
- MEMORY_SCHEMA_VERSION3 as MEMORY_SCHEMA_VERSION,
21665
21651
  REPOSITORY_HEALTH_WEIGHTS,
21666
21652
  VERSION,
21667
21653
  baselineStatusMessage,
21668
- cachePath5 as cachePath,
21669
21654
  colorForSlop,
21670
- constitutionPath3 as constitutionPath,
21671
21655
  extractSignatures,
21672
21656
  failedThresholdCount,
21673
21657
  filterByDisabledDirectives,
@@ -21677,22 +21661,10 @@ export {
21677
21661
  formatBadge,
21678
21662
  formatReportFromFile,
21679
21663
  formatSparkline,
21680
- invalidateFile3 as invalidateFile,
21681
- inventoryPath3 as inventoryPath,
21682
- isComponentFingerprint3 as isComponentFingerprint,
21683
- isConstitutionFile3 as isConstitutionFile,
21684
- isFileMtimeEntry3 as isFileMtimeEntry,
21685
- isInventoryFile3 as isInventoryFile,
21686
- isInventoryFresh3 as isInventoryFresh,
21687
- isMemoryPattern3 as isMemoryPattern,
21688
21664
  loadConfig,
21689
- loadConstitution3 as loadConstitution,
21690
- loadInventory3 as loadInventory,
21691
21665
  readReportFile,
21692
21666
  runCli,
21693
21667
  runInitWizard,
21694
- saveConstitution3 as saveConstitution,
21695
- saveInventory2 as saveInventory,
21696
21668
  scanProject,
21697
21669
  serializeConfig,
21698
21670
  signatureSimilarity,