slopbrick 0.18.2 → 0.18.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.cjs CHANGED
@@ -35284,10 +35284,10 @@ function parseSvelte(source) {
35284
35284
  const ast = parseScriptContent(script.content, isTypeScriptScript(script.openTag));
35285
35285
  return { ast, source };
35286
35286
  }
35287
- function cacheEnabled() {
35287
+ function legacyCacheEnabled() {
35288
35288
  return process.env.SLOP_AUDIT_CACHE === "1" || process.env.SLOP_AUDIT_CACHE === "true";
35289
35289
  }
35290
- function cacheRoot() {
35290
+ function legacyCacheRoot() {
35291
35291
  const override = process.env.SLOP_AUDIT_CACHE_ROOT;
35292
35292
  if (override) return override;
35293
35293
  return (0, import_path2.join)(process.cwd(), ".slopbrick", "cache", "ast");
@@ -35295,11 +35295,11 @@ function cacheRoot() {
35295
35295
  function hashContent(content) {
35296
35296
  return (0, import_crypto.createHash)("md5").update(content, "utf-8").digest("hex");
35297
35297
  }
35298
- function cachePath2(content) {
35299
- return (0, import_path2.join)(cacheRoot(), `${hashContent(content)}.json`);
35298
+ function cachePathWithRoot(content, root) {
35299
+ return (0, import_path2.join)(root, `${hashContent(content)}.json`);
35300
35300
  }
35301
- async function readCache2(filePath, content) {
35302
- const path = cachePath2(content);
35301
+ async function readCacheWithRoot(filePath, content, root) {
35302
+ const path = cachePathWithRoot(content, root);
35303
35303
  try {
35304
35304
  await (0, import_promises.access)(path);
35305
35305
  const raw = await (0, import_promises.readFile)(path, "utf8");
@@ -35312,8 +35312,8 @@ async function readCache2(filePath, content) {
35312
35312
  }
35313
35313
  return void 0;
35314
35314
  }
35315
- async function writeCache(content, result) {
35316
- const path = cachePath2(content);
35315
+ async function writeCacheWithRoot(content, result, root) {
35316
+ const path = cachePathWithRoot(content, root);
35317
35317
  await (0, import_promises.mkdir)((0, import_path2.dirname)(path), { recursive: true });
35318
35318
  await (0, import_promises.writeFile)(path, JSON.stringify(result), "utf8");
35319
35319
  }
@@ -35344,15 +35344,17 @@ function parseSource(source, filePath) {
35344
35344
  return parseWithSwc(source, filePath);
35345
35345
  }
35346
35346
  }
35347
- async function parseFile(filePath) {
35347
+ async function parseFile(filePath, opts) {
35348
35348
  const source = await (0, import_promises.readFile)(filePath, "utf-8");
35349
- if (cacheEnabled()) {
35350
- const cached = await readCache2(filePath, source);
35349
+ const useCache = opts?.cache?.enabled ?? legacyCacheEnabled();
35350
+ const cacheDir = opts?.cache?.root ?? legacyCacheRoot();
35351
+ if (useCache) {
35352
+ const cached = await readCacheWithRoot(filePath, source, cacheDir);
35351
35353
  if (cached) return cached;
35352
35354
  }
35353
35355
  const result = parseSource(source, filePath);
35354
- if (cacheEnabled()) {
35355
- await writeCache(source, result);
35356
+ if (useCache) {
35357
+ await writeCacheWithRoot(source, result, cacheDir);
35356
35358
  }
35357
35359
  return result;
35358
35360
  }
@@ -45790,8 +45792,8 @@ var init_git = __esm({
45790
45792
  });
45791
45793
 
45792
45794
  // src/engine/cache-incremental.ts
45793
- function loadCache(cachePath4) {
45794
- const abs = (0, import_node_path12.isAbsolute)(cachePath4) ? cachePath4 : (0, import_node_path12.resolve)(process.cwd(), cachePath4);
45795
+ function loadCache(cachePath3) {
45796
+ const abs = (0, import_node_path12.isAbsolute)(cachePath3) ? cachePath3 : (0, import_node_path12.resolve)(process.cwd(), cachePath3);
45795
45797
  if (!(0, import_node_fs13.existsSync)(abs)) return void 0;
45796
45798
  try {
45797
45799
  const raw = (0, import_node_fs13.readFileSync)(abs, "utf-8");
@@ -45802,8 +45804,8 @@ function loadCache(cachePath4) {
45802
45804
  return void 0;
45803
45805
  }
45804
45806
  }
45805
- function saveCache(cachePath4, cache) {
45806
- const abs = (0, import_node_path12.isAbsolute)(cachePath4) ? cachePath4 : (0, import_node_path12.resolve)(process.cwd(), cachePath4);
45807
+ function saveCache(cachePath3, cache) {
45808
+ const abs = (0, import_node_path12.isAbsolute)(cachePath3) ? cachePath3 : (0, import_node_path12.resolve)(process.cwd(), cachePath3);
45807
45809
  (0, import_node_fs13.mkdirSync)((0, import_node_path12.dirname)(abs), { recursive: true });
45808
45810
  const tmp = abs + ".tmp";
45809
45811
  if ((0, import_node_fs13.existsSync)(tmp)) {
@@ -47147,6 +47149,12 @@ var init_signal_strength2 = __esm({
47147
47149
  });
47148
47150
 
47149
47151
  // src/engine/worker.ts
47152
+ function buildParserCacheConfig(cwd) {
47153
+ const envVal = process.env.SLOP_AUDIT_CACHE;
47154
+ const enabled = envVal === "1" || envVal === "true";
47155
+ const root = process.env.SLOP_AUDIT_CACHE_ROOT ?? (0, import_node_path14.join)(cwd, ".slopbrick", "cache", "ast");
47156
+ return { enabled, root };
47157
+ }
47150
47158
  function applyRuleOverrides(issues, rules) {
47151
47159
  const result = [];
47152
47160
  for (const issue of issues) {
@@ -47161,6 +47169,7 @@ function applyRuleOverrides(issues, rules) {
47161
47169
  return result;
47162
47170
  }
47163
47171
  async function scanFile(filePath, config, registry, cwd = process.cwd()) {
47172
+ const cache = buildParserCacheConfig(cwd);
47164
47173
  const ext = (0, import_node_path13.extname)(filePath).toLowerCase();
47165
47174
  const UNSUPPORTED_LANGS = /* @__PURE__ */ new Set([
47166
47175
  ".swift",
@@ -47191,7 +47200,7 @@ async function scanFile(filePath, config, registry, cwd = process.cwd()) {
47191
47200
  };
47192
47201
  }
47193
47202
  try {
47194
- const { ast, source } = await parseFile(filePath);
47203
+ const { ast, source } = await parseFile(filePath, { cache });
47195
47204
  const facts = extractFacts(filePath, ast, source, config.supportsRsc ?? true, config.framework ?? "react", config);
47196
47205
  const activeRegistry = registry ?? new RuleRegistry();
47197
47206
  if (!registry) {
@@ -47278,12 +47287,13 @@ function collectStyleSources(facts) {
47278
47287
  }
47279
47288
  return sources;
47280
47289
  }
47281
- var import_node_worker_threads, import_node_path13;
47290
+ var import_node_worker_threads, import_node_path13, import_node_path14;
47282
47291
  var init_worker = __esm({
47283
47292
  "src/engine/worker.ts"() {
47284
47293
  "use strict";
47285
47294
  import_node_worker_threads = require("worker_threads");
47286
47295
  import_node_path13 = require("path");
47296
+ import_node_path14 = require("path");
47287
47297
  init_dist2();
47288
47298
  init_visitor();
47289
47299
  init_registry();
@@ -47401,7 +47411,7 @@ function migrateFlywheelState(state) {
47401
47411
  };
47402
47412
  }
47403
47413
  function loadFlywheelState(cwd) {
47404
- const path = (0, import_node_path14.join)(cwd, FLYWHEEL_DIR, STATE_FILE);
47414
+ const path = (0, import_node_path15.join)(cwd, FLYWHEEL_DIR, STATE_FILE);
47405
47415
  if (!(0, import_node_fs15.existsSync)(path)) {
47406
47416
  return migrateFlywheelState({});
47407
47417
  }
@@ -47413,9 +47423,9 @@ function loadFlywheelState(cwd) {
47413
47423
  }
47414
47424
  }
47415
47425
  function loadResearchMetricsFromDisk(cwd) {
47416
- const flywheelDir = (0, import_node_path14.join)(cwd, FLYWHEEL_DIR);
47417
- const analysisPath = (0, import_node_path14.join)(flywheelDir, "analysis.json");
47418
- const candidatesPath = (0, import_node_path14.join)(flywheelDir, "rule-candidates.json");
47426
+ const flywheelDir = (0, import_node_path15.join)(cwd, FLYWHEEL_DIR);
47427
+ const analysisPath = (0, import_node_path15.join)(flywheelDir, "analysis.json");
47428
+ const candidatesPath = (0, import_node_path15.join)(flywheelDir, "rule-candidates.json");
47419
47429
  const hasAnalysis = (0, import_node_fs15.existsSync)(analysisPath);
47420
47430
  const hasCandidates = (0, import_node_fs15.existsSync)(candidatesPath);
47421
47431
  if (!hasAnalysis && !hasCandidates) return void 0;
@@ -47445,20 +47455,20 @@ function loadResearchMetricsFromDisk(cwd) {
47445
47455
  };
47446
47456
  }
47447
47457
  function saveFlywheelState(cwd, state) {
47448
- const dir = (0, import_node_path14.join)(cwd, FLYWHEEL_DIR);
47458
+ const dir = (0, import_node_path15.join)(cwd, FLYWHEEL_DIR);
47449
47459
  if (!(0, import_node_fs15.existsSync)(dir)) (0, import_node_fs15.mkdirSync)(dir, { recursive: true });
47450
- (0, import_node_fs15.writeFileSync)((0, import_node_path14.join)(dir, STATE_FILE), JSON.stringify(state, null, 2));
47460
+ (0, import_node_fs15.writeFileSync)((0, import_node_path15.join)(dir, STATE_FILE), JSON.stringify(state, null, 2));
47451
47461
  }
47452
47462
  function hashFile(filePath) {
47453
47463
  return (0, import_node_crypto3.createHash)("sha256").update(filePath).digest("hex").slice(0, 16);
47454
47464
  }
47455
- var import_node_crypto3, import_node_fs15, import_node_path14, FLYWHEEL_DIR, STATE_FILE, CONSECUTIVE_THRESHOLD, FLYWHEEL_VERSION;
47465
+ var import_node_crypto3, import_node_fs15, import_node_path15, FLYWHEEL_DIR, STATE_FILE, CONSECUTIVE_THRESHOLD, FLYWHEEL_VERSION;
47456
47466
  var init_flywheel = __esm({
47457
47467
  "src/engine/flywheel.ts"() {
47458
47468
  "use strict";
47459
47469
  import_node_crypto3 = require("crypto");
47460
47470
  import_node_fs15 = require("fs");
47461
- import_node_path14 = require("path");
47471
+ import_node_path15 = require("path");
47462
47472
  FLYWHEEL_DIR = ".slopbrick/flywheel";
47463
47473
  STATE_FILE = "auto-tuned.json";
47464
47474
  CONSECUTIVE_THRESHOLD = 3;
@@ -47596,7 +47606,7 @@ function scoreFile(result, frameworkMultiplier, config, baseline, cwd) {
47596
47606
  100,
47597
47607
  rawScore * frameworkMultiplier * CONTEXT_DENSITY_MULTIPLIER
47598
47608
  );
47599
- const baselineKey = cwd ? (0, import_node_path15.isAbsolute)(result.filePath) ? (0, import_node_path15.relative)(cwd, result.filePath) : result.filePath : result.filePath;
47609
+ const baselineKey = cwd ? (0, import_node_path16.isAbsolute)(result.filePath) ? (0, import_node_path16.relative)(cwd, result.filePath) : result.filePath : result.filePath;
47600
47610
  const baselineScore = baseline?.scores[baselineKey]?.baselineScore ?? 0;
47601
47611
  const adjustedScore = baseline ? Math.max(0, componentScore - baselineScore) : componentScore;
47602
47612
  return {
@@ -47735,11 +47745,11 @@ function aggregateReport(scores, issueGroups, config, compositeScores) {
47735
47745
  ...compositeAggregate && { compositeScore: compositeAggregate }
47736
47746
  };
47737
47747
  }
47738
- var import_node_path15, SEVERITY_WEIGHTS, CONTEXT_DENSITY_MULTIPLIER, COMPOSITE_WEIGHTS, RULE_TO_BUCKET;
47748
+ var import_node_path16, SEVERITY_WEIGHTS, CONTEXT_DENSITY_MULTIPLIER, COMPOSITE_WEIGHTS, RULE_TO_BUCKET;
47739
47749
  var init_metrics = __esm({
47740
47750
  "src/engine/metrics.ts"() {
47741
47751
  "use strict";
47742
- import_node_path15 = require("path");
47752
+ import_node_path16 = require("path");
47743
47753
  init_ai_security_risk();
47744
47754
  init_test_quality();
47745
47755
  SEVERITY_WEIGHTS = {
@@ -47878,7 +47888,7 @@ function hashConfig(config) {
47878
47888
  return (0, import_node_crypto4.createHash)("sha256").update(JSON.stringify(sanitizeForHash(pickBaselineConfig(config)))).digest("hex");
47879
47889
  }
47880
47890
  function baselinePath(projectPath) {
47881
- return (0, import_node_path16.join)(projectPath, ".slopbrick", "cache", "baseline.json");
47891
+ return (0, import_node_path17.join)(projectPath, ".slopbrick", "cache", "baseline.json");
47882
47892
  }
47883
47893
  function isBaselineCache(value) {
47884
47894
  if (!value || typeof value !== "object") return false;
@@ -47921,7 +47931,7 @@ function loadBaseline(projectPath) {
47921
47931
  }
47922
47932
  function saveBaseline(projectPath, cache) {
47923
47933
  const path = baselinePath(projectPath);
47924
- (0, import_node_fs16.mkdirSync)((0, import_node_path16.join)(projectPath, ".slopbrick", "cache"), { recursive: true });
47934
+ (0, import_node_fs16.mkdirSync)((0, import_node_path17.join)(projectPath, ".slopbrick", "cache"), { recursive: true });
47925
47935
  (0, import_node_fs16.writeFileSync)(path, JSON.stringify(cache, null, 2));
47926
47936
  }
47927
47937
  function tightenBaseline(cache) {
@@ -47955,13 +47965,13 @@ function validateBaseline(cache, configHash, gitHead) {
47955
47965
  if (cache.git_head !== gitHead) return { valid: false, reason: "git_head mismatch" };
47956
47966
  return { valid: true };
47957
47967
  }
47958
- var import_node_crypto4, import_node_fs16, import_node_path16, BASELINE_VERSION, BASELINE_HASH_KEYS;
47968
+ var import_node_crypto4, import_node_fs16, import_node_path17, BASELINE_VERSION, BASELINE_HASH_KEYS;
47959
47969
  var init_cache = __esm({
47960
47970
  "src/engine/cache.ts"() {
47961
47971
  "use strict";
47962
47972
  import_node_crypto4 = require("crypto");
47963
47973
  import_node_fs16 = require("fs");
47964
- import_node_path16 = require("path");
47974
+ import_node_path17 = require("path");
47965
47975
  init_types();
47966
47976
  init_config();
47967
47977
  BASELINE_VERSION = VERSION;
@@ -48093,15 +48103,15 @@ var init_tokens = __esm({
48093
48103
  });
48094
48104
 
48095
48105
  // src/cli/memory-io.ts
48096
- var import_promises3, import_node_path17, fsMemoryIO;
48106
+ var import_promises3, import_node_path18, fsMemoryIO;
48097
48107
  var init_memory_io = __esm({
48098
48108
  "src/cli/memory-io.ts"() {
48099
48109
  "use strict";
48100
48110
  import_promises3 = require("fs/promises");
48101
- import_node_path17 = require("path");
48111
+ import_node_path18 = require("path");
48102
48112
  fsMemoryIO = {
48103
48113
  read: (path) => (0, import_promises3.readFile)(path, "utf-8").catch(() => null),
48104
- write: (path, content) => (0, import_promises3.mkdir)((0, import_node_path17.dirname)(path), { recursive: true }).then(
48114
+ write: (path, content) => (0, import_promises3.mkdir)((0, import_node_path18.dirname)(path), { recursive: true }).then(
48105
48115
  () => (0, import_promises3.writeFile)(path, content, "utf-8")
48106
48116
  ),
48107
48117
  exists: (path) => (0, import_promises3.access)(path).then(
@@ -48989,7 +48999,7 @@ async function buildDbHealth(cwd, _config, options = {}) {
48989
48999
  for (const abs of sqlFiles.slice(0, maxFiles)) {
48990
49000
  const parsed = await parseSqlFile(abs);
48991
49001
  if (!parsed) continue;
48992
- const relPath = (0, import_node_path18.relative)(cwd, abs);
49002
+ const relPath = (0, import_node_path19.relative)(cwd, abs);
48993
49003
  parsedFiles.push({ relPath, parsed });
48994
49004
  for (const stmt of parsed.statements) {
48995
49005
  if (stmt.type !== "IndexStmt") continue;
@@ -49044,7 +49054,7 @@ async function buildDbHealth(cwd, _config, options = {}) {
49044
49054
  } catch {
49045
49055
  continue;
49046
49056
  }
49047
- const relPath = (0, import_node_path18.relative)(cwd, abs);
49057
+ const relPath = (0, import_node_path19.relative)(cwd, abs);
49048
49058
  const context = { config: _config, filePath: relPath, cwd };
49049
49059
  const facts = { filePath: relPath, v2: { _source: source } };
49050
49060
  const ruleContext = sqlConcatRule.create(context);
@@ -49090,12 +49100,12 @@ async function buildDbHealth(cwd, _config, options = {}) {
49090
49100
  byRule
49091
49101
  };
49092
49102
  }
49093
- var import_node_fs18, import_node_path18, import_globby3, import_pgsql_parser6, moduleLoaded, DB_RULE_WEIGHTS, DB_FRESHNESS_THRESHOLDS;
49103
+ var import_node_fs18, import_node_path19, import_globby3, import_pgsql_parser6, moduleLoaded, DB_RULE_WEIGHTS, DB_FRESHNESS_THRESHOLDS;
49094
49104
  var init_db_health = __esm({
49095
49105
  "src/engine/db-health.ts"() {
49096
49106
  "use strict";
49097
49107
  import_node_fs18 = require("fs");
49098
- import_node_path18 = require("path");
49108
+ import_node_path19 = require("path");
49099
49109
  import_globby3 = require("globby");
49100
49110
  import_pgsql_parser6 = require("pgsql-parser");
49101
49111
  init_duplicate_index();
@@ -49445,7 +49455,7 @@ function collectBusinessLogicIssues(cwd, filePaths) {
49445
49455
  for (const issue of fileIssues) {
49446
49456
  issues.push({
49447
49457
  ...issue,
49448
- filePath: (0, import_node_path19.relative)(cwd, absPath) || absPath
49458
+ filePath: (0, import_node_path20.relative)(cwd, absPath) || absPath
49449
49459
  });
49450
49460
  }
49451
49461
  }
@@ -49709,12 +49719,12 @@ async function enrichReport(input) {
49709
49719
  domainIssues
49710
49720
  };
49711
49721
  }
49712
- var import_node_fs19, import_node_path19;
49722
+ var import_node_fs19, import_node_path20;
49713
49723
  var init_enrichReport = __esm({
49714
49724
  "src/cli/report/enrichReport.ts"() {
49715
49725
  "use strict";
49716
49726
  import_node_fs19 = require("fs");
49717
- import_node_path19 = require("path");
49727
+ import_node_path20 = require("path");
49718
49728
  init_logger();
49719
49729
  init_error();
49720
49730
  init_architecture_score();
@@ -49829,14 +49839,14 @@ var init_assembleScanReport = __esm({
49829
49839
 
49830
49840
  // src/engine/telemetry.ts
49831
49841
  function telemetryPath2(cwd) {
49832
- return (0, import_node_path20.join)(cwd, TELEMETRY_DIR, TELEMETRY_FILE2);
49842
+ return (0, import_node_path21.join)(cwd, TELEMETRY_DIR, TELEMETRY_FILE2);
49833
49843
  }
49834
49844
  function hashString(input) {
49835
49845
  return (0, import_node_crypto5.createHash)("sha256").update(input).digest("hex").slice(0, 16);
49836
49846
  }
49837
49847
  function safeRelative(cwd, filePath) {
49838
49848
  try {
49839
- return (0, import_node_path20.relative)(cwd, filePath);
49849
+ return (0, import_node_path21.relative)(cwd, filePath);
49840
49850
  } catch {
49841
49851
  return filePath;
49842
49852
  }
@@ -49889,23 +49899,23 @@ function rotateTelemetry(cwd) {
49889
49899
  if (stats.size < MAX_TELEMETRY_BYTES) {
49890
49900
  return;
49891
49901
  }
49892
- const dir = (0, import_node_path20.dirname)(path);
49902
+ const dir = (0, import_node_path21.dirname)(path);
49893
49903
  const timestamp = (/* @__PURE__ */ new Date()).toISOString().replace(/[:.]/g, "-");
49894
- (0, import_node_fs20.renameSync)(path, (0, import_node_path20.join)(dir, `scans-${timestamp}.jsonl`));
49895
- const rotated = (0, import_node_fs20.readdirSync)(dir).filter(isTelemetryFile).map((name) => ({ name, mtime: (0, import_node_fs20.statSync)((0, import_node_path20.join)(dir, name)).mtimeMs })).sort((a, b) => a.mtime - b.mtime);
49904
+ (0, import_node_fs20.renameSync)(path, (0, import_node_path21.join)(dir, `scans-${timestamp}.jsonl`));
49905
+ const rotated = (0, import_node_fs20.readdirSync)(dir).filter(isTelemetryFile).map((name) => ({ name, mtime: (0, import_node_fs20.statSync)((0, import_node_path21.join)(dir, name)).mtimeMs })).sort((a, b) => a.mtime - b.mtime);
49896
49906
  while (rotated.length > MAX_ROTATED_FILES) {
49897
49907
  const oldest = rotated.shift();
49898
49908
  if (oldest) {
49899
- (0, import_node_fs20.rmSync)((0, import_node_path20.join)(dir, oldest.name), { force: true });
49909
+ (0, import_node_fs20.rmSync)((0, import_node_path21.join)(dir, oldest.name), { force: true });
49900
49910
  }
49901
49911
  }
49902
49912
  }
49903
49913
  function readTelemetry(cwd) {
49904
- const dir = (0, import_node_path20.join)(cwd, TELEMETRY_DIR);
49914
+ const dir = (0, import_node_path21.join)(cwd, TELEMETRY_DIR);
49905
49915
  if (!(0, import_node_fs20.existsSync)(dir)) {
49906
49916
  return [];
49907
49917
  }
49908
- const files = (0, import_node_fs20.readdirSync)(dir).filter(isTelemetryFile).sort().map((name) => (0, import_node_path20.join)(dir, name));
49918
+ const files = (0, import_node_fs20.readdirSync)(dir).filter(isTelemetryFile).sort().map((name) => (0, import_node_path21.join)(dir, name));
49909
49919
  const payloads = [];
49910
49920
  for (const file of files) {
49911
49921
  const raw = (0, import_node_fs20.readFileSync)(file, "utf-8");
@@ -49944,7 +49954,7 @@ function recordTelemetry(cwd, report, results, config) {
49944
49954
  files: buildFileRecords(cwd, report, results)
49945
49955
  };
49946
49956
  const path = telemetryPath2(cwd);
49947
- const dir = (0, import_node_path20.dirname)(path);
49957
+ const dir = (0, import_node_path21.dirname)(path);
49948
49958
  if (!(0, import_node_fs20.existsSync)(dir)) {
49949
49959
  (0, import_node_fs20.mkdirSync)(dir, { recursive: true });
49950
49960
  }
@@ -49952,14 +49962,14 @@ function recordTelemetry(cwd, report, results, config) {
49952
49962
  (0, import_node_fs20.appendFileSync)(path, JSON.stringify(payload) + "\n", "utf-8");
49953
49963
  return payload;
49954
49964
  }
49955
- var import_node_fs20, import_node_crypto5, import_node_path20, TELEMETRY_DIR, TELEMETRY_FILE2, MAX_TELEMETRY_BYTES, MAX_ROTATED_FILES;
49965
+ var import_node_fs20, import_node_crypto5, import_node_path21, TELEMETRY_DIR, TELEMETRY_FILE2, MAX_TELEMETRY_BYTES, MAX_ROTATED_FILES;
49956
49966
  var init_telemetry = __esm({
49957
49967
  "src/engine/telemetry.ts"() {
49958
49968
  "use strict";
49959
49969
  import_node_fs20 = require("fs");
49960
49970
  import_node_crypto5 = require("crypto");
49961
- import_node_path20 = require("path");
49962
- TELEMETRY_DIR = (0, import_node_path20.join)(".slopbrick", "flywheel");
49971
+ import_node_path21 = require("path");
49972
+ TELEMETRY_DIR = (0, import_node_path21.join)(".slopbrick", "flywheel");
49963
49973
  TELEMETRY_FILE2 = "scans.jsonl";
49964
49974
  MAX_TELEMETRY_BYTES = 10 * 1024 * 1024;
49965
49975
  MAX_ROTATED_FILES = 5;
@@ -50115,8 +50125,8 @@ function renderStructureMarkdown(inventory, constitution) {
50115
50125
  async function writeStructureMarkdown(workspaceDir, md) {
50116
50126
  await new Promise((resolve42, reject) => {
50117
50127
  try {
50118
- const path = (0, import_node_path21.join)(workspaceDir, STRUCTURE_MD_FILE);
50119
- (0, import_node_fs21.mkdirSync)((0, import_node_path21.dirname)(path), { recursive: true });
50128
+ const path = (0, import_node_path22.join)(workspaceDir, STRUCTURE_MD_FILE);
50129
+ (0, import_node_fs21.mkdirSync)((0, import_node_path22.dirname)(path), { recursive: true });
50120
50130
  (0, import_node_fs21.writeFileSync)(path, md, "utf-8");
50121
50131
  resolve42();
50122
50132
  } catch (err) {
@@ -50127,7 +50137,7 @@ async function writeStructureMarkdown(workspaceDir, md) {
50127
50137
  async function readStructureMarkdown(workspaceDir) {
50128
50138
  return new Promise((resolve42) => {
50129
50139
  try {
50130
- const path = (0, import_node_path21.join)(workspaceDir, STRUCTURE_MD_FILE);
50140
+ const path = (0, import_node_path22.join)(workspaceDir, STRUCTURE_MD_FILE);
50131
50141
  if (!(0, import_node_fs21.existsSync)(path)) {
50132
50142
  resolve42(null);
50133
50143
  return;
@@ -50139,13 +50149,13 @@ async function readStructureMarkdown(workspaceDir) {
50139
50149
  }
50140
50150
  });
50141
50151
  }
50142
- var import_node_fs21, import_node_path21, STRUCTURE_MD_FILE, CATEGORY_LABELS, CATEGORY_ORDER, DECLARED_FIELDS;
50152
+ var import_node_fs21, import_node_path22, STRUCTURE_MD_FILE, CATEGORY_LABELS, CATEGORY_ORDER, DECLARED_FIELDS;
50143
50153
  var init_structure_md = __esm({
50144
50154
  "src/engine/structure-md.ts"() {
50145
50155
  "use strict";
50146
50156
  import_node_fs21 = require("fs");
50147
- import_node_path21 = require("path");
50148
- STRUCTURE_MD_FILE = (0, import_node_path21.join)(".slopbrick", "structure.md");
50157
+ import_node_path22 = require("path");
50158
+ STRUCTURE_MD_FILE = (0, import_node_path22.join)(".slopbrick", "structure.md");
50149
50159
  CATEGORY_LABELS = {
50150
50160
  stateManagement: "State management",
50151
50161
  dataFetching: "Data fetching",
@@ -50219,8 +50229,8 @@ async function persistRun(input) {
50219
50229
  );
50220
50230
  }
50221
50231
  if (options.incremental) {
50222
- const cachePath4 = options.cachePath ?? ".slopbrick-cache.json";
50223
- const existing = loadCache(cachePath4) ?? emptyCache();
50232
+ const cachePath3 = options.cachePath ?? ".slopbrick-cache.json";
50233
+ const existing = loadCache(cachePath3) ?? emptyCache();
50224
50234
  const next = { ...existing, generatedAt: (/* @__PURE__ */ new Date()).toISOString() };
50225
50235
  for (const result of results) {
50226
50236
  try {
@@ -50234,7 +50244,7 @@ async function persistRun(input) {
50234
50244
  } catch {
50235
50245
  }
50236
50246
  }
50237
- saveCache(cachePath4, next);
50247
+ saveCache(cachePath3, next);
50238
50248
  if (incrementalSummary && !options.quiet) {
50239
50249
  logger.info(
50240
50250
  `Incremental: re-scanned ${incrementalSummary.rescanned}, skipped ${incrementalSummary.skipped} (unchanged).`
@@ -50247,7 +50257,7 @@ async function persistRun(input) {
50247
50257
  const recentTopHashes = telemetryPayloads.map(
50248
50258
  (payload) => [...payload.files].sort((a, b) => b.score - a.score).slice(0, 10).map((file) => file.hash)
50249
50259
  );
50250
- const currentTopFiles = [...report.components].sort((a, b) => b.adjustedScore - a.adjustedScore).slice(0, 10).map((c) => ({ filePath: c.filePath, hash: hashFile((0, import_node_path22.relative)(cwd, c.filePath)) }));
50260
+ const currentTopFiles = [...report.components].sort((a, b) => b.adjustedScore - a.adjustedScore).slice(0, 10).map((c) => ({ filePath: c.filePath, hash: hashFile((0, import_node_path23.relative)(cwd, c.filePath)) }));
50251
50261
  const unmatchedStringLiterals = results.flatMap((r) => r.unmatchedStringLiterals ?? []);
50252
50262
  const flywheelOutput = computeFlywheelOutput(
50253
50263
  runs,
@@ -50266,10 +50276,10 @@ async function persistRun(input) {
50266
50276
  report.research = state.research;
50267
50277
  }
50268
50278
  if (flywheelOutput.suggestions.length > 0) {
50269
- const suggestionsDir = (0, import_node_path22.join)(cwd, ".slopbrick", "flywheel");
50279
+ const suggestionsDir = (0, import_node_path23.join)(cwd, ".slopbrick", "flywheel");
50270
50280
  if (!(0, import_node_fs22.existsSync)(suggestionsDir)) (0, import_node_fs22.mkdirSync)(suggestionsDir, { recursive: true });
50271
50281
  (0, import_node_fs22.writeFileSync)(
50272
- (0, import_node_path22.join)(suggestionsDir, "rule-suggestions.json"),
50282
+ (0, import_node_path23.join)(suggestionsDir, "rule-suggestions.json"),
50273
50283
  JSON.stringify(flywheelOutput.suggestions, null, 2)
50274
50284
  );
50275
50285
  }
@@ -50314,12 +50324,12 @@ async function persistRun(input) {
50314
50324
  }
50315
50325
  }
50316
50326
  }
50317
- var import_node_fs22, import_node_path22;
50327
+ var import_node_fs22, import_node_path23;
50318
50328
  var init_persistRun = __esm({
50319
50329
  "src/cli/report/persistRun.ts"() {
50320
50330
  "use strict";
50321
50331
  import_node_fs22 = require("fs");
50322
- import_node_path22 = require("path");
50332
+ import_node_path23 = require("path");
50323
50333
  init_logger();
50324
50334
  init_cache_incremental();
50325
50335
  init_flywheel();
@@ -50458,7 +50468,7 @@ var init_finalizeReport = __esm({
50458
50468
  function buildBaselineCache(report, configHash, gitHead, cwd) {
50459
50469
  const scores = {};
50460
50470
  for (const component of report.components) {
50461
- scores[(0, import_node_path23.relative)(cwd, component.filePath)] = {
50471
+ scores[(0, import_node_path24.relative)(cwd, component.filePath)] = {
50462
50472
  baselineScore: component.componentScore,
50463
50473
  componentCount: component.componentCount
50464
50474
  };
@@ -50473,11 +50483,11 @@ function buildBaselineCache(report, configHash, gitHead, cwd) {
50473
50483
  scores
50474
50484
  };
50475
50485
  }
50476
- var import_node_path23;
50486
+ var import_node_path24;
50477
50487
  var init_baseline_cache = __esm({
50478
50488
  "src/cli/report/baseline-cache.ts"() {
50479
50489
  "use strict";
50480
- import_node_path23 = require("path");
50490
+ import_node_path24 = require("path");
50481
50491
  init_types();
50482
50492
  }
50483
50493
  });
@@ -50541,24 +50551,24 @@ function buildArtifactUri(filePath, cwd) {
50541
50551
  return ".";
50542
50552
  }
50543
50553
  if (cwd) {
50544
- const absoluteFilePath = (0, import_node_path24.isAbsolute)(filePath) ? filePath : (0, import_node_path24.resolve)(cwd, filePath);
50545
- const rel = (0, import_node_path24.relative)(cwd, absoluteFilePath);
50554
+ const absoluteFilePath = (0, import_node_path25.isAbsolute)(filePath) ? filePath : (0, import_node_path25.resolve)(cwd, filePath);
50555
+ const rel = (0, import_node_path25.relative)(cwd, absoluteFilePath);
50546
50556
  if (rel.startsWith("..")) {
50547
- return (0, import_node_path24.basename)(filePath);
50557
+ return (0, import_node_path25.basename)(filePath);
50548
50558
  }
50549
50559
  return rel;
50550
50560
  }
50551
- if ((0, import_node_path24.isAbsolute)(filePath)) {
50552
- return (0, import_node_path24.basename)(filePath);
50561
+ if ((0, import_node_path25.isAbsolute)(filePath)) {
50562
+ return (0, import_node_path25.basename)(filePath);
50553
50563
  }
50554
50564
  return filePath;
50555
50565
  }
50556
50566
  function resolveSourcePath(filePath, cwd) {
50557
50567
  if (!filePath) return null;
50558
50568
  if (cwd) {
50559
- return (0, import_node_path24.isAbsolute)(filePath) ? filePath : (0, import_node_path24.resolve)(cwd, filePath);
50569
+ return (0, import_node_path25.isAbsolute)(filePath) ? filePath : (0, import_node_path25.resolve)(cwd, filePath);
50560
50570
  }
50561
- return (0, import_node_path24.isAbsolute)(filePath) ? filePath : null;
50571
+ return (0, import_node_path25.isAbsolute)(filePath) ? filePath : null;
50562
50572
  }
50563
50573
  function severityToSarifLevel(severity) {
50564
50574
  switch (severity) {
@@ -50713,13 +50723,13 @@ function formatSarif(report, options) {
50713
50723
  };
50714
50724
  return JSON.stringify(log, null, 2);
50715
50725
  }
50716
- var import_node_crypto6, import_node_fs23, import_node_path24, REPO_INFORMATION_URI, RULES_BASE_URL;
50726
+ var import_node_crypto6, import_node_fs23, import_node_path25, REPO_INFORMATION_URI, RULES_BASE_URL;
50717
50727
  var init_sarif = __esm({
50718
50728
  "src/report/sarif.ts"() {
50719
50729
  "use strict";
50720
50730
  import_node_crypto6 = require("crypto");
50721
50731
  import_node_fs23 = require("fs");
50722
- import_node_path24 = require("path");
50732
+ import_node_path25 = require("path");
50723
50733
  REPO_INFORMATION_URI = "https://github.com/brickdotdev/slopbrick";
50724
50734
  RULES_BASE_URL = "https://github.com/Dystx/slopbrick/blob/main/src/rules";
50725
50735
  }
@@ -52005,7 +52015,7 @@ function formatUnifiedDiff(report, cwd) {
52005
52015
  parts.push("");
52006
52016
  hasHunk = true;
52007
52017
  }
52008
- const rel = (0, import_node_path25.relative)(cwd, filePath);
52018
+ const rel = (0, import_node_path26.relative)(cwd, filePath);
52009
52019
  parts.push(`--- a/${rel}`);
52010
52020
  parts.push(`+++ b/${rel}`);
52011
52021
  parts.push(...formatHunk(original, patched));
@@ -52016,12 +52026,12 @@ function formatUnifiedDiff(report, cwd) {
52016
52026
  }
52017
52027
  return parts.join("\n");
52018
52028
  }
52019
- var import_node_fs25, import_node_path25;
52029
+ var import_node_fs25, import_node_path26;
52020
52030
  var init_unified_diff = __esm({
52021
52031
  "src/report/unified-diff.ts"() {
52022
52032
  "use strict";
52023
52033
  import_node_fs25 = require("fs");
52024
- import_node_path25 = require("path");
52034
+ import_node_path26 = require("path");
52025
52035
  init_layout_token();
52026
52036
  }
52027
52037
  });
@@ -52047,7 +52057,7 @@ async function buildHeatmap(report, cwd, helpers = { getFileEditCount, getFileLa
52047
52057
  const reference = new Date(report.generatedAt);
52048
52058
  const entries = await Promise.all(
52049
52059
  report.components.map(async (component) => {
52050
- const relPath = (0, import_node_path26.relative)(cwd, component.filePath) || component.filePath;
52060
+ const relPath = (0, import_node_path27.relative)(cwd, component.filePath) || component.filePath;
52051
52061
  const [edits, lastModified] = await Promise.all([
52052
52062
  helpers.getFileEditCount(cwd, relPath, RECENCY_DAYS),
52053
52063
  helpers.getFileLastModifiedDate(cwd, relPath)
@@ -52092,11 +52102,11 @@ function formatHeatmap(entries, options = {}) {
52092
52102
  );
52093
52103
  return [header, ...rows].join("\n");
52094
52104
  }
52095
- var import_node_path26, RECENCY_DAYS, MAX_EDITS;
52105
+ var import_node_path27, RECENCY_DAYS, MAX_EDITS;
52096
52106
  var init_heatmap = __esm({
52097
52107
  "src/report/heatmap.ts"() {
52098
52108
  "use strict";
52099
- import_node_path26 = require("path");
52109
+ import_node_path27 = require("path");
52100
52110
  init_git();
52101
52111
  RECENCY_DAYS = 30;
52102
52112
  MAX_EDITS = 10;
@@ -52137,7 +52147,7 @@ function renderOutput(report, options, cwd) {
52137
52147
  if (options.html) {
52138
52148
  const html = formatHtml(report);
52139
52149
  if (typeof options.html === "string") {
52140
- (0, import_node_fs26.writeFileSync)((0, import_node_path27.resolve)(options.html), html);
52150
+ (0, import_node_fs26.writeFileSync)((0, import_node_path28.resolve)(options.html), html);
52141
52151
  if (!options.quiet) {
52142
52152
  logger.info(`Wrote HTML report to ${options.html}`);
52143
52153
  }
@@ -52149,7 +52159,7 @@ function renderOutput(report, options, cwd) {
52149
52159
  if (options.json) {
52150
52160
  const json = formatJson(report);
52151
52161
  if (typeof options.json === "string") {
52152
- (0, import_node_fs26.writeFileSync)((0, import_node_path27.resolve)(options.json), json);
52162
+ (0, import_node_fs26.writeFileSync)((0, import_node_path28.resolve)(options.json), json);
52153
52163
  if (!options.quiet) {
52154
52164
  logger.info(`Wrote JSON report to ${options.json}`);
52155
52165
  }
@@ -52163,7 +52173,7 @@ function renderOutput(report, options, cwd) {
52163
52173
  return;
52164
52174
  }
52165
52175
  if (options.format === "sarif") {
52166
- const cwdSarif = (0, import_node_path27.resolve)(options.workspace ?? process.cwd());
52176
+ const cwdSarif = (0, import_node_path28.resolve)(options.workspace ?? process.cwd());
52167
52177
  logger.info(formatSarif(report, { cwd: cwdSarif }));
52168
52178
  return;
52169
52179
  }
@@ -52184,11 +52194,11 @@ async function outputScanResults(report, options, cwd) {
52184
52194
  }
52185
52195
  renderOutput(report, options, cwd);
52186
52196
  }
52187
- var import_node_path27, import_node_fs26, VALID_FORMATS;
52197
+ var import_node_path28, import_node_fs26, VALID_FORMATS;
52188
52198
  var init_renderOutput = __esm({
52189
52199
  "src/cli/report/renderOutput.ts"() {
52190
52200
  "use strict";
52191
- import_node_path27 = require("path");
52201
+ import_node_path28 = require("path");
52192
52202
  import_node_fs26 = require("fs");
52193
52203
  init_logger();
52194
52204
  init_json();
@@ -52327,7 +52337,7 @@ async function watchProject(options, cwd, paths) {
52327
52337
  { recursive: true },
52328
52338
  (_eventType, filename) => {
52329
52339
  if (closed || !filename) return;
52330
- const changedPath = (0, import_node_path28.resolve)(cwd, filename.toString());
52340
+ const changedPath = (0, import_node_path29.resolve)(cwd, filename.toString());
52331
52341
  if (debounceTimer) clearTimeout(debounceTimer);
52332
52342
  debounceTimer = setTimeout(() => {
52333
52343
  debounceTimer = void 0;
@@ -52362,12 +52372,12 @@ async function watchProject(options, cwd, paths) {
52362
52372
  }
52363
52373
  );
52364
52374
  }
52365
- var import_node_fs27, import_node_path28;
52375
+ var import_node_fs27, import_node_path29;
52366
52376
  var init_watch = __esm({
52367
52377
  "src/cli/watch.ts"() {
52368
52378
  "use strict";
52369
52379
  import_node_fs27 = require("fs");
52370
- import_node_path28 = require("path");
52380
+ import_node_path29 = require("path");
52371
52381
  init_metrics();
52372
52382
  init_worker();
52373
52383
  init_threshold();
@@ -52396,7 +52406,7 @@ __export(scan_exports, {
52396
52406
  async function runScan(options, explicitPaths) {
52397
52407
  setLoggerQuiet(!!options.quiet);
52398
52408
  const startTime = Date.now();
52399
- const cwd = (0, import_node_path29.resolve)(options.workspace ?? process.cwd());
52409
+ const cwd = (0, import_node_path30.resolve)(options.workspace ?? process.cwd());
52400
52410
  if (!(0, import_node_fs28.existsSync)(cwd)) {
52401
52411
  throw new Error(`Workspace not found: ${cwd}`);
52402
52412
  }
@@ -52427,7 +52437,7 @@ async function runScan(options, explicitPaths) {
52427
52437
  process.env.SLOP_AUDIT_CACHE = "1";
52428
52438
  }
52429
52439
  if (options.tokens) {
52430
- const tokenResult = readDtcgTokensFile((0, import_node_path29.resolve)(cwd, options.tokens));
52440
+ const tokenResult = readDtcgTokensFile((0, import_node_path30.resolve)(cwd, options.tokens));
52431
52441
  if (tokenResult.ok) {
52432
52442
  const extra = tokensToAllowlist(tokenResult.tree);
52433
52443
  config.arbitraryValueAllowlist = [...config.arbitraryValueAllowlist, ...extra];
@@ -52439,14 +52449,14 @@ async function runScan(options, explicitPaths) {
52439
52449
  if (explicitPaths && explicitPaths.length > 0) {
52440
52450
  const { globby: globby4 } = await import("globby");
52441
52451
  const { minimatch: minimatch3 } = await import("minimatch");
52442
- const resolved = explicitPaths.map((p) => (0, import_node_path29.resolve)(cwd, p));
52452
+ const resolved = explicitPaths.map((p) => (0, import_node_path30.resolve)(cwd, p));
52443
52453
  const expanded = [];
52444
52454
  for (const p of resolved) {
52445
52455
  if ((0, import_node_fs28.existsSync)(p) && (0, import_node_fs28.statSync)(p).isDirectory()) {
52446
52456
  const found = await globby4(`${p}/**/*`, { absolute: true, onlyFiles: true });
52447
52457
  for (const f of found) {
52448
- if (!ALL_SOURCE_EXTENSIONS.has((0, import_node_path29.extname)(f).toLowerCase())) continue;
52449
- const rel = (0, import_node_path29.relative)(cwd, f).split(import_node_path29.sep).join("/");
52458
+ if (!ALL_SOURCE_EXTENSIONS.has((0, import_node_path30.extname)(f).toLowerCase())) continue;
52459
+ const rel = (0, import_node_path30.relative)(cwd, f).split(import_node_path30.sep).join("/");
52450
52460
  if (config.include.length > 0 && !config.include.some((pattern) => minimatch3(rel, pattern))) {
52451
52461
  continue;
52452
52462
  }
@@ -52481,8 +52491,8 @@ async function runScan(options, explicitPaths) {
52481
52491
  }
52482
52492
  let incrementalSummary;
52483
52493
  if (options.incremental) {
52484
- const cachePath4 = options.cachePath ?? ".slopbrick-cache.json";
52485
- const existing = loadCache(cachePath4);
52494
+ const cachePath3 = options.cachePath ?? ".slopbrick-cache.json";
52495
+ const existing = loadCache(cachePath3);
52486
52496
  const { toScan, unchanged } = partitionByCache(files, existing);
52487
52497
  files = toScan;
52488
52498
  incrementalSummary = { skipped: unchanged.length, rescanned: toScan.length };
@@ -52656,12 +52666,12 @@ async function scanProject(options) {
52656
52666
  const { report } = await runScan({ ...options, workspace: options.cwd });
52657
52667
  return report;
52658
52668
  }
52659
- var import_node_fs28, import_node_path29;
52669
+ var import_node_fs28, import_node_path30;
52660
52670
  var init_scan = __esm({
52661
52671
  "src/cli/scan.ts"() {
52662
52672
  "use strict";
52663
52673
  import_node_fs28 = require("fs");
52664
- import_node_path29 = require("path");
52674
+ import_node_path30 = require("path");
52665
52675
  init_render();
52666
52676
  init_threshold();
52667
52677
  init_config();
@@ -52867,7 +52877,7 @@ async function runGovernance(args, ctx) {
52867
52877
  function runCheckConstitution(args, ctx) {
52868
52878
  const path = args.path;
52869
52879
  if (!path) return toolError("Missing required argument: path");
52870
- const absPath = (0, import_node_path37.resolve)(ctx.cwd, path);
52880
+ const absPath = (0, import_node_path38.resolve)(ctx.cwd, path);
52871
52881
  let source;
52872
52882
  try {
52873
52883
  source = (0, import_node_fs32.readFileSync)(absPath, "utf-8");
@@ -53057,12 +53067,12 @@ function canonicalToolNames() {
53057
53067
  function getDeprecation(toolName) {
53058
53068
  return TOOL_DEFINITIONS.find((t) => t.name === toolName)?.deprecated;
53059
53069
  }
53060
- var import_node_fs32, import_node_path37, TOOL_DEFINITIONS;
53070
+ var import_node_fs32, import_node_path38, TOOL_DEFINITIONS;
53061
53071
  var init_tools = __esm({
53062
53072
  "src/mcp/tools.ts"() {
53063
53073
  "use strict";
53064
53074
  import_node_fs32 = require("fs");
53065
- import_node_path37 = require("path");
53075
+ import_node_path38 = require("path");
53066
53076
  init_worker();
53067
53077
  init_patterns();
53068
53078
  init_architecture_score();
@@ -53320,7 +53330,7 @@ init_config();
53320
53330
  init_dist2();
53321
53331
 
53322
53332
  // src/cli/program.ts
53323
- var import_node_path69 = require("path");
53333
+ var import_node_path70 = require("path");
53324
53334
  var import_node_perf_hooks = require("perf_hooks");
53325
53335
  var import_commander2 = require("commander");
53326
53336
 
@@ -53365,7 +53375,7 @@ init_scan();
53365
53375
 
53366
53376
  // src/cli/init.ts
53367
53377
  var import_node_fs30 = require("fs");
53368
- var import_node_path31 = require("path");
53378
+ var import_node_path32 = require("path");
53369
53379
  var import_node_readline = require("readline");
53370
53380
  init_config();
53371
53381
  init_discover();
@@ -53375,7 +53385,7 @@ init_logger();
53375
53385
 
53376
53386
  // src/rules/registry-loader.ts
53377
53387
  var import_node_fs29 = require("fs");
53378
- var import_node_path30 = require("path");
53388
+ var import_node_path31 = require("path");
53379
53389
 
53380
53390
  // src/data/shadcn-registry.json
53381
53391
  var shadcn_registry_default = {
@@ -53508,11 +53518,11 @@ var shadcn_registry_default = {
53508
53518
  // src/rules/registry-loader.ts
53509
53519
  var REGISTRY_URL = "https://ui.shadcn.com/registry.json";
53510
53520
  var BUNDLED_REGISTRY_VERSION = shadcn_registry_default.version;
53511
- function cachePath3(cwd) {
53512
- return (0, import_node_path30.join)(cwd, ".slopbrick", "cache", "registry-snapshot.json");
53521
+ function cachePath2(cwd) {
53522
+ return (0, import_node_path31.join)(cwd, ".slopbrick", "cache", "registry-snapshot.json");
53513
53523
  }
53514
53524
  function ensureCacheDir(cwd) {
53515
- const dir = (0, import_node_path30.dirname)(cachePath3(cwd));
53525
+ const dir = (0, import_node_path31.dirname)(cachePath2(cwd));
53516
53526
  if (!(0, import_node_fs29.existsSync)(dir)) {
53517
53527
  (0, import_node_fs29.mkdirSync)(dir, { recursive: true });
53518
53528
  }
@@ -53525,7 +53535,7 @@ function isValidSnapshot(value) {
53525
53535
  return true;
53526
53536
  }
53527
53537
  function isRegistryFresh(cwd) {
53528
- const cached = cachePath3(cwd);
53538
+ const cached = cachePath2(cwd);
53529
53539
  if (!(0, import_node_fs29.existsSync)(cached)) return false;
53530
53540
  try {
53531
53541
  const parsed = JSON.parse((0, import_node_fs29.readFileSync)(cached, "utf8"));
@@ -53562,7 +53572,7 @@ async function refreshRegistrySnapshot(cwd, url = REGISTRY_URL, timeoutMs = 5e3)
53562
53572
  };
53563
53573
  }
53564
53574
  ensureCacheDir(cwd);
53565
- (0, import_node_fs29.writeFileSync)(cachePath3(cwd), JSON.stringify(fetched, null, 2));
53575
+ (0, import_node_fs29.writeFileSync)(cachePath2(cwd), JSON.stringify(fetched, null, 2));
53566
53576
  const fresh = fetched.version === BUNDLED_REGISTRY_VERSION;
53567
53577
  return {
53568
53578
  ok: true,
@@ -53572,7 +53582,7 @@ async function refreshRegistrySnapshot(cwd, url = REGISTRY_URL, timeoutMs = 5e3)
53572
53582
  }
53573
53583
  function copyBundledSnapshotToCache(cwd) {
53574
53584
  ensureCacheDir(cwd);
53575
- (0, import_node_fs29.writeFileSync)(cachePath3(cwd), JSON.stringify(shadcn_registry_default, null, 2));
53585
+ (0, import_node_fs29.writeFileSync)(cachePath2(cwd), JSON.stringify(shadcn_registry_default, null, 2));
53576
53586
  }
53577
53587
 
53578
53588
  // src/cli/init.ts
@@ -53761,8 +53771,8 @@ async function runDoctor(cwd) {
53761
53771
  }
53762
53772
  try {
53763
53773
  const { parseFile: tryParse } = await Promise.resolve().then(() => (init_dist2(), dist_exports2));
53764
- const testFile = (0, import_node_path31.join)(cwd, ".slopbrick", ".doctor-test.ts");
53765
- (0, import_node_fs30.mkdirSync)((0, import_node_path31.dirname)(testFile), { recursive: true });
53774
+ const testFile = (0, import_node_path32.join)(cwd, ".slopbrick", ".doctor-test.ts");
53775
+ (0, import_node_fs30.mkdirSync)((0, import_node_path32.dirname)(testFile), { recursive: true });
53766
53776
  (0, import_node_fs30.writeFileSync)(testFile, "export const x = 1;\n");
53767
53777
  await tryParse(testFile);
53768
53778
  (0, import_node_fs30.rmSync)(testFile, { force: true });
@@ -53854,7 +53864,7 @@ async function runDoctor(cwd) {
53854
53864
  }
53855
53865
 
53856
53866
  // src/cli/commands/badge.ts
53857
- var import_node_path32 = require("path");
53867
+ var import_node_path33 = require("path");
53858
53868
  init_render();
53859
53869
  init_logger();
53860
53870
  init_scan();
@@ -53863,7 +53873,7 @@ function registerBadge(program) {
53863
53873
  "print a shields.io slop-index badge. Reads .slopbrick/health.json if present (no re-scan); falls back to a fresh scan."
53864
53874
  ).action(async (_cmdOptions, command) => {
53865
53875
  const options = command.optsWithGlobals();
53866
- const cwd = (0, import_node_path32.resolve)(options.workspace ?? process.cwd());
53876
+ const cwd = (0, import_node_path33.resolve)(options.workspace ?? process.cwd());
53867
53877
  const { loadHealth: loadHealth2 } = await Promise.resolve().then(() => (init_dist(), dist_exports));
53868
53878
  const health = loadHealth2(cwd);
53869
53879
  if (health) {
@@ -53880,7 +53890,7 @@ function registerBadge(program) {
53880
53890
  }
53881
53891
 
53882
53892
  // src/cli/commands/suggest.ts
53883
- var import_node_path33 = require("path");
53893
+ var import_node_path34 = require("path");
53884
53894
  init_advice();
53885
53895
  init_unified_diff();
53886
53896
  init_logger();
@@ -53889,7 +53899,7 @@ function registerSuggest(program) {
53889
53899
  program.command("suggest").description("print remediation advice").action(async (_cmdOptions, command) => {
53890
53900
  const options = command.optsWithGlobals();
53891
53901
  const { report } = await runScan(options);
53892
- const cwd = (0, import_node_path33.resolve)(options.workspace ?? process.cwd());
53902
+ const cwd = (0, import_node_path34.resolve)(options.workspace ?? process.cwd());
53893
53903
  logger.info(formatAdvice(report));
53894
53904
  const diff = formatUnifiedDiff(report, cwd);
53895
53905
  if (diff) logger.info(diff);
@@ -54082,13 +54092,13 @@ function registerExplain(program) {
54082
54092
  }
54083
54093
 
54084
54094
  // src/cli/commands/install.ts
54085
- var import_node_path35 = require("path");
54095
+ var import_node_path36 = require("path");
54086
54096
  init_logger();
54087
54097
  init_git();
54088
54098
 
54089
54099
  // src/cli/installer.ts
54090
54100
  var import_node_fs31 = require("fs");
54091
- var import_node_path34 = require("path");
54101
+ var import_node_path35 = require("path");
54092
54102
  var BEGIN_SENTINEL = "# slopbrick-hook-begin";
54093
54103
  var END_SENTINEL = "# slopbrick-hook-end";
54094
54104
  var SENTINEL_BLOCK = `${BEGIN_SENTINEL}
@@ -54096,11 +54106,11 @@ npx slopbrick --staged
54096
54106
  ${END_SENTINEL}
54097
54107
  `;
54098
54108
  function hookPath(gitRoot) {
54099
- const huskyDir = (0, import_node_path34.join)(gitRoot, ".husky");
54109
+ const huskyDir = (0, import_node_path35.join)(gitRoot, ".husky");
54100
54110
  if ((0, import_node_fs31.existsSync)(huskyDir)) {
54101
- return (0, import_node_path34.join)(huskyDir, "pre-commit");
54111
+ return (0, import_node_path35.join)(huskyDir, "pre-commit");
54102
54112
  }
54103
- return (0, import_node_path34.join)(gitRoot, ".git", "hooks", "pre-commit");
54113
+ return (0, import_node_path35.join)(gitRoot, ".git", "hooks", "pre-commit");
54104
54114
  }
54105
54115
  function readHookContent(path) {
54106
54116
  return (0, import_node_fs31.readFileSync)(path, "utf8");
@@ -54165,7 +54175,7 @@ function installHook(gitRoot) {
54165
54175
  exitCode: 0
54166
54176
  };
54167
54177
  }
54168
- (0, import_node_fs31.mkdirSync)((0, import_node_path34.dirname)(path), { recursive: true });
54178
+ (0, import_node_fs31.mkdirSync)((0, import_node_path35.dirname)(path), { recursive: true });
54169
54179
  (0, import_node_fs31.writeFileSync)(path, SENTINEL_BLOCK, { mode: 493 });
54170
54180
  (0, import_node_fs31.chmodSync)(path, 493);
54171
54181
  return {
@@ -54225,7 +54235,7 @@ function uninstallHook(gitRoot) {
54225
54235
  function registerInstall(program) {
54226
54236
  program.command("install").description("install the git pre-commit hook").action(async (_cmdOptions, command) => {
54227
54237
  const options = command.optsWithGlobals();
54228
- const cwd = (0, import_node_path35.resolve)(options.workspace ?? process.cwd());
54238
+ const cwd = (0, import_node_path36.resolve)(options.workspace ?? process.cwd());
54229
54239
  const root = getGitRoot(cwd);
54230
54240
  if (!root) {
54231
54241
  logger.error("Not a Git repository. Run `git init` first, or remove --staged from your command.");
@@ -54240,13 +54250,13 @@ function registerInstall(program) {
54240
54250
  }
54241
54251
 
54242
54252
  // src/cli/commands/uninstall.ts
54243
- var import_node_path36 = require("path");
54253
+ var import_node_path37 = require("path");
54244
54254
  init_logger();
54245
54255
  init_git();
54246
54256
  function registerUninstall(program) {
54247
54257
  program.command("uninstall").description("uninstall the git pre-commit hook").action(async (_cmdOptions, command) => {
54248
54258
  const options = command.optsWithGlobals();
54249
- const cwd = (0, import_node_path36.resolve)(options.workspace ?? process.cwd());
54259
+ const cwd = (0, import_node_path37.resolve)(options.workspace ?? process.cwd());
54250
54260
  const root = getGitRoot(cwd);
54251
54261
  if (!root) {
54252
54262
  logger.error("Not a Git repository. Run `git init` first, or remove --staged from your command.");
@@ -54392,7 +54402,7 @@ function registerDoctor(program) {
54392
54402
  }
54393
54403
 
54394
54404
  // src/cli/commands/watch.ts
54395
- var import_node_path38 = require("path");
54405
+ var import_node_path39 = require("path");
54396
54406
  init_watch();
54397
54407
  function registerWatch(program, scanAction) {
54398
54408
  program.command("watch").description("re-run scan on every file change. Flags new violations as you write. The LockBrick prevention loop entry.").action(async (_cmdOptions, command) => {
@@ -54401,19 +54411,19 @@ function registerWatch(program, scanAction) {
54401
54411
  ...rawGlobals,
54402
54412
  noIncrease: rawGlobals.increase === false
54403
54413
  };
54404
- const cwd = (0, import_node_path38.resolve)(options.workspace ?? process.cwd());
54414
+ const cwd = (0, import_node_path39.resolve)(options.workspace ?? process.cwd());
54405
54415
  await scanAction([], options, command);
54406
54416
  await watchProject(options, cwd, []);
54407
54417
  });
54408
54418
  }
54409
54419
 
54410
54420
  // src/cli/commands/lock.ts
54411
- var import_node_path39 = require("path");
54421
+ var import_node_path40 = require("path");
54412
54422
  init_logger();
54413
54423
  function registerLock(program) {
54414
54424
  program.command("lock").description("install a Git pre-commit hook that runs `slopbrick scan --staged` on every commit. The LockBrick prevention loop: block AI-introduced slop from ever reaching the repo.").option("--uninstall", "remove the pre-commit hook instead of installing it").option("--husky", "force-install under .husky/pre-commit (Husky v9). Default auto-detects via .husky/ dir.").option("--workspace <path>", "workspace directory", process.cwd()).action(
54415
54425
  (cmdOptions) => {
54416
- const cwd = (0, import_node_path39.resolve)(cmdOptions.workspace ?? process.cwd());
54426
+ const cwd = (0, import_node_path40.resolve)(cmdOptions.workspace ?? process.cwd());
54417
54427
  if (cmdOptions.uninstall) {
54418
54428
  const result2 = uninstallHook(cwd);
54419
54429
  logger.info(result2.message);
@@ -54434,7 +54444,7 @@ function registerLock(program) {
54434
54444
  }
54435
54445
 
54436
54446
  // src/cli/commands/ci.ts
54437
- var import_node_path40 = require("path");
54447
+ var import_node_path41 = require("path");
54438
54448
  init_logger();
54439
54449
  init_dist();
54440
54450
  function registerCi(program, scanAction) {
@@ -54449,7 +54459,7 @@ function registerCi(program, scanAction) {
54449
54459
  // scan only changed files
54450
54460
  format: cmdOptions.format ?? "json"
54451
54461
  };
54452
- const cwd = (0, import_node_path40.resolve)(options.workspace ?? process.cwd());
54462
+ const cwd = (0, import_node_path41.resolve)(options.workspace ?? process.cwd());
54453
54463
  await scanAction([], options, command);
54454
54464
  const health = loadHealth(cwd);
54455
54465
  if (!health) {
@@ -54477,12 +54487,12 @@ function registerCi(program, scanAction) {
54477
54487
  }
54478
54488
 
54479
54489
  // src/cli/commands/memory.ts
54480
- var import_node_path41 = require("path");
54490
+ var import_node_path42 = require("path");
54481
54491
  init_logger();
54482
54492
  function registerMemory(program) {
54483
54493
  program.command("memory").description("show or regenerate .slopbrick/structure.md (the agent-readable repository summary) without re-scanning").option("--show", "print the current .slopbrick/structure.md to stdout (default if no flag is passed)").option("--regenerate", "re-render structure.md from the existing inventory.json + constitution.json (no scan)").option("--workspace <path>", "workspace directory", process.cwd()).action(
54484
54494
  async (cmdOptions) => {
54485
- const cwd = (0, import_node_path41.resolve)(cmdOptions.workspace ?? process.cwd());
54495
+ const cwd = (0, import_node_path42.resolve)(cmdOptions.workspace ?? process.cwd());
54486
54496
  const { renderStructureMarkdown: renderStructureMarkdown2, readStructureMarkdown: readStructureMarkdown2, writeStructureMarkdown: writeStructureMarkdown2 } = await Promise.resolve().then(() => (init_structure_md(), structure_md_exports));
54487
54497
  const { loadInventory: loadInventory2, loadConstitution: loadConstitution2, inventoryPath: invPath, constitutionPath: conPath } = await Promise.resolve().then(() => (init_dist(), dist_exports));
54488
54498
  if (cmdOptions.regenerate) {
@@ -54512,47 +54522,47 @@ function registerMemory(program) {
54512
54522
  }
54513
54523
 
54514
54524
  // src/cli/commands/migrate.ts
54515
- var import_node_path43 = require("path");
54525
+ var import_node_path44 = require("path");
54516
54526
  init_logger();
54517
54527
 
54518
54528
  // src/cli/migrate.ts
54519
54529
  var import_node_fs33 = require("fs");
54520
- var import_node_path42 = require("path");
54530
+ var import_node_path43 = require("path");
54521
54531
  init_logger();
54522
54532
  function planMigration(workspaceDir) {
54523
54533
  const moves = [];
54524
54534
  const rewrites = [];
54525
54535
  const gitignoreEdits = [];
54526
- const oldDir = (0, import_node_path42.join)(workspaceDir, ".slop-audit");
54527
- const newDir = (0, import_node_path42.join)(workspaceDir, ".slopbrick");
54536
+ const oldDir = (0, import_node_path43.join)(workspaceDir, ".slop-audit");
54537
+ const newDir = (0, import_node_path43.join)(workspaceDir, ".slopbrick");
54528
54538
  if ((0, import_node_fs33.existsSync)(oldDir)) {
54529
54539
  moves.push({ from: oldDir, to: newDir, kind: "dir" });
54530
54540
  rewrites.push({
54531
- path: (0, import_node_path42.join)(newDir, "inventory.json"),
54541
+ path: (0, import_node_path43.join)(newDir, "inventory.json"),
54532
54542
  field: "version",
54533
54543
  from: '"1"',
54534
54544
  to: '"2"'
54535
54545
  });
54536
54546
  rewrites.push({
54537
- path: (0, import_node_path42.join)(newDir, "constitution.json"),
54547
+ path: (0, import_node_path43.join)(newDir, "constitution.json"),
54538
54548
  field: "version",
54539
54549
  from: '"1"',
54540
54550
  to: '"2"'
54541
54551
  });
54542
54552
  }
54543
- const oldCache = (0, import_node_path42.join)(workspaceDir, ".slop-audit-cache.json");
54544
- const newCache = (0, import_node_path42.join)(workspaceDir, ".slopbrick-cache.json");
54553
+ const oldCache = (0, import_node_path43.join)(workspaceDir, ".slop-audit-cache.json");
54554
+ const newCache = (0, import_node_path43.join)(workspaceDir, ".slopbrick-cache.json");
54545
54555
  if ((0, import_node_fs33.existsSync)(oldCache)) {
54546
54556
  moves.push({ from: oldCache, to: newCache, kind: "file" });
54547
54557
  }
54548
54558
  for (const ext of ["mjs", "cjs", "js"]) {
54549
- const oldCfg = (0, import_node_path42.join)(workspaceDir, `slop-audit.config.${ext}`);
54550
- const newCfg = (0, import_node_path42.join)(workspaceDir, `slopbrick.config.${ext}`);
54559
+ const oldCfg = (0, import_node_path43.join)(workspaceDir, `slop-audit.config.${ext}`);
54560
+ const newCfg = (0, import_node_path43.join)(workspaceDir, `slopbrick.config.${ext}`);
54551
54561
  if ((0, import_node_fs33.existsSync)(oldCfg)) {
54552
54562
  moves.push({ from: oldCfg, to: newCfg, kind: "config" });
54553
54563
  }
54554
54564
  }
54555
- const gi = (0, import_node_path42.join)(workspaceDir, ".gitignore");
54565
+ const gi = (0, import_node_path43.join)(workspaceDir, ".gitignore");
54556
54566
  if ((0, import_node_fs33.existsSync)(gi)) {
54557
54567
  const content = (0, import_node_fs33.readFileSync)(gi, "utf-8");
54558
54568
  if (content.includes(".slop-audit/")) {
@@ -54573,7 +54583,7 @@ function planMigration(workspaceDir) {
54573
54583
  return { moves, rewrites, gitignoreEdits };
54574
54584
  }
54575
54585
  function isAlreadyMigrated(workspaceDir) {
54576
- return (0, import_node_fs33.existsSync)((0, import_node_path42.join)(workspaceDir, ".slopbrick")) && !(0, import_node_fs33.existsSync)((0, import_node_path42.join)(workspaceDir, ".slop-audit"));
54586
+ return (0, import_node_fs33.existsSync)((0, import_node_path43.join)(workspaceDir, ".slopbrick")) && !(0, import_node_fs33.existsSync)((0, import_node_path43.join)(workspaceDir, ".slop-audit"));
54577
54587
  }
54578
54588
  function applyMigration(plan, options = {}) {
54579
54589
  if (options.dryRun) return;
@@ -54604,8 +54614,8 @@ function runMigrate(options) {
54604
54614
  };
54605
54615
  }
54606
54616
  const alreadyMigrated = isAlreadyMigrated(workspace);
54607
- const newDir = (0, import_node_path42.join)(workspace, ".slopbrick");
54608
- const oldDir = (0, import_node_path42.join)(workspace, ".slop-audit");
54617
+ const newDir = (0, import_node_path43.join)(workspace, ".slopbrick");
54618
+ const oldDir = (0, import_node_path43.join)(workspace, ".slop-audit");
54609
54619
  if ((0, import_node_fs33.existsSync)(newDir) && (0, import_node_fs33.existsSync)(oldDir) && !force) {
54610
54620
  return {
54611
54621
  ok: false,
@@ -54682,7 +54692,7 @@ function registerMigrate(program) {
54682
54692
  (cmdOptions, command) => {
54683
54693
  const globals = command.optsWithGlobals();
54684
54694
  const format = (cmdOptions.format ?? globals.format) === "json" ? "json" : "pretty";
54685
- const cwd = (0, import_node_path43.resolve)(cmdOptions.workspace ?? process.cwd());
54695
+ const cwd = (0, import_node_path44.resolve)(cmdOptions.workspace ?? process.cwd());
54686
54696
  const result = runMigrate({
54687
54697
  workspace: cwd,
54688
54698
  dryRun: cmdOptions.dryRun,
@@ -54787,18 +54797,18 @@ function registerRules(program) {
54787
54797
 
54788
54798
  // src/cli/commands/validate-config.ts
54789
54799
  var import_node_fs34 = require("fs");
54790
- var import_node_path44 = require("path");
54800
+ var import_node_path45 = require("path");
54791
54801
  init_logger();
54792
54802
  init_validation();
54793
54803
  function registerValidateConfig(program) {
54794
54804
  program.command("validate-config [path]").description("Statically validate a slopbrick.config.mjs without scanning").action(async (configPath) => {
54795
- const path = configPath ? (0, import_node_path44.resolve)(configPath) : (0, import_node_path44.resolve)(process.cwd(), "slopbrick.config.mjs");
54805
+ const path = configPath ? (0, import_node_path45.resolve)(configPath) : (0, import_node_path45.resolve)(process.cwd(), "slopbrick.config.mjs");
54796
54806
  if (!(0, import_node_fs34.existsSync)(path)) {
54797
54807
  logger.error(`Error: config file not found: ${path}`);
54798
54808
  process.exit(2);
54799
54809
  }
54800
54810
  try {
54801
- const mod = (0, import_node_path44.extname)(path) === ".cjs" ? require(path) : await import(path);
54811
+ const mod = (0, import_node_path45.extname)(path) === ".cjs" ? require(path) : await import(path);
54802
54812
  const userConfig = mod.default ?? mod;
54803
54813
  const result = validateConfig(userConfig);
54804
54814
  if (result.errors.length === 0) {
@@ -55019,7 +55029,7 @@ ${formatMarkdown(result.report)}`);
55019
55029
 
55020
55030
  // src/cli/commands/calibrate.ts
55021
55031
  var import_node_fs37 = require("fs");
55022
- var import_node_path48 = require("path");
55032
+ var import_node_path49 = require("path");
55023
55033
  init_logger();
55024
55034
 
55025
55035
  // src/research/providers/openai.ts
@@ -55076,7 +55086,7 @@ function createProvider(config) {
55076
55086
 
55077
55087
  // src/research/generator.ts
55078
55088
  var import_node_fs35 = require("fs");
55079
- var import_node_path45 = require("path");
55089
+ var import_node_path46 = require("path");
55080
55090
 
55081
55091
  // src/research/prompts.ts
55082
55092
  var DEFAULT_PROMPT_TEMPLATES = [
@@ -55139,13 +55149,13 @@ async function generateSamples(options) {
55139
55149
  }
55140
55150
  const samples = [];
55141
55151
  const ext = extForFramework(framework);
55142
- const dir = (0, import_node_path45.join)(outputDir, framework, componentType);
55152
+ const dir = (0, import_node_path46.join)(outputDir, framework, componentType);
55143
55153
  (0, import_node_fs35.mkdirSync)(dir, { recursive: true });
55144
55154
  for (let i = 1; i <= count; i += 1) {
55145
55155
  const raw = await provider.generateSample(renderPrompt(template), { temperature });
55146
55156
  const code = extractCodeFromMarkdown(raw);
55147
55157
  const fileName = `sample-${i}${ext}`;
55148
- const filePath = (0, import_node_path45.join)(dir, fileName);
55158
+ const filePath = (0, import_node_path46.join)(dir, fileName);
55149
55159
  (0, import_node_fs35.writeFileSync)(filePath, code, "utf8");
55150
55160
  const sample = {
55151
55161
  filePath,
@@ -55157,7 +55167,7 @@ async function generateSamples(options) {
55157
55167
  };
55158
55168
  samples.push(sample);
55159
55169
  }
55160
- const metadataPath = (0, import_node_path45.join)(dir, "metadata.json");
55170
+ const metadataPath = (0, import_node_path46.join)(dir, "metadata.json");
55161
55171
  (0, import_node_fs35.writeFileSync)(metadataPath, JSON.stringify(samples, null, 2), "utf8");
55162
55172
  return samples;
55163
55173
  }
@@ -55365,20 +55375,20 @@ function slugify(value) {
55365
55375
  // src/research/calibrator.ts
55366
55376
  var import_node_child_process2 = require("child_process");
55367
55377
  var import_node_fs36 = require("fs");
55368
- var import_node_path47 = require("path");
55378
+ var import_node_path48 = require("path");
55369
55379
 
55370
55380
  // src/corpus-paths.ts
55371
- var import_node_path46 = require("path");
55381
+ var import_node_path47 = require("path");
55372
55382
  var CORPUS_ROOT = process.env["SLOPBRICK_CORPUS_DIR"] ?? "/Users/cheng/corpus-expansion";
55373
- var POSITIVE_DIR = (0, import_node_path46.join)(CORPUS_ROOT, "positive");
55374
- var NEGATIVE_DIR = (0, import_node_path46.join)(CORPUS_ROOT, "negative");
55375
- var FILELISTS_DIR = (0, import_node_path46.join)(CORPUS_ROOT, "filelists");
55383
+ var POSITIVE_DIR = (0, import_node_path47.join)(CORPUS_ROOT, "positive");
55384
+ var NEGATIVE_DIR = (0, import_node_path47.join)(CORPUS_ROOT, "negative");
55385
+ var FILELISTS_DIR = (0, import_node_path47.join)(CORPUS_ROOT, "filelists");
55376
55386
 
55377
55387
  // src/research/calibrator.ts
55378
55388
  var DEFAULT_POSITIVE = POSITIVE_DIR;
55379
55389
  var DEFAULT_NEGATIVE = NEGATIVE_DIR;
55380
55390
  function buildFileList(dir, extensions) {
55381
- const tmpList = (0, import_node_path47.join)("/tmp", `cal-build-${Date.now()}-${Math.random().toString(36).slice(2)}.txt`);
55391
+ const tmpList = (0, import_node_path48.join)("/tmp", `cal-build-${Date.now()}-${Math.random().toString(36).slice(2)}.txt`);
55382
55392
  const expr = extensions.map((e) => `-name '*.${e}'`).join(" -o ");
55383
55393
  (0, import_node_child_process2.execFileSync)("bash", ["-c", `find ${dir} -maxdepth 8 -type f \\( ${expr} \\) -print0 | xargs -0 realpath > ${tmpList}`]);
55384
55394
  const out = (0, import_node_fs36.readFileSync)(tmpList, "utf8");
@@ -55391,13 +55401,13 @@ function runScan2(fileListPath) {
55391
55401
  const ruleFires = /* @__PURE__ */ new Map();
55392
55402
  const uniqueFilesPerRule = /* @__PURE__ */ new Map();
55393
55403
  let fileCount = 0;
55394
- const tmpOut = (0, import_node_path47.join)("/tmp", `calibrate-${Date.now()}-${Math.random().toString(36).slice(2)}.json`);
55404
+ const tmpOut = (0, import_node_path48.join)("/tmp", `calibrate-${Date.now()}-${Math.random().toString(36).slice(2)}.json`);
55395
55405
  for (let i = 0; i < files.length; i += CHUNK) {
55396
55406
  const chunk = files.slice(i, i + CHUNK);
55397
55407
  try {
55398
55408
  (0, import_node_child_process2.execFileSync)(
55399
55409
  "node",
55400
- [(0, import_node_path47.join)(process.cwd(), "bin", "slopbrick.js"), "scan", ...chunk, "--json", tmpOut, "--no-telemetry", "--quiet"],
55410
+ [(0, import_node_path48.join)(process.cwd(), "bin", "slopbrick.js"), "scan", ...chunk, "--json", tmpOut, "--no-telemetry", "--quiet"],
55401
55411
  { encoding: "utf8", stdio: ["ignore", "pipe", "pipe"] }
55402
55412
  );
55403
55413
  } catch {
@@ -55437,8 +55447,8 @@ async function calibrate(cwd, options = {}) {
55437
55447
  const negativeFiles = buildFileList(negativeDir, ["tsx", "ts"]);
55438
55448
  const posSample = options.positiveLimit ? positiveFiles.slice(0, options.positiveLimit) : positiveFiles;
55439
55449
  const negSample = options.negativeLimit ? negativeFiles.slice(0, options.negativeLimit) : negativeFiles;
55440
- const posListPath = (0, import_node_path47.join)("/tmp", `cal-pos-${Date.now()}.txt`);
55441
- const negListPath = (0, import_node_path47.join)("/tmp", `cal-neg-${Date.now()}.txt`);
55450
+ const posListPath = (0, import_node_path48.join)("/tmp", `cal-pos-${Date.now()}.txt`);
55451
+ const negListPath = (0, import_node_path48.join)("/tmp", `cal-neg-${Date.now()}.txt`);
55442
55452
  (0, import_node_fs36.writeFileSync)(posListPath, posSample.join("\n"));
55443
55453
  (0, import_node_fs36.writeFileSync)(negListPath, negSample.join("\n"));
55444
55454
  const builtins = await Promise.resolve().then(() => (init_builtins(), builtins_exports));
@@ -55554,8 +55564,8 @@ function registerCalibrate(program) {
55554
55564
  positiveLimit: cmdOptions.positiveLimit,
55555
55565
  negativeLimit: cmdOptions.negativeLimit
55556
55566
  });
55557
- const outputPath = cmdOptions.output ? (0, import_node_path48.resolve)(cwd, cmdOptions.output) : (0, import_node_path48.resolve)(cwd, "corpus", "calibration-empirical.md");
55558
- (0, import_node_fs37.mkdirSync)((0, import_node_path48.dirname)(outputPath), { recursive: true });
55567
+ const outputPath = cmdOptions.output ? (0, import_node_path49.resolve)(cwd, cmdOptions.output) : (0, import_node_path49.resolve)(cwd, "corpus", "calibration-empirical.md");
55568
+ (0, import_node_fs37.mkdirSync)((0, import_node_path49.dirname)(outputPath), { recursive: true });
55559
55569
  (0, import_node_fs37.writeFileSync)(outputPath, reportToMarkdown(report), "utf8");
55560
55570
  logger.info(
55561
55571
  "Calibrated " + report.rules.length + " rules across " + report.positiveFileCount + " positive + " + report.negativeFileCount + " negative files."
@@ -55693,13 +55703,13 @@ function registerTrend(program) {
55693
55703
  }
55694
55704
 
55695
55705
  // src/cli/commands/drift.ts
55696
- var import_node_path50 = require("path");
55706
+ var import_node_path51 = require("path");
55697
55707
  init_logger();
55698
55708
  init_scan();
55699
55709
 
55700
55710
  // src/cli/drift.ts
55701
55711
  var import_node_fs38 = require("fs");
55702
- var import_node_path49 = require("path");
55712
+ var import_node_path50 = require("path");
55703
55713
  init_discover();
55704
55714
  init_patterns();
55705
55715
  async function runDrift(cwd, config, options = {}) {
@@ -55723,7 +55733,7 @@ async function runDrift(cwd, config, options = {}) {
55723
55733
  byCategory[v.category] = (byCategory[v.category] ?? 0) + 1;
55724
55734
  byFile.push({
55725
55735
  file: absPath,
55726
- relPath: (0, import_node_path49.relative)(cwd, absPath),
55736
+ relPath: (0, import_node_path50.relative)(cwd, absPath),
55727
55737
  category: v.category,
55728
55738
  import: v.import,
55729
55739
  declared: v.declared,
@@ -55820,7 +55830,7 @@ function registerDrift(program) {
55820
55830
  const options = command.optsWithGlobals();
55821
55831
  const rawFormat = options.format ?? cmdOptions.format ?? "pretty";
55822
55832
  const format = rawFormat === "json" || rawFormat === "pretty" ? rawFormat : "pretty";
55823
- const cwd = (0, import_node_path50.resolve)(options.workspace ?? process.cwd());
55833
+ const cwd = (0, import_node_path51.resolve)(options.workspace ?? process.cwd());
55824
55834
  const { config } = await runScan({ ...options, workspace: cwd });
55825
55835
  const result = await runDrift(cwd, config, { maxFiles: cmdOptions.maxFiles });
55826
55836
  logger.info(formatDrift(result, { json: format === "json" }));
@@ -55834,13 +55844,13 @@ function registerDrift(program) {
55834
55844
  }
55835
55845
 
55836
55846
  // src/cli/commands/pr.ts
55837
- var import_node_path52 = require("path");
55847
+ var import_node_path53 = require("path");
55838
55848
  init_logger();
55839
55849
  init_scan();
55840
55850
 
55841
55851
  // src/cli/pr.ts
55842
55852
  var import_node_fs39 = require("fs");
55843
- var import_node_path51 = require("path");
55853
+ var import_node_path52 = require("path");
55844
55854
  var import_node_child_process3 = require("child_process");
55845
55855
  var import_node_util2 = require("util");
55846
55856
  var import_minimatch2 = require("minimatch");
@@ -55886,10 +55896,10 @@ async function discoverPrFiles(cwd, config, base, head, maxFiles) {
55886
55896
  if (gitFiles.length === 0) return [];
55887
55897
  const sourceFiles = [];
55888
55898
  for (const relOrAbs of gitFiles) {
55889
- const abs = (0, import_node_path51.resolve)(cwd, relOrAbs);
55890
- const ext = (0, import_node_path51.extname)(abs).toLowerCase();
55899
+ const abs = (0, import_node_path52.resolve)(cwd, relOrAbs);
55900
+ const ext = (0, import_node_path52.extname)(abs).toLowerCase();
55891
55901
  if (!PR_EXTENSIONS.has(ext)) continue;
55892
- const rel = (0, import_node_path51.relative)(cwd, abs).split("\\").join("/");
55902
+ const rel = (0, import_node_path52.relative)(cwd, abs).split("\\").join("/");
55893
55903
  if (config.include.length > 0 && !config.include.some((pattern) => (0, import_minimatch2.minimatch)(rel, pattern))) {
55894
55904
  continue;
55895
55905
  }
@@ -55960,7 +55970,7 @@ async function runPrScan(cwd, config, options = {}) {
55960
55970
  totalScore += fileScore;
55961
55971
  files.push({
55962
55972
  file: absPath,
55963
- relPath: (0, import_node_path51.relative)(cwd, absPath).split("\\").join("/"),
55973
+ relPath: (0, import_node_path52.relative)(cwd, absPath).split("\\").join("/"),
55964
55974
  score: fileScore,
55965
55975
  issueCount: issues.length,
55966
55976
  constitutionViolationCount: constitutionViolations.length,
@@ -56101,7 +56111,7 @@ function registerPr(program) {
56101
56111
  async (cmdOptions, command) => {
56102
56112
  try {
56103
56113
  const options = command.optsWithGlobals();
56104
- const cwd = (0, import_node_path52.resolve)(options.workspace ?? process.cwd());
56114
+ const cwd = (0, import_node_path53.resolve)(options.workspace ?? process.cwd());
56105
56115
  const rawFormat = options.format ?? cmdOptions.format ?? "text";
56106
56116
  const format = rawFormat === "json" || rawFormat === "markdown" || rawFormat === "text" ? rawFormat : "text";
56107
56117
  const { config } = await runScan({ ...options, workspace: cwd });
@@ -56123,7 +56133,7 @@ function registerPr(program) {
56123
56133
  }
56124
56134
 
56125
56135
  // src/cli/commands/security.ts
56126
- var import_node_path53 = require("path");
56136
+ var import_node_path54 = require("path");
56127
56137
  init_logger();
56128
56138
  init_scan();
56129
56139
  init_ai_security_risk();
@@ -56136,7 +56146,7 @@ function registerSecurity(program) {
56136
56146
  const options = command.optsWithGlobals();
56137
56147
  const rawFormat = options.format ?? cmdOptions.format ?? "pretty";
56138
56148
  const format = rawFormat === "json" || rawFormat === "pretty" ? rawFormat : "pretty";
56139
- const cwd = (0, import_node_path53.resolve)(options.workspace ?? process.cwd());
56149
+ const cwd = (0, import_node_path54.resolve)(options.workspace ?? process.cwd());
56140
56150
  const { report } = await runScan({ ...options, workspace: cwd });
56141
56151
  const securityIssues = report.issues.filter((i) => i.category === "security");
56142
56152
  const { risk, findings } = computeAiSecurityRisk(securityIssues);
@@ -56182,12 +56192,12 @@ function registerSecurity(program) {
56182
56192
  }
56183
56193
 
56184
56194
  // src/cli/commands/test.ts
56185
- var import_node_path55 = require("path");
56195
+ var import_node_path56 = require("path");
56186
56196
  init_logger();
56187
56197
  init_scan();
56188
56198
 
56189
56199
  // src/cli/test.ts
56190
- var import_node_path54 = require("path");
56200
+ var import_node_path55 = require("path");
56191
56201
  init_scan();
56192
56202
  init_test_quality();
56193
56203
  init_logger();
@@ -56258,7 +56268,7 @@ function formatTestReport(result, opts = {}) {
56258
56268
  const sortedFiles = [...byFile.keys()].sort();
56259
56269
  for (const file of sortedFiles) {
56260
56270
  const issues = byFile.get(file) ?? [];
56261
- const rel = file.startsWith((0, import_node_path54.resolve)(process.cwd())) ? file : file;
56271
+ const rel = file.startsWith((0, import_node_path55.resolve)(process.cwd())) ? file : file;
56262
56272
  lines.push("");
56263
56273
  lines.push(` ${rel}`);
56264
56274
  for (const issue of issues.slice(0, 20)) {
@@ -56287,7 +56297,7 @@ function registerTest(program) {
56287
56297
  const options = command.optsWithGlobals();
56288
56298
  const rawFormat = options.format ?? cmdOptions.format ?? "pretty";
56289
56299
  const format = rawFormat === "json" || rawFormat === "pretty" ? rawFormat : "pretty";
56290
- const cwd = (0, import_node_path55.resolve)(options.workspace ?? process.cwd());
56300
+ const cwd = (0, import_node_path56.resolve)(options.workspace ?? process.cwd());
56291
56301
  const { config } = await runScan({ ...options, workspace: cwd });
56292
56302
  const { result } = await runTestScan(cwd, config, { strict: options.strict });
56293
56303
  logger.info(formatTestReport(result, { json: format === "json" }));
@@ -56301,7 +56311,7 @@ function registerTest(program) {
56301
56311
  }
56302
56312
 
56303
56313
  // src/cli/commands/architecture.ts
56304
- var import_node_path56 = require("path");
56314
+ var import_node_path57 = require("path");
56305
56315
  init_logger();
56306
56316
  init_scan();
56307
56317
  init_architecture_score();
@@ -56314,7 +56324,7 @@ function registerArchitecture(program) {
56314
56324
  const options = command.optsWithGlobals();
56315
56325
  const rawFormat = options.format ?? cmdOptions.format ?? "pretty";
56316
56326
  const format = rawFormat === "json" || rawFormat === "pretty" ? rawFormat : "pretty";
56317
- const cwd = (0, import_node_path56.resolve)(options.workspace ?? process.cwd());
56327
+ const cwd = (0, import_node_path57.resolve)(options.workspace ?? process.cwd());
56318
56328
  const { config } = await runScan({ ...options, workspace: cwd });
56319
56329
  const score = await buildArchitectureScore(cwd, config, cmdOptions.maxFiles);
56320
56330
  const out = format === "json" ? JSON.stringify(score, null, 2) : formatArchitectureScore(score);
@@ -56329,13 +56339,13 @@ function registerArchitecture(program) {
56329
56339
  }
56330
56340
 
56331
56341
  // src/cli/commands/business-logic.ts
56332
- var import_node_path58 = require("path");
56342
+ var import_node_path59 = require("path");
56333
56343
  init_logger();
56334
56344
  init_scan();
56335
56345
 
56336
56346
  // src/cli/business-logic.ts
56337
56347
  var import_node_fs40 = require("fs");
56338
- var import_node_path57 = require("path");
56348
+ var import_node_path58 = require("path");
56339
56349
  init_discover();
56340
56350
  init_business_logic();
56341
56351
  async function runBusinessLogicScan(cwd, config, options = {}) {
@@ -56356,7 +56366,7 @@ async function runBusinessLogicScan(cwd, config, options = {}) {
56356
56366
  for (const issue of fileIssues) {
56357
56367
  issues.push({
56358
56368
  ...issue,
56359
- filePath: (0, import_node_path57.relative)(cwd, absPath) || absPath
56369
+ filePath: (0, import_node_path58.relative)(cwd, absPath) || absPath
56360
56370
  });
56361
56371
  }
56362
56372
  }
@@ -56459,7 +56469,7 @@ function registerBusinessLogic(program) {
56459
56469
  const options = command.optsWithGlobals();
56460
56470
  const rawFormat = options.format ?? cmdOptions.format ?? "text";
56461
56471
  const format = rawFormat === "json" || rawFormat === "markdown" || rawFormat === "text" ? rawFormat : "text";
56462
- const cwd = (0, import_node_path58.resolve)(options.workspace ?? process.cwd());
56472
+ const cwd = (0, import_node_path59.resolve)(options.workspace ?? process.cwd());
56463
56473
  const { config } = await runScan({ ...options, workspace: cwd });
56464
56474
  const result = await runBusinessLogicScan(cwd, config, {
56465
56475
  maxFiles: cmdOptions.maxFiles
@@ -56475,7 +56485,7 @@ function registerBusinessLogic(program) {
56475
56485
  }
56476
56486
 
56477
56487
  // src/cli/commands/maintenance-cost.ts
56478
- var import_node_path59 = require("path");
56488
+ var import_node_path60 = require("path");
56479
56489
  init_logger();
56480
56490
  init_scan();
56481
56491
 
@@ -56601,7 +56611,7 @@ function registerMaintenanceCost(program) {
56601
56611
  const rawFormat = options.format ?? cmdOptions.format ?? "text";
56602
56612
  const format = rawFormat === "json" || rawFormat === "text" ? rawFormat : "text";
56603
56613
  const strict = options.strict ?? cmdOptions.strict ?? false;
56604
- const cwd = (0, import_node_path59.resolve)(options.workspace ?? process.cwd());
56614
+ const cwd = (0, import_node_path60.resolve)(options.workspace ?? process.cwd());
56605
56615
  const { config } = await runScan({ ...options, workspace: cwd });
56606
56616
  const result = await runMaintenanceCostScan(cwd, config, {
56607
56617
  maxFiles: cmdOptions.maxFiles,
@@ -56618,7 +56628,7 @@ function registerMaintenanceCost(program) {
56618
56628
  }
56619
56629
 
56620
56630
  // src/cli/commands/docs.ts
56621
- var import_node_path60 = require("path");
56631
+ var import_node_path61 = require("path");
56622
56632
  init_logger();
56623
56633
  init_scan();
56624
56634
 
@@ -56745,7 +56755,7 @@ function registerDocs(program) {
56745
56755
  const rawFormat = options.format ?? cmdOptions.format ?? "text";
56746
56756
  const format = rawFormat === "json" || rawFormat === "markdown" || rawFormat === "text" ? rawFormat : "text";
56747
56757
  const strict = options.strict ?? cmdOptions.strict ?? false;
56748
- const cwd = (0, import_node_path60.resolve)(options.workspace ?? process.cwd());
56758
+ const cwd = (0, import_node_path61.resolve)(options.workspace ?? process.cwd());
56749
56759
  const { config } = await runScan({ ...options, workspace: cwd });
56750
56760
  const result = await runDocsScan(cwd, config, {
56751
56761
  maxDocFiles: cmdOptions.maxFiles,
@@ -56767,7 +56777,7 @@ function registerDocs(program) {
56767
56777
  }
56768
56778
 
56769
56779
  // src/cli/commands/db.ts
56770
- var import_node_path61 = require("path");
56780
+ var import_node_path62 = require("path");
56771
56781
  init_logger();
56772
56782
  init_scan();
56773
56783
 
@@ -56888,7 +56898,7 @@ function registerDb(program) {
56888
56898
  const rawFormat = options.format ?? cmdOptions.format ?? "text";
56889
56899
  const format = rawFormat === "json" || rawFormat === "markdown" || rawFormat === "text" ? rawFormat : "text";
56890
56900
  const strict = options.strict ?? cmdOptions.strict ?? false;
56891
- const cwd = (0, import_node_path61.resolve)(options.workspace ?? process.cwd());
56901
+ const cwd = (0, import_node_path62.resolve)(options.workspace ?? process.cwd());
56892
56902
  const { config } = await runScan({ ...options, workspace: cwd });
56893
56903
  const result = await runDbScan(cwd, config, {
56894
56904
  maxFiles: cmdOptions.maxFiles,
@@ -56910,13 +56920,13 @@ function registerDb(program) {
56910
56920
  }
56911
56921
 
56912
56922
  // src/cli/commands/patterns.ts
56913
- var import_node_path63 = require("path");
56923
+ var import_node_path64 = require("path");
56914
56924
  init_logger();
56915
56925
  init_scan();
56916
56926
 
56917
56927
  // src/engine/patterns.ts
56918
56928
  var import_node_fs41 = require("fs");
56919
- var import_node_path62 = require("path");
56929
+ var import_node_path63 = require("path");
56920
56930
  init_patterns();
56921
56931
  init_discover();
56922
56932
  var PATTERN_CATEGORIES = [
@@ -56951,7 +56961,7 @@ var TOAST_NAME_RE = /^(?:[A-Z][a-zA-Z0-9]+)?(Toast|Notification|Snackbar|Alert|B
56951
56961
  var CARD_NAME_RE = /^(?:[A-Z][a-zA-Z0-9]+)?(Card|Tile|Chip|Badge)$/;
56952
56962
  var API_PATH_RE2 = /(?:^|\/)(?:lib\/api|services|api-client|clients)\//;
56953
56963
  function baseName(filePath) {
56954
- return (0, import_node_path62.basename)(filePath).replace(/\.(tsx|ts|jsx|js|vue|svelte|astro)$/i, "");
56964
+ return (0, import_node_path63.basename)(filePath).replace(/\.(tsx|ts|jsx|js|vue|svelte|astro)$/i, "");
56955
56965
  }
56956
56966
  function makeStats(patterns) {
56957
56967
  const seen = /* @__PURE__ */ new Set();
@@ -57010,7 +57020,7 @@ function detectApiFromFiles(files, cwd) {
57010
57020
  const out = [];
57011
57021
  for (const f of files) {
57012
57022
  if (API_PATH_RE2.test(f)) {
57013
- out.push((0, import_node_path62.relative)(cwd, f).split("\\").join("/"));
57023
+ out.push((0, import_node_path63.relative)(cwd, f).split("\\").join("/"));
57014
57024
  }
57015
57025
  }
57016
57026
  return out;
@@ -57241,7 +57251,7 @@ function registerPatterns(program) {
57241
57251
  const options = command.optsWithGlobals();
57242
57252
  const rawFormat = options.format ?? cmdOptions.format ?? "text";
57243
57253
  const format = rawFormat === "json" || rawFormat === "markdown" || rawFormat === "text" ? rawFormat : "text";
57244
- const cwd = (0, import_node_path63.resolve)(options.workspace ?? process.cwd());
57254
+ const cwd = (0, import_node_path64.resolve)(options.workspace ?? process.cwd());
57245
57255
  const { config } = await runScan({ ...options, workspace: cwd });
57246
57256
  const result = await runPatternsScan(cwd, config, {
57247
57257
  maxFiles: cmdOptions.maxFiles,
@@ -57259,7 +57269,7 @@ function registerPatterns(program) {
57259
57269
 
57260
57270
  // src/cli/commands/research.ts
57261
57271
  var import_node_fs42 = require("fs");
57262
- var import_node_path64 = require("path");
57272
+ var import_node_path65 = require("path");
57263
57273
  init_logger();
57264
57274
  init_config();
57265
57275
  function registerResearch(program) {
@@ -57276,14 +57286,14 @@ function registerResearch(program) {
57276
57286
  framework: cmdOptions.framework,
57277
57287
  componentType: cmdOptions.componentType,
57278
57288
  provider,
57279
- outputDir: (0, import_node_path64.resolve)(cmdOptions.outputDir),
57289
+ outputDir: (0, import_node_path65.resolve)(cmdOptions.outputDir),
57280
57290
  temperature: cmdOptions.temperature
57281
57291
  });
57282
57292
  logger.info(`Generated ${samples.length} samples in ${cmdOptions.outputDir}`);
57283
57293
  });
57284
57294
  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) => {
57285
57295
  try {
57286
- const metadataPath = (0, import_node_path64.resolve)(cmdOptions.inputDir, "metadata.json");
57296
+ const metadataPath = (0, import_node_path65.resolve)(cmdOptions.inputDir, "metadata.json");
57287
57297
  if (!(0, import_node_fs42.existsSync)(metadataPath)) {
57288
57298
  logger.error(`No metadata.json found in ${cmdOptions.inputDir}`);
57289
57299
  process.exit(2);
@@ -57291,8 +57301,8 @@ function registerResearch(program) {
57291
57301
  const samples = JSON.parse((0, import_node_fs42.readFileSync)(metadataPath, "utf8"));
57292
57302
  const config = cmdOptions.config ? await loadConfig(cmdOptions.config) : { ...DEFAULT_CONFIG, framework: cmdOptions.framework };
57293
57303
  const analysis = await analyzeSamples(samples, config);
57294
- const outputPath = (0, import_node_path64.resolve)(cmdOptions.output);
57295
- (0, import_node_fs42.mkdirSync)((0, import_node_path64.dirname)(outputPath), { recursive: true });
57304
+ const outputPath = (0, import_node_path65.resolve)(cmdOptions.output);
57305
+ (0, import_node_fs42.mkdirSync)((0, import_node_path65.dirname)(outputPath), { recursive: true });
57296
57306
  (0, import_node_fs42.writeFileSync)(outputPath, JSON.stringify(analysis, null, 2), "utf8");
57297
57307
  logger.info(`Analyzed ${analysis.summary.total} samples; coverage: ${analysis.summary.coverage}%`);
57298
57308
  logger.info(`Wrote analysis to ${outputPath}`);
@@ -57303,7 +57313,7 @@ function registerResearch(program) {
57303
57313
  });
57304
57314
  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) => {
57305
57315
  try {
57306
- const metadataPath = (0, import_node_path64.resolve)(cmdOptions.inputDir, "metadata.json");
57316
+ const metadataPath = (0, import_node_path65.resolve)(cmdOptions.inputDir, "metadata.json");
57307
57317
  if (!(0, import_node_fs42.existsSync)(metadataPath)) {
57308
57318
  logger.error(`No metadata.json found in ${cmdOptions.inputDir}`);
57309
57319
  process.exit(2);
@@ -57318,8 +57328,8 @@ function registerResearch(program) {
57318
57328
  const candidates = clustersToCandidates(extraction.clusters, {
57319
57329
  minFrequency: cmdOptions.minFrequency
57320
57330
  });
57321
- const outputPath = (0, import_node_path64.resolve)(cmdOptions.output);
57322
- (0, import_node_fs42.mkdirSync)((0, import_node_path64.dirname)(outputPath), { recursive: true });
57331
+ const outputPath = (0, import_node_path65.resolve)(cmdOptions.output);
57332
+ (0, import_node_fs42.mkdirSync)((0, import_node_path65.dirname)(outputPath), { recursive: true });
57323
57333
  const payload = {
57324
57334
  generatedAt: (/* @__PURE__ */ new Date()).toISOString(),
57325
57335
  sampleCount: analysis.summary.total,
@@ -57339,7 +57349,7 @@ function registerResearch(program) {
57339
57349
 
57340
57350
  // src/cli/commands/init.ts
57341
57351
  var import_node_fs43 = require("fs");
57342
- var import_node_path66 = require("path");
57352
+ var import_node_path67 = require("path");
57343
57353
  init_logger();
57344
57354
  init_builtins();
57345
57355
  init_scan();
@@ -57349,7 +57359,7 @@ init_git();
57349
57359
  init_cache();
57350
57360
 
57351
57361
  // src/snippet/targets.ts
57352
- var import_node_path65 = require("path");
57362
+ var import_node_path66 = require("path");
57353
57363
 
57354
57364
  // src/snippet/render.ts
57355
57365
  function aiSpecificRules(rules) {
@@ -57580,7 +57590,7 @@ var SNIPPET_TARGETS = [
57580
57590
  }
57581
57591
  ];
57582
57592
  function resolveTargetPath(target) {
57583
- return target.isFolder ? (0, import_node_path65.join)(target.path, target.filename) : target.path;
57593
+ return target.isFolder ? (0, import_node_path66.join)(target.path, target.filename) : target.path;
57584
57594
  }
57585
57595
  function renderMatrix() {
57586
57596
  const lines = [];
@@ -57602,8 +57612,8 @@ function registerInit(program) {
57602
57612
  logger.info(renderMatrix());
57603
57613
  process.exit(0);
57604
57614
  }
57605
- const cwd = (0, import_node_path66.resolve)(options.workspace ?? process.cwd());
57606
- const configPath = (0, import_node_path66.join)(cwd, "slopbrick.config.mjs");
57615
+ const cwd = (0, import_node_path67.resolve)(options.workspace ?? process.cwd());
57616
+ const configPath = (0, import_node_path67.join)(cwd, "slopbrick.config.mjs");
57607
57617
  const detected = detectStack(cwd);
57608
57618
  const fallbackConfig = { ...DEFAULT_CONFIG, ...detected };
57609
57619
  const proposed = serializeConfig(fallbackConfig);
@@ -57659,8 +57669,8 @@ function registerInit(program) {
57659
57669
  return Boolean(opts[t.flag]);
57660
57670
  });
57661
57671
  for (const target of targetsToWrite) {
57662
- const snippetPath = (0, import_node_path66.join)(cwd, resolveTargetPath(target));
57663
- (0, import_node_fs43.mkdirSync)((0, import_node_path66.dirname)(snippetPath), { recursive: true });
57672
+ const snippetPath = (0, import_node_path67.join)(cwd, resolveTargetPath(target));
57673
+ (0, import_node_fs43.mkdirSync)((0, import_node_path67.dirname)(snippetPath), { recursive: true });
57664
57674
  const generated = target.generator(builtinRules);
57665
57675
  if (!target.isFolder && (0, import_node_fs43.existsSync)(snippetPath)) {
57666
57676
  const existing = (0, import_node_fs43.readFileSync)(snippetPath, "utf8");
@@ -57700,13 +57710,13 @@ function registerInit(program) {
57700
57710
 
57701
57711
  // src/cli/commands/flywheel.ts
57702
57712
  var import_node_fs45 = require("fs");
57703
- var import_node_path68 = require("path");
57713
+ var import_node_path69 = require("path");
57704
57714
  init_logger();
57705
57715
  init_telemetry();
57706
57716
 
57707
57717
  // src/report/flywheel.ts
57708
57718
  var import_node_fs44 = require("fs");
57709
- var import_node_path67 = require("path");
57719
+ var import_node_path68 = require("path");
57710
57720
  function average(values) {
57711
57721
  if (values.length === 0) return 0;
57712
57722
  return values.reduce((a, b) => a + b, 0) / values.length;
@@ -57796,7 +57806,7 @@ function formatFlywheel(summary, options = {}) {
57796
57806
  function registerFlywheel(program) {
57797
57807
  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) => {
57798
57808
  const options = command.optsWithGlobals();
57799
- const cwd = (0, import_node_path68.resolve)(options.workspace ?? process.cwd());
57809
+ const cwd = (0, import_node_path69.resolve)(options.workspace ?? process.cwd());
57800
57810
  const payloads = readTelemetry(cwd);
57801
57811
  if (payloads.length === 0) {
57802
57812
  logger.info("No flywheel telemetry found. Run a scan first.");
@@ -57804,8 +57814,8 @@ function registerFlywheel(program) {
57804
57814
  }
57805
57815
  const summary = summarizeTelemetry(payloads);
57806
57816
  if (cmdOptions.export) {
57807
- const exportPath = (0, import_node_path68.resolve)(cmdOptions.export);
57808
- (0, import_node_fs45.mkdirSync)((0, import_node_path68.dirname)(exportPath), { recursive: true });
57817
+ const exportPath = (0, import_node_path69.resolve)(cmdOptions.export);
57818
+ (0, import_node_fs45.mkdirSync)((0, import_node_path69.dirname)(exportPath), { recursive: true });
57809
57819
  (0, import_node_fs45.writeFileSync)(exportPath, JSON.stringify(summary, null, 2), "utf-8");
57810
57820
  logger.info(`Wrote flywheel summary to ${exportPath}`);
57811
57821
  process.exit(0);
@@ -58288,7 +58298,7 @@ async function runCli({ start }) {
58288
58298
  logger.error("--heatmap and --suggest can't be used together. Pick one: a heatmap of severity, or text advice.");
58289
58299
  process.exit(2);
58290
58300
  }
58291
- const cwd = (0, import_node_path69.resolve)(options.workspace ?? process.cwd());
58301
+ const cwd = (0, import_node_path70.resolve)(options.workspace ?? process.cwd());
58292
58302
  if (options.trend !== void 0) {
58293
58303
  const runs = await readRuns(cwd, fsMemoryIO);
58294
58304
  if (runs.length === 0) {
@@ -58321,7 +58331,7 @@ async function runCli({ start }) {
58321
58331
  const scanElapsed = Math.round(import_node_perf_hooks.performance.now() - scanStart);
58322
58332
  const totalElapsed = Math.round(import_node_perf_hooks.performance.now() - start);
58323
58333
  if (options.baseline) {
58324
- const cwd2 = (0, import_node_path69.resolve)(options.workspace ?? process.cwd());
58334
+ const cwd2 = (0, import_node_path70.resolve)(options.workspace ?? process.cwd());
58325
58335
  const configHash = hashConfig(config);
58326
58336
  const gitHead = await getGitHead(cwd2) ?? "unknown";
58327
58337
  const cache = buildBaselineCache(report, configHash, gitHead, cwd2);