@massu/core 1.5.8 → 1.6.0

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/cli.js CHANGED
@@ -11159,22 +11159,440 @@ var init_python_flask = __esm({
11159
11159
  }
11160
11160
  });
11161
11161
 
11162
- // src/detect/adapters/go-chi.ts
11163
- import { Parser as Parser7 } from "web-tree-sitter";
11162
+ // dist/adapter.js
11163
+ import { Query as Query2 } from "web-tree-sitter";
11164
+ import { createHash as createHash3 } from "crypto";
11165
+ import {
11166
+ mkdirSync as mkdirSync4,
11167
+ readdirSync as readdirSync9,
11168
+ readFileSync as readFileSync9,
11169
+ writeFileSync as writeFileSync2,
11170
+ renameSync as renameSync3,
11171
+ unlinkSync as unlinkSync2,
11172
+ lstatSync as lstatSync4,
11173
+ chmodSync as chmodSync2,
11174
+ utimesSync as utimesSync2
11175
+ } from "fs";
11176
+ import { homedir as homedir3 } from "os";
11177
+ import { dirname as dirname5, join as join9 } from "path";
11178
+ import { Language as Language2, Parser as Parser7 } from "web-tree-sitter";
11179
+ function compileQuery2(language, source, queryName) {
11180
+ let perLang = queryCache2.get(language);
11181
+ if (!perLang) {
11182
+ perLang = /* @__PURE__ */ new Map();
11183
+ queryCache2.set(language, perLang);
11184
+ }
11185
+ const cached = perLang.get(source);
11186
+ if (cached) return cached;
11187
+ let q2;
11188
+ try {
11189
+ q2 = new Query2(language, source);
11190
+ } catch (e2) {
11191
+ throw new InvalidQueryError2(queryName, source, e2);
11192
+ }
11193
+ perLang.set(source, q2);
11194
+ return q2;
11195
+ }
11196
+ function runQuery2(parser, source, queryText, queryName, filePath) {
11197
+ const language = parser.language;
11198
+ if (!language) {
11199
+ throw new InvalidQueryError2(
11200
+ queryName,
11201
+ queryText,
11202
+ new Error("Parser has no language assigned")
11203
+ );
11204
+ }
11205
+ const query = compileQuery2(language, queryText, queryName);
11206
+ const tree = parser.parse(source);
11207
+ if (!tree) return [];
11208
+ let matches;
11209
+ try {
11210
+ matches = query.matches(tree.rootNode);
11211
+ } catch (e2) {
11212
+ throw new InvalidQueryError2(queryName, queryText, e2);
11213
+ }
11214
+ const out = [];
11215
+ for (const match of matches) {
11216
+ if (!match.captures || match.captures.length === 0) continue;
11217
+ const captures = {};
11218
+ let earliestLine = Number.POSITIVE_INFINITY;
11219
+ for (const cap of match.captures) {
11220
+ const node = cap.node;
11221
+ captures[cap.name] = node.text;
11222
+ if (node.startPosition.row + 1 < earliestLine) {
11223
+ earliestLine = node.startPosition.row + 1;
11224
+ }
11225
+ }
11226
+ out.push({
11227
+ captures,
11228
+ file: filePath,
11229
+ line: Number.isFinite(earliestLine) ? earliestLine : 1,
11230
+ queryName
11231
+ });
11232
+ }
11233
+ try {
11234
+ tree.delete();
11235
+ } catch {
11236
+ }
11237
+ return out;
11238
+ }
11239
+ function getCacheDir2() {
11240
+ return process.env.MASSU_WASM_CACHE_DIR ?? join9(homedir3(), ".massu", "wasm-cache");
11241
+ }
11242
+ function getCachedPath2(language, sha) {
11243
+ return join9(getCacheDir2(), `${language}-${sha}.wasm`);
11244
+ }
11245
+ function getCacheRetainCount2() {
11246
+ const env = process.env.MASSU_WASM_CACHE_RETAIN;
11247
+ if (env) {
11248
+ const n = Number(env);
11249
+ if (Number.isFinite(n) && n >= 1 && n <= 1024) return Math.floor(n);
11250
+ }
11251
+ return DEFAULT_CACHE_RETAIN_COUNT2;
11252
+ }
11253
+ function touchCacheFile2(path) {
11254
+ try {
11255
+ const now = /* @__PURE__ */ new Date();
11256
+ utimesSync2(path, now, now);
11257
+ } catch {
11258
+ }
11259
+ }
11260
+ function evictBeyondRetainCount2(retain = getCacheRetainCount2()) {
11261
+ const dir = getCacheDir2();
11262
+ let entries;
11263
+ try {
11264
+ entries = readdirSync9(dir);
11265
+ } catch {
11266
+ return;
11267
+ }
11268
+ const candidates = [];
11269
+ for (const name of entries) {
11270
+ if (!name.endsWith(".wasm")) continue;
11271
+ const path = join9(dir, name);
11272
+ let stat;
11273
+ try {
11274
+ stat = lstatSync4(path);
11275
+ } catch {
11276
+ continue;
11277
+ }
11278
+ if (stat.isSymbolicLink() || !stat.isFile()) {
11279
+ console.error(
11280
+ `[tree-sitter-loader] cache eviction skipped non-regular file: ${path} (possible symlink attack \u2014 see Phase 3.5 finding F-008).`
11281
+ );
11282
+ continue;
11283
+ }
11284
+ candidates.push({ path, mtimeMs: stat.mtimeMs });
11285
+ }
11286
+ if (candidates.length <= retain) return;
11287
+ candidates.sort((a2, b2) => b2.mtimeMs - a2.mtimeMs);
11288
+ for (const victim of candidates.slice(retain)) {
11289
+ try {
11290
+ unlinkSync2(victim.path);
11291
+ } catch {
11292
+ }
11293
+ }
11294
+ }
11295
+ function sha2562(bytes) {
11296
+ return createHash3("sha256").update(bytes).digest("hex");
11297
+ }
11298
+ async function ensureParserInitialized2() {
11299
+ if (parserInitPromise2) return parserInitPromise2;
11300
+ parserInitPromise2 = Parser7.init();
11301
+ return parserInitPromise2;
11302
+ }
11303
+ async function loadGrammar2(language, options = {}) {
11304
+ await ensureParserInitialized2();
11305
+ const cached = loadedGrammars2.get(language);
11306
+ if (cached) return cached;
11307
+ const manifest = options.manifestOverride?.[language] ?? GRAMMAR_MANIFEST2[language];
11308
+ if (!manifest) {
11309
+ throw new GrammarUnavailableError2(
11310
+ language,
11311
+ new Error(`No manifest entry for language "${language}". v1 supports: ${Object.keys(GRAMMAR_MANIFEST2).join(", ")}.`)
11312
+ );
11313
+ }
11314
+ const cachePath = getCachedPath2(language, manifest.sha256);
11315
+ let cacheLstat;
11316
+ try {
11317
+ cacheLstat = lstatSync4(cachePath);
11318
+ } catch {
11319
+ cacheLstat = null;
11320
+ }
11321
+ if (cacheLstat) {
11322
+ if (cacheLstat.isSymbolicLink() || !cacheLstat.isFile()) {
11323
+ throw new GrammarCacheSymlinkError2(cachePath);
11324
+ }
11325
+ let bytes;
11326
+ try {
11327
+ bytes = readFileSync9(cachePath);
11328
+ } catch (e2) {
11329
+ bytes = new Uint8Array(0);
11330
+ }
11331
+ if (bytes.byteLength > 0) {
11332
+ const actualSha = sha2562(bytes);
11333
+ if (actualSha !== manifest.sha256) {
11334
+ throw new GrammarSHAMismatchError2(language, manifest.sha256, actualSha);
11335
+ }
11336
+ const lang2 = await Language2.load(bytes);
11337
+ loadedGrammars2.set(language, lang2);
11338
+ touchCacheFile2(cachePath);
11339
+ return lang2;
11340
+ }
11341
+ }
11342
+ if (!/^https:\/\//i.test(manifest.url)) {
11343
+ throw new GrammarUrlNotHttpsError2(manifest.url);
11344
+ }
11345
+ const fetchImpl = options.fetchImpl ?? globalThis.fetch;
11346
+ if (!fetchImpl) {
11347
+ throw new GrammarUnavailableError2(
11348
+ language,
11349
+ new Error("No fetch implementation available (Node < 18?)")
11350
+ );
11351
+ }
11352
+ let body;
11353
+ try {
11354
+ const res = await fetchImpl(manifest.url);
11355
+ if (!res.ok) {
11356
+ throw new Error(`HTTP ${res.status ?? "unknown"} from ${manifest.url}`);
11357
+ }
11358
+ body = new Uint8Array(await res.arrayBuffer());
11359
+ } catch (e2) {
11360
+ throw new GrammarUnavailableError2(language, e2);
11361
+ }
11362
+ const downloadedSha = sha2562(body);
11363
+ if (downloadedSha !== manifest.sha256) {
11364
+ throw new GrammarSHAMismatchError2(language, manifest.sha256, downloadedSha);
11365
+ }
11366
+ try {
11367
+ mkdirSync4(dirname5(cachePath), { recursive: true, mode: 448 });
11368
+ try {
11369
+ chmodSync2(dirname5(cachePath), 448);
11370
+ } catch {
11371
+ }
11372
+ const tmpPath = `${cachePath}.tmp.${process.pid}`;
11373
+ writeFileSync2(tmpPath, body, { mode: 384 });
11374
+ try {
11375
+ chmodSync2(tmpPath, 384);
11376
+ } catch {
11377
+ }
11378
+ try {
11379
+ renameSync3(tmpPath, cachePath);
11380
+ try {
11381
+ chmodSync2(cachePath, 384);
11382
+ } catch {
11383
+ }
11384
+ } catch (e2) {
11385
+ try {
11386
+ unlinkSync2(tmpPath);
11387
+ } catch {
11388
+ }
11389
+ throw e2;
11390
+ }
11391
+ evictBeyondRetainCount2();
11392
+ } catch (e2) {
11393
+ console.error(
11394
+ `[tree-sitter-loader] cache write failed for ${language}: ${e2 instanceof Error ? e2.message : String(e2)} \u2014 loading directly from memory.`
11395
+ );
11396
+ }
11397
+ const lang = await Language2.load(body);
11398
+ loadedGrammars2.set(language, lang);
11399
+ return lang;
11400
+ }
11401
+ function isParsableSource2(source, sizeBytes) {
11402
+ const bytes = sizeBytes ?? Buffer.byteLength(source, "utf-8");
11403
+ if (bytes > MAX_AST_FILE_BYTES2) {
11404
+ return {
11405
+ reason: "size-cap",
11406
+ detail: `${bytes} bytes > ${MAX_AST_FILE_BYTES2} cap`
11407
+ };
11408
+ }
11409
+ let depth = 0;
11410
+ let maxDepth = 0;
11411
+ for (let i = 0; i < source.length; i++) {
11412
+ const c2 = source.charCodeAt(i);
11413
+ if (c2 === 0) {
11414
+ return { reason: "control-bytes", detail: "NUL byte at offset " + i };
11415
+ }
11416
+ if (c2 === 40 || c2 === 91 || c2 === 123) {
11417
+ depth++;
11418
+ if (depth > maxDepth) maxDepth = depth;
11419
+ if (depth > MAX_AST_PARSE_DEPTH2) {
11420
+ return {
11421
+ reason: "depth-cap",
11422
+ detail: `nesting depth exceeded ${MAX_AST_PARSE_DEPTH2}`
11423
+ };
11424
+ }
11425
+ } else if (c2 === 41 || c2 === 93 || c2 === 125) {
11426
+ depth = depth > 0 ? depth - 1 : 0;
11427
+ }
11428
+ }
11429
+ return null;
11430
+ }
11431
+ var InvalidQueryError2, queryCache2, GrammarSHAMismatchError2, GrammarUnavailableError2, GrammarCacheSymlinkError2, GrammarUrlNotHttpsError2, GRAMMAR_MANIFEST2, DEFAULT_CACHE_RETAIN_COUNT2, parserInitPromise2, loadedGrammars2, MAX_AST_FILE_BYTES2, MAX_AST_PARSE_DEPTH2;
11432
+ var init_adapter = __esm({
11433
+ "dist/adapter.js"() {
11434
+ "use strict";
11435
+ InvalidQueryError2 = class extends Error {
11436
+ queryName;
11437
+ querySource;
11438
+ cause;
11439
+ constructor(queryName, querySource, cause) {
11440
+ const causeMsg = cause instanceof Error ? cause.message : String(cause);
11441
+ super(
11442
+ `[query-helpers] Invalid Tree-sitter query "${queryName}": ${causeMsg}
11443
+ Query source:
11444
+ ${querySource}`
11445
+ );
11446
+ this.name = "InvalidQueryError";
11447
+ this.queryName = queryName;
11448
+ this.querySource = querySource;
11449
+ this.cause = cause;
11450
+ }
11451
+ };
11452
+ queryCache2 = /* @__PURE__ */ new WeakMap();
11453
+ GrammarSHAMismatchError2 = class extends Error {
11454
+ language;
11455
+ expected;
11456
+ actual;
11457
+ constructor(language, expected, actual) {
11458
+ super(
11459
+ `[tree-sitter-loader] SHA-256 mismatch for grammar "${language}". Expected ${expected}, got ${actual}. REFUSING to load \u2014 see Phase 3.5 audit attack vector #3.`
11460
+ );
11461
+ this.name = "GrammarSHAMismatchError";
11462
+ this.language = language;
11463
+ this.expected = expected;
11464
+ this.actual = actual;
11465
+ }
11466
+ };
11467
+ GrammarUnavailableError2 = class extends Error {
11468
+ language;
11469
+ cause;
11470
+ constructor(language, cause) {
11471
+ const causeMsg = cause instanceof Error ? cause.message : cause ? String(cause) : "no cached grammar and download failed";
11472
+ super(
11473
+ `[tree-sitter-loader] Grammar for "${language}" is unavailable: ${causeMsg}. Falling back to regex introspection for files in ${language}.`
11474
+ );
11475
+ this.name = "GrammarUnavailableError";
11476
+ this.language = language;
11477
+ this.cause = cause;
11478
+ }
11479
+ };
11480
+ GrammarCacheSymlinkError2 = class extends Error {
11481
+ cachePath;
11482
+ constructor(cachePath) {
11483
+ super(
11484
+ `[tree-sitter-loader] Refusing to load grammar \u2014 cache path "${cachePath}" is a symlink or non-regular file. (Phase 3.5 finding #3 \u2014 symlink attack vector.)`
11485
+ );
11486
+ this.name = "GrammarCacheSymlinkError";
11487
+ this.cachePath = cachePath;
11488
+ }
11489
+ };
11490
+ GrammarUrlNotHttpsError2 = class extends Error {
11491
+ url;
11492
+ constructor(url) {
11493
+ super(
11494
+ `[tree-sitter-loader] Refusing to download grammar from non-HTTPS URL: ${url}. Only https:// URLs are accepted. (Phase 3.5 finding #3.)`
11495
+ );
11496
+ this.name = "GrammarUrlNotHttpsError";
11497
+ this.url = url;
11498
+ }
11499
+ };
11500
+ GRAMMAR_MANIFEST2 = {
11501
+ python: {
11502
+ url: "https://unpkg.com/tree-sitter-wasms@0.1.13/out/tree-sitter-python.wasm",
11503
+ sha256: "9056d0fb0c337810d019fae350e8167786119da98f0f282aceae7ab89ee8253b",
11504
+ version: "0.1.13"
11505
+ },
11506
+ typescript: {
11507
+ url: "https://unpkg.com/tree-sitter-wasms@0.1.13/out/tree-sitter-typescript.wasm",
11508
+ sha256: "8515404dceed38e1ed86aa34b09fcf3379fff1b4ff9dd3967bcd6d1eb5ac3d8f",
11509
+ version: "0.1.13"
11510
+ },
11511
+ javascript: {
11512
+ url: "https://unpkg.com/tree-sitter-wasms@0.1.13/out/tree-sitter-javascript.wasm",
11513
+ sha256: "63812b9e275d26851264734868d27a1656bd44a2ef6eb3e85e6b03728c595ab5",
11514
+ version: "0.1.13"
11515
+ },
11516
+ swift: {
11517
+ url: "https://unpkg.com/tree-sitter-wasms@0.1.13/out/tree-sitter-swift.wasm",
11518
+ sha256: "41c4fdb2249a3aa6d87eed0d383081ff09725c2248b4977043a43825980ffcc7",
11519
+ version: "0.1.13"
11520
+ },
11521
+ // ----------------------------------------------------------------
11522
+ // Plan 3c Phase 7 expansion (2026-05-07):
11523
+ //
11524
+ // Six additional grammars to support the registry-verified framework
11525
+ // adapters (go-chi, rails, aspnet, spring, ktor, phoenix) plus the
11526
+ // bundled adapters in the same language families (gin/echo/fiber,
11527
+ // sinatra, etc.). All entries use the SAME pinned tree-sitter-wasms
11528
+ // version (0.1.13) as the v1 four to keep the dependency surface
11529
+ // single-source.
11530
+ //
11531
+ // SHA-256s computed 2026-05-07 via:
11532
+ // curl -fsSL <url> | shasum -a 256
11533
+ //
11534
+ // The unpkg filename for C# uses an underscore (`c_sharp`) while the
11535
+ // TreeSitterLanguage identifier uses no separator (`csharp`); the map
11536
+ // key is the type identifier, the URL is the storage path — they do
11537
+ // NOT need to match, the same as how `python` maps to `tree-sitter-
11538
+ // python.wasm`. This is intentional and validated by the manifest
11539
+ // shape test in tree-sitter-loader-manifest.test.ts.
11540
+ // ----------------------------------------------------------------
11541
+ go: {
11542
+ url: "https://unpkg.com/tree-sitter-wasms@0.1.13/out/tree-sitter-go.wasm",
11543
+ sha256: "9963ca89b616eaf04b08a43bc1fb0f07b85395bec313330851f1f1ead2f755b6",
11544
+ version: "0.1.13"
11545
+ },
11546
+ ruby: {
11547
+ url: "https://unpkg.com/tree-sitter-wasms@0.1.13/out/tree-sitter-ruby.wasm",
11548
+ sha256: "93a5022855314cdb45458c7bb026a24a0ebc3a5ff6439e542e881f14dfa13a39",
11549
+ version: "0.1.13"
11550
+ },
11551
+ csharp: {
11552
+ url: "https://unpkg.com/tree-sitter-wasms@0.1.13/out/tree-sitter-c_sharp.wasm",
11553
+ sha256: "6266a7e32d68a3459104d994dc848df15d5672b0ea8e86d327274b694f8e6991",
11554
+ version: "0.1.13"
11555
+ },
11556
+ java: {
11557
+ url: "https://unpkg.com/tree-sitter-wasms@0.1.13/out/tree-sitter-java.wasm",
11558
+ sha256: "637aac4415fb39a211a4f4292d63c66b5ce9c32fa2cd35464af4f681d91b9a1f",
11559
+ version: "0.1.13"
11560
+ },
11561
+ kotlin: {
11562
+ url: "https://unpkg.com/tree-sitter-wasms@0.1.13/out/tree-sitter-kotlin.wasm",
11563
+ sha256: "b5cb00c8d06ed0f10f1dbe497205b437809d7e87db1f638721a8cfb30e044449",
11564
+ version: "0.1.13"
11565
+ },
11566
+ elixir: {
11567
+ url: "https://unpkg.com/tree-sitter-wasms@0.1.13/out/tree-sitter-elixir.wasm",
11568
+ sha256: "82e91b9759ddca30d8978ebbfa8e347b4451b64c931f9ae62112e6db9b8fac20",
11569
+ version: "0.1.13"
11570
+ }
11571
+ };
11572
+ DEFAULT_CACHE_RETAIN_COUNT2 = 16;
11573
+ parserInitPromise2 = null;
11574
+ loadedGrammars2 = /* @__PURE__ */ new Map();
11575
+ MAX_AST_FILE_BYTES2 = 1 * 1024 * 1024;
11576
+ MAX_AST_PARSE_DEPTH2 = 5e3;
11577
+ }
11578
+ });
11579
+
11580
+ // ../adapter-go-chi/dist/index.js
11581
+ import { Parser as Parser8 } from "web-tree-sitter";
11164
11582
  function extractPrefixBase4(prefix3) {
11165
- if (!prefix3.startsWith("/")) return null;
11583
+ if (!prefix3.startsWith("/"))
11584
+ return null;
11166
11585
  const stripped = prefix3.replace(/^\/+/, "");
11167
11586
  const firstSeg = stripped.split("/")[0];
11168
- if (!firstSeg) return null;
11587
+ if (!firstSeg)
11588
+ return null;
11169
11589
  return "/" + firstSeg;
11170
11590
  }
11171
11591
  var ROUTE_METHOD_QUERY, MOUNT_PREFIX_QUERY, MIDDLEWARE_USE_QUERY, goChiAdapter;
11172
- var init_go_chi = __esm({
11173
- "src/detect/adapters/go-chi.ts"() {
11592
+ var init_dist = __esm({
11593
+ "../adapter-go-chi/dist/index.js"() {
11174
11594
  "use strict";
11175
- init_query_helpers();
11176
- init_tree_sitter_loader();
11177
- init_parse_guard();
11595
+ init_adapter();
11178
11596
  ROUTE_METHOD_QUERY = `
11179
11597
  (call_expression
11180
11598
  function: (selector_expression
@@ -11205,8 +11623,10 @@ var init_go_chi = __esm({
11205
11623
  id: "go-chi",
11206
11624
  languages: ["go"],
11207
11625
  matches(signals) {
11208
- if (!signals.goMod) return false;
11209
- if (/github\.com\/go-chi\/chi/i.test(signals.goMod)) return true;
11626
+ if (!signals.goMod)
11627
+ return false;
11628
+ if (/github\.com\/go-chi\/chi/i.test(signals.goMod))
11629
+ return true;
11210
11630
  return false;
11211
11631
  },
11212
11632
  async introspect(files, _rootDir) {
@@ -11215,49 +11635,48 @@ var init_go_chi = __esm({
11215
11635
  }
11216
11636
  let language;
11217
11637
  try {
11218
- language = await loadGrammar("go");
11638
+ language = await loadGrammar2("go");
11219
11639
  } catch (e2) {
11220
11640
  return { conventions: {}, provenance: [], confidence: "none" };
11221
11641
  }
11222
- const parser = new Parser7();
11642
+ const parser = new Parser8();
11223
11643
  parser.setLanguage(language);
11224
11644
  const routeMethods = /* @__PURE__ */ new Map();
11225
11645
  const mountBases = /* @__PURE__ */ new Map();
11226
11646
  const middlewareNames = /* @__PURE__ */ new Map();
11227
11647
  try {
11228
11648
  for (const file of files) {
11229
- const skip = isParsableSource(file.content, file.size);
11649
+ const skip = isParsableSource2(file.content, file.size);
11230
11650
  if (skip) {
11231
- process.stderr.write(
11232
- `[massu/ast] WARN: go-chi skipping ${file.path}: ${skip.reason} (${skip.detail}). Cap=${MAX_AST_FILE_BYTES}. (Phase 3.5 mitigation)
11233
- `
11234
- );
11651
+ process.stderr.write(`[massu/ast] WARN: go-chi skipping ${file.path}: ${skip.reason} (${skip.detail}). Cap=${MAX_AST_FILE_BYTES2}. (Phase 3.5 mitigation)
11652
+ `);
11235
11653
  continue;
11236
11654
  }
11237
11655
  try {
11238
- for (const hit of runQuery(parser, file.content, ROUTE_METHOD_QUERY, "chi-route-method", file.path)) {
11656
+ for (const hit of runQuery2(parser, file.content, ROUTE_METHOD_QUERY, "chi-route-method", file.path)) {
11239
11657
  const method = hit.captures.method;
11240
11658
  if (method && !routeMethods.has(method)) {
11241
11659
  routeMethods.set(method, { line: hit.line, file: file.path });
11242
11660
  }
11243
11661
  }
11244
- for (const hit of runQuery(parser, file.content, MOUNT_PREFIX_QUERY, "chi-mount-prefix", file.path)) {
11662
+ for (const hit of runQuery2(parser, file.content, MOUNT_PREFIX_QUERY, "chi-mount-prefix", file.path)) {
11245
11663
  const raw = hit.captures.mount_path;
11246
- if (!raw) continue;
11664
+ if (!raw)
11665
+ continue;
11247
11666
  const literal = raw.replace(/^["`]/, "").replace(/["`]$/, "");
11248
11667
  const base = extractPrefixBase4(literal);
11249
11668
  if (base && !mountBases.has(base)) {
11250
11669
  mountBases.set(base, { line: hit.line, file: file.path });
11251
11670
  }
11252
11671
  }
11253
- for (const hit of runQuery(parser, file.content, MIDDLEWARE_USE_QUERY, "chi-middleware-use", file.path)) {
11672
+ for (const hit of runQuery2(parser, file.content, MIDDLEWARE_USE_QUERY, "chi-middleware-use", file.path)) {
11254
11673
  const name = hit.captures.middleware_name;
11255
11674
  if (name && !middlewareNames.has(name)) {
11256
11675
  middlewareNames.set(name, { line: hit.line, file: file.path });
11257
11676
  }
11258
11677
  }
11259
11678
  } catch (e2) {
11260
- if (e2 instanceof InvalidQueryError) {
11679
+ if (e2 instanceof InvalidQueryError2) {
11261
11680
  throw e2;
11262
11681
  }
11263
11682
  continue;
@@ -11306,21 +11725,28 @@ var init_go_chi = __esm({
11306
11725
  }
11307
11726
  });
11308
11727
 
11309
- // src/detect/adapters/rails.ts
11310
- import { Parser as Parser8 } from "web-tree-sitter";
11728
+ // src/detect/adapters/go-chi.ts
11729
+ var init_go_chi = __esm({
11730
+ "src/detect/adapters/go-chi.ts"() {
11731
+ "use strict";
11732
+ init_dist();
11733
+ }
11734
+ });
11735
+
11736
+ // ../adapter-rails/dist/index.js
11737
+ import { Parser as Parser9 } from "web-tree-sitter";
11311
11738
  function extractRootController(target) {
11312
11739
  const idx = target.indexOf("#");
11313
- if (idx <= 0) return null;
11740
+ if (idx <= 0)
11741
+ return null;
11314
11742
  const controller = target.slice(0, idx).trim();
11315
11743
  return controller || null;
11316
11744
  }
11317
11745
  var ROUTE_METHOD_QUERY2, NAMESPACE_QUERY, ROOT_ROUTE_QUERY, railsAdapter;
11318
- var init_rails = __esm({
11319
- "src/detect/adapters/rails.ts"() {
11746
+ var init_dist2 = __esm({
11747
+ "../adapter-rails/dist/index.js"() {
11320
11748
  "use strict";
11321
- init_query_helpers();
11322
- init_tree_sitter_loader();
11323
- init_parse_guard();
11749
+ init_adapter();
11324
11750
  ROUTE_METHOD_QUERY2 = `
11325
11751
  (call
11326
11752
  method: (identifier) @method (#match? @method "^(get|post|put|patch|delete|options|head)$")
@@ -11356,7 +11782,8 @@ var init_rails = __esm({
11356
11782
  id: "rails",
11357
11783
  languages: ["ruby"],
11358
11784
  matches(signals) {
11359
- if (!signals.gemfile) return false;
11785
+ if (!signals.gemfile)
11786
+ return false;
11360
11787
  return /^\s*gem\s+['"]rails['"]/im.test(signals.gemfile);
11361
11788
  },
11362
11789
  async introspect(files, _rootDir) {
@@ -11365,45 +11792,45 @@ var init_rails = __esm({
11365
11792
  }
11366
11793
  let language;
11367
11794
  try {
11368
- language = await loadGrammar("ruby");
11795
+ language = await loadGrammar2("ruby");
11369
11796
  } catch (e2) {
11370
11797
  return { conventions: {}, provenance: [], confidence: "none" };
11371
11798
  }
11372
- const parser = new Parser8();
11799
+ const parser = new Parser9();
11373
11800
  parser.setLanguage(language);
11374
11801
  const routeMethods = /* @__PURE__ */ new Map();
11375
11802
  const namespaces = /* @__PURE__ */ new Map();
11376
11803
  const rootControllers = /* @__PURE__ */ new Map();
11377
11804
  try {
11378
11805
  for (const file of files) {
11379
- const skip = isParsableSource(file.content, file.size);
11806
+ const skip = isParsableSource2(file.content, file.size);
11380
11807
  if (skip) {
11381
- process.stderr.write(
11382
- `[massu/ast] WARN: rails skipping ${file.path}: ${skip.reason} (${skip.detail}). Cap=${MAX_AST_FILE_BYTES}. (Phase 3.5 mitigation)
11383
- `
11384
- );
11808
+ process.stderr.write(`[massu/ast] WARN: rails skipping ${file.path}: ${skip.reason} (${skip.detail}). Cap=${MAX_AST_FILE_BYTES2}. (Phase 3.5 mitigation)
11809
+ `);
11385
11810
  continue;
11386
11811
  }
11387
11812
  try {
11388
- for (const hit of runQuery(parser, file.content, ROUTE_METHOD_QUERY2, "rails-route-method", file.path)) {
11813
+ for (const hit of runQuery2(parser, file.content, ROUTE_METHOD_QUERY2, "rails-route-method", file.path)) {
11389
11814
  const method = hit.captures.method;
11390
11815
  if (method && !routeMethods.has(method)) {
11391
11816
  routeMethods.set(method, { line: hit.line, file: file.path });
11392
11817
  }
11393
11818
  }
11394
- for (const hit of runQuery(parser, file.content, NAMESPACE_QUERY, "rails-namespace", file.path)) {
11819
+ for (const hit of runQuery2(parser, file.content, NAMESPACE_QUERY, "rails-namespace", file.path)) {
11395
11820
  const symbolRaw = hit.captures.namespace_symbol;
11396
11821
  const stringRaw = hit.captures.namespace_string;
11397
11822
  const name = symbolRaw ? symbolRaw.replace(/^:/, "") : stringRaw ? stringRaw.replace(/^['"]/, "").replace(/['"]$/, "") : null;
11398
- if (!name) continue;
11823
+ if (!name)
11824
+ continue;
11399
11825
  const path = "/" + name;
11400
11826
  if (!namespaces.has(path)) {
11401
11827
  namespaces.set(path, { line: hit.line, file: file.path });
11402
11828
  }
11403
11829
  }
11404
- for (const hit of runQuery(parser, file.content, ROOT_ROUTE_QUERY, "rails-root", file.path)) {
11830
+ for (const hit of runQuery2(parser, file.content, ROOT_ROUTE_QUERY, "rails-root", file.path)) {
11405
11831
  const raw = hit.captures.root_target;
11406
- if (!raw) continue;
11832
+ if (!raw)
11833
+ continue;
11407
11834
  const literal = raw.replace(/^['"]/, "").replace(/['"]$/, "");
11408
11835
  const controller = extractRootController(literal);
11409
11836
  if (controller && !rootControllers.has(controller)) {
@@ -11411,7 +11838,7 @@ var init_rails = __esm({
11411
11838
  }
11412
11839
  }
11413
11840
  } catch (e2) {
11414
- if (e2 instanceof InvalidQueryError) {
11841
+ if (e2 instanceof InvalidQueryError2) {
11415
11842
  throw e2;
11416
11843
  }
11417
11844
  continue;
@@ -11460,22 +11887,30 @@ var init_rails = __esm({
11460
11887
  }
11461
11888
  });
11462
11889
 
11463
- // src/detect/adapters/phoenix.ts
11464
- import { Parser as Parser9 } from "web-tree-sitter";
11890
+ // src/detect/adapters/rails.ts
11891
+ var init_rails = __esm({
11892
+ "src/detect/adapters/rails.ts"() {
11893
+ "use strict";
11894
+ init_dist2();
11895
+ }
11896
+ });
11897
+
11898
+ // ../adapter-phoenix/dist/index.js
11899
+ import { Parser as Parser10 } from "web-tree-sitter";
11465
11900
  function extractPrefixBase5(prefix3) {
11466
- if (!prefix3.startsWith("/")) return null;
11901
+ if (!prefix3.startsWith("/"))
11902
+ return null;
11467
11903
  const stripped = prefix3.replace(/^\/+/, "");
11468
11904
  const firstSeg = stripped.split("/")[0];
11469
- if (!firstSeg) return null;
11905
+ if (!firstSeg)
11906
+ return null;
11470
11907
  return "/" + firstSeg;
11471
11908
  }
11472
11909
  var ROUTE_METHOD_QUERY3, SCOPE_PATH_QUERY, ROUTER_MODULE_QUERY, phoenixAdapter;
11473
- var init_phoenix = __esm({
11474
- "src/detect/adapters/phoenix.ts"() {
11910
+ var init_dist3 = __esm({
11911
+ "../adapter-phoenix/dist/index.js"() {
11475
11912
  "use strict";
11476
- init_query_helpers();
11477
- init_tree_sitter_loader();
11478
- init_parse_guard();
11913
+ init_adapter();
11479
11914
  ROUTE_METHOD_QUERY3 = `
11480
11915
  (call
11481
11916
  (identifier) @method (#match? @method "^(get|post|put|patch|delete|options|head)$")
@@ -11503,7 +11938,8 @@ var init_phoenix = __esm({
11503
11938
  id: "phoenix",
11504
11939
  languages: ["elixir"],
11505
11940
  matches(signals) {
11506
- if (!signals.mixExs) return false;
11941
+ if (!signals.mixExs)
11942
+ return false;
11507
11943
  return /\{\s*:phoenix\b(?!_)/.test(signals.mixExs);
11508
11944
  },
11509
11945
  async introspect(files, _rootDir) {
@@ -11512,49 +11948,48 @@ var init_phoenix = __esm({
11512
11948
  }
11513
11949
  let language;
11514
11950
  try {
11515
- language = await loadGrammar("elixir");
11951
+ language = await loadGrammar2("elixir");
11516
11952
  } catch (e2) {
11517
11953
  return { conventions: {}, provenance: [], confidence: "none" };
11518
11954
  }
11519
- const parser = new Parser9();
11955
+ const parser = new Parser10();
11520
11956
  parser.setLanguage(language);
11521
11957
  const routeMethods = /* @__PURE__ */ new Map();
11522
11958
  const scopePaths = /* @__PURE__ */ new Map();
11523
11959
  const routerModules = /* @__PURE__ */ new Map();
11524
11960
  try {
11525
11961
  for (const file of files) {
11526
- const skip = isParsableSource(file.content, file.size);
11962
+ const skip = isParsableSource2(file.content, file.size);
11527
11963
  if (skip) {
11528
- process.stderr.write(
11529
- `[massu/ast] WARN: phoenix skipping ${file.path}: ${skip.reason} (${skip.detail}). Cap=${MAX_AST_FILE_BYTES}. (Phase 3.5 mitigation)
11530
- `
11531
- );
11964
+ process.stderr.write(`[massu/ast] WARN: phoenix skipping ${file.path}: ${skip.reason} (${skip.detail}). Cap=${MAX_AST_FILE_BYTES2}. (Phase 3.5 mitigation)
11965
+ `);
11532
11966
  continue;
11533
11967
  }
11534
11968
  try {
11535
- for (const hit of runQuery(parser, file.content, ROUTE_METHOD_QUERY3, "phoenix-route-method", file.path)) {
11969
+ for (const hit of runQuery2(parser, file.content, ROUTE_METHOD_QUERY3, "phoenix-route-method", file.path)) {
11536
11970
  const method = hit.captures.method;
11537
11971
  if (method && !routeMethods.has(method)) {
11538
11972
  routeMethods.set(method, { line: hit.line, file: file.path });
11539
11973
  }
11540
11974
  }
11541
- for (const hit of runQuery(parser, file.content, SCOPE_PATH_QUERY, "phoenix-scope-path", file.path)) {
11975
+ for (const hit of runQuery2(parser, file.content, SCOPE_PATH_QUERY, "phoenix-scope-path", file.path)) {
11542
11976
  const raw = hit.captures.scope_path;
11543
- if (!raw) continue;
11977
+ if (!raw)
11978
+ continue;
11544
11979
  const literal = raw.replace(/^["']/, "").replace(/["']$/, "");
11545
11980
  const base = extractPrefixBase5(literal);
11546
11981
  if (base && !scopePaths.has(base)) {
11547
11982
  scopePaths.set(base, { line: hit.line, file: file.path });
11548
11983
  }
11549
11984
  }
11550
- for (const hit of runQuery(parser, file.content, ROUTER_MODULE_QUERY, "phoenix-router-module", file.path)) {
11985
+ for (const hit of runQuery2(parser, file.content, ROUTER_MODULE_QUERY, "phoenix-router-module", file.path)) {
11551
11986
  const name = hit.captures.module_name;
11552
11987
  if (name && !routerModules.has(name)) {
11553
11988
  routerModules.set(name, { line: hit.line, file: file.path });
11554
11989
  }
11555
11990
  }
11556
11991
  } catch (e2) {
11557
- if (e2 instanceof InvalidQueryError) {
11992
+ if (e2 instanceof InvalidQueryError2) {
11558
11993
  throw e2;
11559
11994
  }
11560
11995
  continue;
@@ -11603,21 +12038,28 @@ var init_phoenix = __esm({
11603
12038
  }
11604
12039
  });
11605
12040
 
11606
- // src/detect/adapters/aspnet.ts
11607
- import { Parser as Parser10 } from "web-tree-sitter";
12041
+ // src/detect/adapters/phoenix.ts
12042
+ var init_phoenix = __esm({
12043
+ "src/detect/adapters/phoenix.ts"() {
12044
+ "use strict";
12045
+ init_dist3();
12046
+ }
12047
+ });
12048
+
12049
+ // ../adapter-aspnet/dist/index.js
12050
+ import { Parser as Parser11 } from "web-tree-sitter";
11608
12051
  function extractPrefixBase6(prefix3) {
11609
12052
  const stripped = prefix3.replace(/^\/+/, "");
11610
12053
  const firstSeg = stripped.split("/")[0];
11611
- if (!firstSeg) return null;
12054
+ if (!firstSeg)
12055
+ return null;
11612
12056
  return "/" + firstSeg;
11613
12057
  }
11614
12058
  var MAP_VERB_QUERY, HTTP_ATTR_QUERY, ROUTE_ATTR_QUERY, CONTROLLER_CLASS_QUERY, aspnetAdapter;
11615
- var init_aspnet = __esm({
11616
- "src/detect/adapters/aspnet.ts"() {
12059
+ var init_dist4 = __esm({
12060
+ "../adapter-aspnet/dist/index.js"() {
11617
12061
  "use strict";
11618
- init_query_helpers();
11619
- init_tree_sitter_loader();
11620
- init_parse_guard();
12062
+ init_adapter();
11621
12063
  MAP_VERB_QUERY = `
11622
12064
  (invocation_expression
11623
12065
  function: (member_access_expression
@@ -11644,9 +12086,12 @@ var init_aspnet = __esm({
11644
12086
  id: "aspnet",
11645
12087
  languages: ["csharp"],
11646
12088
  matches(signals) {
11647
- if (!signals.csproj) return false;
11648
- if (/Sdk\s*=\s*["']Microsoft\.NET\.Sdk\.Web["']/i.test(signals.csproj)) return true;
11649
- if (/Microsoft\.AspNetCore\.App/i.test(signals.csproj)) return true;
12089
+ if (!signals.csproj)
12090
+ return false;
12091
+ if (/Sdk\s*=\s*["']Microsoft\.NET\.Sdk\.Web["']/i.test(signals.csproj))
12092
+ return true;
12093
+ if (/Microsoft\.AspNetCore\.App/i.test(signals.csproj))
12094
+ return true;
11650
12095
  return false;
11651
12096
  },
11652
12097
  async introspect(files, _rootDir) {
@@ -11655,29 +12100,28 @@ var init_aspnet = __esm({
11655
12100
  }
11656
12101
  let language;
11657
12102
  try {
11658
- language = await loadGrammar("csharp");
12103
+ language = await loadGrammar2("csharp");
11659
12104
  } catch (e2) {
11660
12105
  return { conventions: {}, provenance: [], confidence: "none" };
11661
12106
  }
11662
- const parser = new Parser10();
12107
+ const parser = new Parser11();
11663
12108
  parser.setLanguage(language);
11664
12109
  const routeMethods = /* @__PURE__ */ new Map();
11665
12110
  const prefixBases = /* @__PURE__ */ new Map();
11666
12111
  const controllerClasses = /* @__PURE__ */ new Map();
11667
12112
  try {
11668
12113
  for (const file of files) {
11669
- const skip = isParsableSource(file.content, file.size);
12114
+ const skip = isParsableSource2(file.content, file.size);
11670
12115
  if (skip) {
11671
- process.stderr.write(
11672
- `[massu/ast] WARN: aspnet skipping ${file.path}: ${skip.reason} (${skip.detail}). Cap=${MAX_AST_FILE_BYTES}. (Phase 3.5 mitigation)
11673
- `
11674
- );
12116
+ process.stderr.write(`[massu/ast] WARN: aspnet skipping ${file.path}: ${skip.reason} (${skip.detail}). Cap=${MAX_AST_FILE_BYTES2}. (Phase 3.5 mitigation)
12117
+ `);
11675
12118
  continue;
11676
12119
  }
11677
12120
  try {
11678
- for (const hit of runQuery(parser, file.content, MAP_VERB_QUERY, "aspnet-map-verb", file.path)) {
12121
+ for (const hit of runQuery2(parser, file.content, MAP_VERB_QUERY, "aspnet-map-verb", file.path)) {
11679
12122
  const methodRaw = hit.captures.method;
11680
- if (!methodRaw) continue;
12123
+ if (!methodRaw)
12124
+ continue;
11681
12125
  const verb = methodRaw.replace(/^Map/, "");
11682
12126
  if (!routeMethods.has(verb)) {
11683
12127
  routeMethods.set(verb, { line: hit.line, file: file.path });
@@ -11691,31 +12135,33 @@ var init_aspnet = __esm({
11691
12135
  }
11692
12136
  }
11693
12137
  }
11694
- for (const hit of runQuery(parser, file.content, HTTP_ATTR_QUERY, "aspnet-http-attr", file.path)) {
12138
+ for (const hit of runQuery2(parser, file.content, HTTP_ATTR_QUERY, "aspnet-http-attr", file.path)) {
11695
12139
  const attrRaw = hit.captures.attr_name;
11696
- if (!attrRaw) continue;
12140
+ if (!attrRaw)
12141
+ continue;
11697
12142
  const verb = attrRaw.replace(/^Http/, "");
11698
12143
  if (!routeMethods.has(verb)) {
11699
12144
  routeMethods.set(verb, { line: hit.line, file: file.path });
11700
12145
  }
11701
12146
  }
11702
- for (const hit of runQuery(parser, file.content, ROUTE_ATTR_QUERY, "aspnet-route-attr", file.path)) {
12147
+ for (const hit of runQuery2(parser, file.content, ROUTE_ATTR_QUERY, "aspnet-route-attr", file.path)) {
11703
12148
  const tplRaw = hit.captures.route_template;
11704
- if (!tplRaw) continue;
12149
+ if (!tplRaw)
12150
+ continue;
11705
12151
  const literal = tplRaw.replace(/^["']/, "").replace(/["']$/, "");
11706
12152
  const base = extractPrefixBase6(literal);
11707
12153
  if (base && !prefixBases.has(base)) {
11708
12154
  prefixBases.set(base, { line: hit.line, file: file.path });
11709
12155
  }
11710
12156
  }
11711
- for (const hit of runQuery(parser, file.content, CONTROLLER_CLASS_QUERY, "aspnet-controller-class", file.path)) {
12157
+ for (const hit of runQuery2(parser, file.content, CONTROLLER_CLASS_QUERY, "aspnet-controller-class", file.path)) {
11712
12158
  const name = hit.captures.class_name;
11713
12159
  if (name && !controllerClasses.has(name)) {
11714
12160
  controllerClasses.set(name, { line: hit.line, file: file.path });
11715
12161
  }
11716
12162
  }
11717
12163
  } catch (e2) {
11718
- if (e2 instanceof InvalidQueryError) {
12164
+ if (e2 instanceof InvalidQueryError2) {
11719
12165
  throw e2;
11720
12166
  }
11721
12167
  continue;
@@ -11764,21 +12210,28 @@ var init_aspnet = __esm({
11764
12210
  }
11765
12211
  });
11766
12212
 
11767
- // src/detect/adapters/spring.ts
11768
- import { Parser as Parser11 } from "web-tree-sitter";
12213
+ // src/detect/adapters/aspnet.ts
12214
+ var init_aspnet = __esm({
12215
+ "src/detect/adapters/aspnet.ts"() {
12216
+ "use strict";
12217
+ init_dist4();
12218
+ }
12219
+ });
12220
+
12221
+ // ../adapter-spring/dist/index.js
12222
+ import { Parser as Parser12 } from "web-tree-sitter";
11769
12223
  function extractPrefixBase7(prefix3) {
11770
12224
  const stripped = prefix3.replace(/^\/+/, "");
11771
12225
  const firstSeg = stripped.split("/")[0];
11772
- if (!firstSeg) return null;
12226
+ if (!firstSeg)
12227
+ return null;
11773
12228
  return "/" + firstSeg;
11774
12229
  }
11775
12230
  var HTTP_MAPPING_QUERY, HTTP_MAPPING_NO_ARGS_QUERY, REQUEST_MAPPING_QUERY, CONTROLLER_CLASS_QUERY2, springAdapter;
11776
- var init_spring = __esm({
11777
- "src/detect/adapters/spring.ts"() {
12231
+ var init_dist5 = __esm({
12232
+ "../adapter-spring/dist/index.js"() {
11778
12233
  "use strict";
11779
- init_query_helpers();
11780
- init_tree_sitter_loader();
11781
- init_parse_guard();
12234
+ init_adapter();
11782
12235
  HTTP_MAPPING_QUERY = `
11783
12236
  (annotation
11784
12237
  name: (identifier) @method (#match? @method "^(Get|Post|Put|Patch|Delete|Head|Options)Mapping$")
@@ -11832,59 +12285,60 @@ var init_spring = __esm({
11832
12285
  }
11833
12286
  let language;
11834
12287
  try {
11835
- language = await loadGrammar("java");
12288
+ language = await loadGrammar2("java");
11836
12289
  } catch (e2) {
11837
12290
  return { conventions: {}, provenance: [], confidence: "none" };
11838
12291
  }
11839
- const parser = new Parser11();
12292
+ const parser = new Parser12();
11840
12293
  parser.setLanguage(language);
11841
12294
  const routeMethods = /* @__PURE__ */ new Map();
11842
12295
  const prefixBases = /* @__PURE__ */ new Map();
11843
12296
  const controllerClasses = /* @__PURE__ */ new Map();
11844
12297
  try {
11845
12298
  for (const file of files) {
11846
- const skip = isParsableSource(file.content, file.size);
12299
+ const skip = isParsableSource2(file.content, file.size);
11847
12300
  if (skip) {
11848
- process.stderr.write(
11849
- `[massu/ast] WARN: spring skipping ${file.path}: ${skip.reason} (${skip.detail}). Cap=${MAX_AST_FILE_BYTES}. (Phase 3.5 mitigation)
11850
- `
11851
- );
12301
+ process.stderr.write(`[massu/ast] WARN: spring skipping ${file.path}: ${skip.reason} (${skip.detail}). Cap=${MAX_AST_FILE_BYTES2}. (Phase 3.5 mitigation)
12302
+ `);
11852
12303
  continue;
11853
12304
  }
11854
12305
  try {
11855
- for (const hit of runQuery(parser, file.content, HTTP_MAPPING_QUERY, "spring-http-mapping", file.path)) {
12306
+ for (const hit of runQuery2(parser, file.content, HTTP_MAPPING_QUERY, "spring-http-mapping", file.path)) {
11856
12307
  const methodRaw = hit.captures.method;
11857
- if (!methodRaw) continue;
12308
+ if (!methodRaw)
12309
+ continue;
11858
12310
  const verb = methodRaw.replace(/Mapping$/, "");
11859
12311
  if (!routeMethods.has(verb)) {
11860
12312
  routeMethods.set(verb, { line: hit.line, file: file.path });
11861
12313
  }
11862
12314
  }
11863
- for (const hit of runQuery(parser, file.content, HTTP_MAPPING_NO_ARGS_QUERY, "spring-http-mapping-marker", file.path)) {
12315
+ for (const hit of runQuery2(parser, file.content, HTTP_MAPPING_NO_ARGS_QUERY, "spring-http-mapping-marker", file.path)) {
11864
12316
  const methodRaw = hit.captures.method;
11865
- if (!methodRaw) continue;
12317
+ if (!methodRaw)
12318
+ continue;
11866
12319
  const verb = methodRaw.replace(/Mapping$/, "");
11867
12320
  if (!routeMethods.has(verb)) {
11868
12321
  routeMethods.set(verb, { line: hit.line, file: file.path });
11869
12322
  }
11870
12323
  }
11871
- for (const hit of runQuery(parser, file.content, REQUEST_MAPPING_QUERY, "spring-request-mapping", file.path)) {
12324
+ for (const hit of runQuery2(parser, file.content, REQUEST_MAPPING_QUERY, "spring-request-mapping", file.path)) {
11872
12325
  const tplRaw = hit.captures.route_template;
11873
- if (!tplRaw) continue;
12326
+ if (!tplRaw)
12327
+ continue;
11874
12328
  const literal = tplRaw.replace(/^["']/, "").replace(/["']$/, "");
11875
12329
  const base = extractPrefixBase7(literal);
11876
12330
  if (base && !prefixBases.has(base)) {
11877
12331
  prefixBases.set(base, { line: hit.line, file: file.path });
11878
12332
  }
11879
12333
  }
11880
- for (const hit of runQuery(parser, file.content, CONTROLLER_CLASS_QUERY2, "spring-controller-class", file.path)) {
12334
+ for (const hit of runQuery2(parser, file.content, CONTROLLER_CLASS_QUERY2, "spring-controller-class", file.path)) {
11881
12335
  const name = hit.captures.class_name;
11882
12336
  if (name && !controllerClasses.has(name)) {
11883
12337
  controllerClasses.set(name, { line: hit.line, file: file.path });
11884
12338
  }
11885
12339
  }
11886
12340
  } catch (e2) {
11887
- if (e2 instanceof InvalidQueryError) {
12341
+ if (e2 instanceof InvalidQueryError2) {
11888
12342
  throw e2;
11889
12343
  }
11890
12344
  continue;
@@ -11933,6 +12387,14 @@ var init_spring = __esm({
11933
12387
  }
11934
12388
  });
11935
12389
 
12390
+ // src/detect/adapters/spring.ts
12391
+ var init_spring = __esm({
12392
+ "src/detect/adapters/spring.ts"() {
12393
+ "use strict";
12394
+ init_dist5();
12395
+ }
12396
+ });
12397
+
11936
12398
  // src/detect/adapters/file-sampler.ts
11937
12399
  var file_sampler_exports = {};
11938
12400
  __export(file_sampler_exports, {
@@ -11940,8 +12402,8 @@ __export(file_sampler_exports, {
11940
12402
  SAMPLE_TEST_FILE_PATTERNS: () => SAMPLE_TEST_FILE_PATTERNS,
11941
12403
  sampleFilesForAdapter: () => sampleFilesForAdapter
11942
12404
  });
11943
- import { readdirSync as readdirSync9, readFileSync as readFileSync9, lstatSync as lstatSync4 } from "node:fs";
11944
- import { join as join9, extname } from "node:path";
12405
+ import { readdirSync as readdirSync10, readFileSync as readFileSync10, lstatSync as lstatSync5 } from "node:fs";
12406
+ import { join as join10, extname } from "node:path";
11945
12407
  function sampleFilesForAdapter(adapter, projectRoot, detection, options = {}) {
11946
12408
  const maxDepth = options.maxDepth ?? DEFAULT_MAX_DEPTH;
11947
12409
  const maxFiles = options.maxFilesPerAdapter ?? DEFAULT_MAX_FILES;
@@ -11956,7 +12418,7 @@ function sampleFilesForAdapter(adapter, projectRoot, detection, options = {}) {
11956
12418
  const langDetection = detection.sourceDirs[langKey];
11957
12419
  const candidateDirs = [];
11958
12420
  if (langDetection?.source_dirs && langDetection.source_dirs.length > 0) {
11959
- candidateDirs.push(...langDetection.source_dirs.map((d2) => join9(projectRoot, d2)));
12421
+ candidateDirs.push(...langDetection.source_dirs.map((d2) => join10(projectRoot, d2)));
11960
12422
  } else {
11961
12423
  candidateDirs.push(projectRoot);
11962
12424
  }
@@ -11972,7 +12434,7 @@ function walkDir(dir, exts, testPatterns, lang, maxDepth, curDepth, out, seen, m
11972
12434
  if (out.length >= maxFiles) return;
11973
12435
  let entries;
11974
12436
  try {
11975
- entries = readdirSync9(dir);
12437
+ entries = readdirSync10(dir);
11976
12438
  } catch {
11977
12439
  return;
11978
12440
  }
@@ -11980,10 +12442,10 @@ function walkDir(dir, exts, testPatterns, lang, maxDepth, curDepth, out, seen, m
11980
12442
  if (out.length >= maxFiles) return;
11981
12443
  if (entry.startsWith(".")) continue;
11982
12444
  if (IGNORED_DIRS3.has(entry)) continue;
11983
- const fullPath = join9(dir, entry);
12445
+ const fullPath = join10(dir, entry);
11984
12446
  let st;
11985
12447
  try {
11986
- st = lstatSync4(fullPath);
12448
+ st = lstatSync5(fullPath);
11987
12449
  } catch {
11988
12450
  continue;
11989
12451
  }
@@ -12001,7 +12463,7 @@ function walkDir(dir, exts, testPatterns, lang, maxDepth, curDepth, out, seen, m
12001
12463
  seen.add(fullPath);
12002
12464
  let content;
12003
12465
  try {
12004
- content = readFileSync9(fullPath, "utf-8");
12466
+ content = readFileSync10(fullPath, "utf-8");
12005
12467
  } catch {
12006
12468
  continue;
12007
12469
  }
@@ -12239,7 +12701,7 @@ var init_detect = __esm({
12239
12701
  });
12240
12702
 
12241
12703
  // src/detect/drift.ts
12242
- import { createHash as createHash3 } from "crypto";
12704
+ import { createHash as createHash4 } from "crypto";
12243
12705
  function summarizeDetection(det) {
12244
12706
  const languages = Array.from(new Set(det.manifests.map((m3) => m3.language))).sort();
12245
12707
  const frameworks = {};
@@ -12270,7 +12732,7 @@ function summarizeDetection(det) {
12270
12732
  function computeFingerprint(det) {
12271
12733
  const data = summarizeDetection(det);
12272
12734
  const stable = JSON.stringify(data, Object.keys(data).sort());
12273
- return createHash3("sha256").update(stable).digest("hex");
12735
+ return createHash4("sha256").update(stable).digest("hex");
12274
12736
  }
12275
12737
  function stringOf(v3) {
12276
12738
  if (typeof v3 === "string") return v3;
@@ -12620,7 +13082,7 @@ function cD({ input: t = $, output: u2 = j, overwrite: F = true, hideCursor: e2
12620
13082
  };
12621
13083
  }
12622
13084
  var import_sisteransi, import_picocolors, Q, P, X, DD, uD, FD, m, L, N, I, r, tD, eD, iD, v, CD, w, W, rD, R, y, V, z2, ED, _, nD, oD, aD, c, xD, S, AD, pD, h, x, fD, gD, vD, K, dD, bD, mD, Y, wD, yD, _D, Z, kD, SD, $D, q, jD, MD, TD, H, OD, PD;
12623
- var init_dist = __esm({
13085
+ var init_dist6 = __esm({
12624
13086
  "../../node_modules/@clack/core/dist/index.mjs"() {
12625
13087
  import_sisteransi = __toESM(require_src(), 1);
12626
13088
  import_picocolors = __toESM(require_picocolors(), 1);
@@ -13038,10 +13500,10 @@ function X2() {
13038
13500
  return p.platform !== "win32" ? p.env.TERM !== "linux" : !!p.env.CI || !!p.env.WT_SESSION || !!p.env.TERMINUS_SUBLIME || p.env.ConEmuTask === "{cmd::Cmder}" || p.env.TERM_PROGRAM === "Terminus-Sublime" || p.env.TERM_PROGRAM === "vscode" || p.env.TERM === "xterm-256color" || p.env.TERM === "alacritty" || p.env.TERMINAL_EMULATOR === "JetBrains-JediTerm";
13039
13501
  }
13040
13502
  var import_picocolors2, import_sisteransi2, E, u, ee, A2, B, S2, te, a, m2, j2, R2, V2, M2, G2, se, N2, re, ie, ne, ae, oe, ce, le, y2, k2, ue, $e, me, de, he, pe, ge, ye, ve, we, fe, v2, L2, be, xe;
13041
- var init_dist2 = __esm({
13503
+ var init_dist7 = __esm({
13042
13504
  "../../node_modules/@clack/prompts/dist/index.mjs"() {
13043
- init_dist();
13044
- init_dist();
13505
+ init_dist6();
13506
+ init_dist6();
13045
13507
  import_picocolors2 = __toESM(require_picocolors(), 1);
13046
13508
  import_sisteransi2 = __toESM(require_src(), 1);
13047
13509
  E = X2();
@@ -13429,10 +13891,10 @@ __export(init_exports, {
13429
13891
  validateWrittenConfig: () => validateWrittenConfig,
13430
13892
  writeConfigAtomic: () => writeConfigAtomic
13431
13893
  });
13432
- import { closeSync as closeSync2, existsSync as existsSync10, fsyncSync as fsyncSync2, openSync as openSync2, readFileSync as readFileSync10, writeFileSync as writeFileSync2, writeSync as writeSync2, mkdirSync as mkdirSync4, readdirSync as readdirSync10, renameSync as renameSync3, rmSync as rmSync2, statSync as statSync7, chmodSync as chmodSync2 } from "fs";
13433
- import { resolve as resolve6, basename as basename4, dirname as dirname5 } from "path";
13894
+ import { closeSync as closeSync2, existsSync as existsSync10, fsyncSync as fsyncSync2, openSync as openSync2, readFileSync as readFileSync11, writeFileSync as writeFileSync3, writeSync as writeSync2, mkdirSync as mkdirSync5, readdirSync as readdirSync11, renameSync as renameSync4, rmSync as rmSync2, statSync as statSync7, chmodSync as chmodSync3 } from "fs";
13895
+ import { resolve as resolve6, basename as basename4, dirname as dirname6 } from "path";
13434
13896
  import { fileURLToPath as fileURLToPath2 } from "url";
13435
- import { homedir as homedir3 } from "os";
13897
+ import { homedir as homedir4 } from "os";
13436
13898
  import { stringify as yamlStringify, parse as yamlParse } from "yaml";
13437
13899
  function detectFramework(projectRoot) {
13438
13900
  const result = {
@@ -13444,7 +13906,7 @@ function detectFramework(projectRoot) {
13444
13906
  const pkgPath = resolve6(projectRoot, "package.json");
13445
13907
  if (!existsSync10(pkgPath)) return result;
13446
13908
  try {
13447
- const pkg = JSON.parse(readFileSync10(pkgPath, "utf-8"));
13909
+ const pkg = JSON.parse(readFileSync11(pkgPath, "utf-8"));
13448
13910
  const allDeps = {
13449
13911
  ...pkg.dependencies,
13450
13912
  ...pkg.devDependencies
@@ -13491,7 +13953,7 @@ function detectPython(projectRoot) {
13491
13953
  const filePath = resolve6(projectRoot, file);
13492
13954
  if (existsSync10(filePath)) {
13493
13955
  try {
13494
- const content = readFileSync10(filePath, "utf-8").toLowerCase();
13956
+ const content = readFileSync11(filePath, "utf-8").toLowerCase();
13495
13957
  if (content.includes("fastapi")) result.hasFastapi = true;
13496
13958
  if (content.includes("sqlalchemy")) result.hasSqlalchemy = true;
13497
13959
  } catch {
@@ -13516,7 +13978,7 @@ function detectPython(projectRoot) {
13516
13978
  }
13517
13979
  if (existsSync10(candidatePath)) {
13518
13980
  try {
13519
- const files = readdirSync10(candidatePath);
13981
+ const files = readdirSync11(candidatePath);
13520
13982
  if (files.some((f2) => f2.endsWith(".py"))) {
13521
13983
  result.root = candidate;
13522
13984
  break;
@@ -13581,7 +14043,7 @@ function generateConfig(projectRoot, framework) {
13581
14043
  # Documentation: https://massu.ai/docs/getting-started/configuration
13582
14044
 
13583
14045
  ${yamlStringify(config)}`;
13584
- writeFileSync2(configPath, yamlContent, "utf-8");
14046
+ writeFileSync3(configPath, yamlContent, "utf-8");
13585
14047
  return true;
13586
14048
  }
13587
14049
  function monorepoCommonRoot(packages) {
@@ -13752,7 +14214,7 @@ function applyVariantTemplate(config, templatesDir) {
13752
14214
  if (!existsSync10(templatePath)) return config;
13753
14215
  let template;
13754
14216
  try {
13755
- template = yamlParse(readFileSync10(templatePath, "utf-8"));
14217
+ template = yamlParse(readFileSync11(templatePath, "utf-8"));
13756
14218
  } catch {
13757
14219
  return config;
13758
14220
  }
@@ -13819,7 +14281,7 @@ function writeConfigAtomic(configPath, content) {
13819
14281
  }
13820
14282
  }
13821
14283
  try {
13822
- mkdirSync4(dirname5(configPath), { recursive: true });
14284
+ mkdirSync5(dirname6(configPath), { recursive: true });
13823
14285
  const fd = openSync2(tmpPath, "w", 420);
13824
14286
  try {
13825
14287
  const buf = Buffer.from(content, "utf-8");
@@ -13832,10 +14294,10 @@ function writeConfigAtomic(configPath, content) {
13832
14294
  if (parsed === null || typeof parsed !== "object") {
13833
14295
  throw new Error("Generated config is not a valid YAML object");
13834
14296
  }
13835
- renameSync3(tmpPath, configPath);
14297
+ renameSync4(tmpPath, configPath);
13836
14298
  if (existingMode !== void 0) {
13837
14299
  try {
13838
- chmodSync2(configPath, existingMode);
14300
+ chmodSync3(configPath, existingMode);
13839
14301
  } catch {
13840
14302
  }
13841
14303
  }
@@ -13853,7 +14315,7 @@ function writeConfigAtomic(configPath, content) {
13853
14315
  function validateWrittenConfig(configPath, projectRoot, checkPaths = true) {
13854
14316
  try {
13855
14317
  if (!existsSync10(configPath)) return "Config file does not exist after write";
13856
- const content = readFileSync10(configPath, "utf-8");
14318
+ const content = readFileSync11(configPath, "utf-8");
13857
14319
  const parsed = yamlParse(content);
13858
14320
  if (parsed === null || typeof parsed !== "object") {
13859
14321
  return "Config is not a valid YAML object";
@@ -13954,9 +14416,9 @@ function copyTemplateConfig(templateName, targetPath, projectName) {
13954
14416
  return { success: false, error: `Template '${templateName}' not found at ${srcPath}` };
13955
14417
  }
13956
14418
  try {
13957
- let content = readFileSync10(srcPath, "utf-8");
14419
+ let content = readFileSync11(srcPath, "utf-8");
13958
14420
  content = content.replace(/\{\{PROJECT_NAME\}\}/g, projectName);
13959
- writeFileSync2(targetPath, content, "utf-8");
14421
+ writeFileSync3(targetPath, content, "utf-8");
13960
14422
  return { success: true };
13961
14423
  } catch (err) {
13962
14424
  return { success: false, error: err instanceof Error ? err.message : String(err) };
@@ -13967,7 +14429,7 @@ function registerMcpServer(projectRoot) {
13967
14429
  let existing = {};
13968
14430
  if (existsSync10(mcpPath)) {
13969
14431
  try {
13970
- existing = JSON.parse(readFileSync10(mcpPath, "utf-8"));
14432
+ existing = JSON.parse(readFileSync11(mcpPath, "utf-8"));
13971
14433
  } catch {
13972
14434
  existing = {};
13973
14435
  }
@@ -13982,7 +14444,7 @@ function registerMcpServer(projectRoot) {
13982
14444
  args: ["-y", "@massu/core"]
13983
14445
  };
13984
14446
  existing.mcpServers = servers;
13985
- writeFileSync2(mcpPath, JSON.stringify(existing, null, 2) + "\n", "utf-8");
14447
+ writeFileSync3(mcpPath, JSON.stringify(existing, null, 2) + "\n", "utf-8");
13986
14448
  return true;
13987
14449
  }
13988
14450
  function resolveHooksDir() {
@@ -14087,12 +14549,12 @@ function installHooks(projectRoot) {
14087
14549
  const claudeDir = resolve6(projectRoot, claudeDirName);
14088
14550
  const settingsPath = resolve6(claudeDir, "settings.local.json");
14089
14551
  if (!existsSync10(claudeDir)) {
14090
- mkdirSync4(claudeDir, { recursive: true });
14552
+ mkdirSync5(claudeDir, { recursive: true });
14091
14553
  }
14092
14554
  let settings = {};
14093
14555
  if (existsSync10(settingsPath)) {
14094
14556
  try {
14095
- settings = JSON.parse(readFileSync10(settingsPath, "utf-8"));
14557
+ settings = JSON.parse(readFileSync11(settingsPath, "utf-8"));
14096
14558
  } catch {
14097
14559
  settings = {};
14098
14560
  }
@@ -14106,15 +14568,15 @@ function installHooks(projectRoot) {
14106
14568
  }
14107
14569
  }
14108
14570
  settings.hooks = hooksConfig;
14109
- writeFileSync2(settingsPath, JSON.stringify(settings, null, 2) + "\n", "utf-8");
14571
+ writeFileSync3(settingsPath, JSON.stringify(settings, null, 2) + "\n", "utf-8");
14110
14572
  return { installed: true, count: hookCount };
14111
14573
  }
14112
14574
  function initMemoryDir(projectRoot) {
14113
14575
  const encodedRoot = "-" + projectRoot.replace(/\//g, "-");
14114
- const memoryDir = resolve6(homedir3(), `.claude/projects/${encodedRoot}/memory`);
14576
+ const memoryDir = resolve6(homedir4(), `.claude/projects/${encodedRoot}/memory`);
14115
14577
  let created = false;
14116
14578
  if (!existsSync10(memoryDir)) {
14117
- mkdirSync4(memoryDir, { recursive: true });
14579
+ mkdirSync5(memoryDir, { recursive: true });
14118
14580
  created = true;
14119
14581
  }
14120
14582
  const memoryMdPath = resolve6(memoryDir, "MEMORY.md");
@@ -14135,7 +14597,7 @@ function initMemoryDir(projectRoot) {
14135
14597
  ## File Index
14136
14598
  <!-- Significant files and directories -->
14137
14599
  `;
14138
- writeFileSync2(memoryMdPath, memoryContent, "utf-8");
14600
+ writeFileSync3(memoryMdPath, memoryContent, "utf-8");
14139
14601
  memoryMdCreated = true;
14140
14602
  }
14141
14603
  return { created, memoryMdCreated };
@@ -14387,8 +14849,8 @@ function installSideEffects(projectRoot, log, skipCommands = false, emptyStack =
14387
14849
  "\u2014 Massu"
14388
14850
  ].join("\n");
14389
14851
  try {
14390
- mkdirSync4(resolve6(cmdResult.claudeDir, "commands"), { recursive: true });
14391
- writeFileSync2(placeholderPath, placeholderBody, "utf-8");
14852
+ mkdirSync5(resolve6(cmdResult.claudeDir, "commands"), { recursive: true });
14853
+ writeFileSync3(placeholderPath, placeholderBody, "utf-8");
14392
14854
  log(" Wrote _massu-needs-stack.md placeholder (no stack detected yet)");
14393
14855
  } catch {
14394
14856
  }
@@ -14407,8 +14869,8 @@ function installSideEffects(projectRoot, log, skipCommands = false, emptyStack =
14407
14869
  (async () => {
14408
14870
  try {
14409
14871
  const encodedRoot = projectRoot.replace(/\//g, "-");
14410
- const memoryDir = resolve6(homedir3(), ".claude", "projects", encodedRoot, "memory");
14411
- const memFiles = existsSync10(memoryDir) ? readdirSync10(memoryDir).filter((f2) => f2.endsWith(".md") && f2 !== "MEMORY.md") : [];
14872
+ const memoryDir = resolve6(homedir4(), ".claude", "projects", encodedRoot, "memory");
14873
+ const memFiles = existsSync10(memoryDir) ? readdirSync11(memoryDir).filter((f2) => f2.endsWith(".md") && f2 !== "MEMORY.md") : [];
14412
14874
  if (memFiles.length > 0) {
14413
14875
  const { getMemoryDb: getMemoryDb2 } = await Promise.resolve().then(() => (init_memory_db(), memory_db_exports));
14414
14876
  const db = getMemoryDb2();
@@ -14431,7 +14893,7 @@ function installSideEffects(projectRoot, log, skipCommands = false, emptyStack =
14431
14893
  }
14432
14894
  async function promptOverwrite(configPath) {
14433
14895
  try {
14434
- const { confirm, isCancel } = await Promise.resolve().then(() => (init_dist2(), dist_exports));
14896
+ const { confirm, isCancel } = await Promise.resolve().then(() => (init_dist7(), dist_exports));
14435
14897
  const res = await confirm({
14436
14898
  message: `massu.config.yaml already exists at ${configPath}. Overwrite?`,
14437
14899
  initialValue: false
@@ -14444,7 +14906,7 @@ async function promptOverwrite(configPath) {
14444
14906
  }
14445
14907
  async function promptStackConfirm() {
14446
14908
  try {
14447
- const { confirm, isCancel } = await Promise.resolve().then(() => (init_dist2(), dist_exports));
14909
+ const { confirm, isCancel } = await Promise.resolve().then(() => (init_dist7(), dist_exports));
14448
14910
  const res = await confirm({
14449
14911
  message: "Generate massu.config.yaml from detected stack?",
14450
14912
  initialValue: true
@@ -14468,7 +14930,7 @@ var init_init = __esm({
14468
14930
  init_detect();
14469
14931
  init_drift();
14470
14932
  __filename2 = fileURLToPath2(import.meta.url);
14471
- __dirname2 = dirname5(__filename2);
14933
+ __dirname2 = dirname6(__filename2);
14472
14934
  FRAMEWORK_TO_TEMPLATE_ID = {
14473
14935
  rails: "rails",
14474
14936
  phoenix: "phoenix",
@@ -14490,7 +14952,7 @@ var init_init = __esm({
14490
14952
  });
14491
14953
 
14492
14954
  // src/license.ts
14493
- import { createHash as createHash4 } from "crypto";
14955
+ import { createHash as createHash5 } from "crypto";
14494
14956
  function tierLevel(tier) {
14495
14957
  return TIER_LEVELS[tier] ?? 0;
14496
14958
  }
@@ -14515,7 +14977,7 @@ function annotateToolDefinitions(defs) {
14515
14977
  });
14516
14978
  }
14517
14979
  async function validateLicense(apiKey) {
14518
- const keyHash = createHash4("sha256").update(apiKey).digest("hex");
14980
+ const keyHash = createHash5("sha256").update(apiKey).digest("hex");
14519
14981
  const memDb = getMemoryDb();
14520
14982
  try {
14521
14983
  const cached = memDb.prepare(
@@ -14576,7 +15038,7 @@ async function validateLicense(apiKey) {
14576
15038
  }
14577
15039
  }
14578
15040
  function updateLicenseCache(apiKey, tier, validUntil, features = []) {
14579
- const keyHash = createHash4("sha256").update(apiKey).digest("hex");
15041
+ const keyHash = createHash5("sha256").update(apiKey).digest("hex");
14580
15042
  const memDb = getMemoryDb();
14581
15043
  try {
14582
15044
  memDb.prepare(`
@@ -14784,8 +15246,8 @@ __export(doctor_exports, {
14784
15246
  runDoctor: () => runDoctor,
14785
15247
  runValidateConfig: () => runValidateConfig
14786
15248
  });
14787
- import { existsSync as existsSync11, readFileSync as readFileSync11, readdirSync as readdirSync11 } from "fs";
14788
- import { resolve as resolve7, dirname as dirname6 } from "path";
15249
+ import { existsSync as existsSync11, readFileSync as readFileSync12, readdirSync as readdirSync12 } from "fs";
15250
+ import { resolve as resolve7, dirname as dirname7 } from "path";
14789
15251
  import { fileURLToPath as fileURLToPath3 } from "url";
14790
15252
  import { parse as parseYaml4 } from "yaml";
14791
15253
  function checkConfig(projectRoot) {
@@ -14794,7 +15256,7 @@ function checkConfig(projectRoot) {
14794
15256
  return { name: "Configuration", status: "fail", detail: "massu.config.yaml not found. Run: npx massu init" };
14795
15257
  }
14796
15258
  try {
14797
- const content = readFileSync11(configPath, "utf-8");
15259
+ const content = readFileSync12(configPath, "utf-8");
14798
15260
  const parsed = parseYaml4(content);
14799
15261
  if (!parsed || typeof parsed !== "object") {
14800
15262
  return { name: "Configuration", status: "fail", detail: "massu.config.yaml is empty or invalid YAML" };
@@ -14810,7 +15272,7 @@ function checkMcpServer(projectRoot) {
14810
15272
  return { name: "MCP Server", status: "fail", detail: ".mcp.json not found. Run: npx massu init" };
14811
15273
  }
14812
15274
  try {
14813
- const content = JSON.parse(readFileSync11(mcpPath, "utf-8"));
15275
+ const content = JSON.parse(readFileSync12(mcpPath, "utf-8"));
14814
15276
  const servers = content.mcpServers ?? {};
14815
15277
  if (!servers.massu) {
14816
15278
  return { name: "MCP Server", status: "fail", detail: "massu not registered in .mcp.json. Run: npx massu init" };
@@ -14826,7 +15288,7 @@ function checkHooksConfig(projectRoot) {
14826
15288
  return { name: "Hooks Config", status: "fail", detail: ".claude/settings.local.json not found. Run: npx massu init" };
14827
15289
  }
14828
15290
  try {
14829
- const content = JSON.parse(readFileSync11(settingsPath, "utf-8"));
15291
+ const content = JSON.parse(readFileSync12(settingsPath, "utf-8"));
14830
15292
  if (!content.hooks) {
14831
15293
  return { name: "Hooks Config", status: "fail", detail: "No hooks configured. Run: npx massu install-hooks" };
14832
15294
  }
@@ -14937,7 +15399,7 @@ function checkShellHooksWired(_projectRoot2) {
14937
15399
  };
14938
15400
  }
14939
15401
  try {
14940
- const content = JSON.parse(readFileSync11(settingsPath, "utf-8"));
15402
+ const content = JSON.parse(readFileSync12(settingsPath, "utf-8"));
14941
15403
  const hooks = content.hooks ?? {};
14942
15404
  const hasSessionStart = Array.isArray(hooks.SessionStart) && hooks.SessionStart.length > 0;
14943
15405
  const hasPreToolUse = Array.isArray(hooks.PreToolUse) && hooks.PreToolUse.length > 0;
@@ -15003,7 +15465,7 @@ function checkPythonHealth(projectRoot) {
15003
15465
  function scanDir(dir, depth) {
15004
15466
  if (depth > 5) return;
15005
15467
  try {
15006
- const entries = readdirSync11(dir, { withFileTypes: true });
15468
+ const entries = readdirSync12(dir, { withFileTypes: true });
15007
15469
  for (const entry of entries) {
15008
15470
  if (entry.isDirectory()) {
15009
15471
  const excludeDirs = config.python?.exclude_dirs || ["__pycache__", ".venv", "venv", ".mypy_cache", ".pytest_cache"];
@@ -15011,7 +15473,7 @@ function checkPythonHealth(projectRoot) {
15011
15473
  const subdir = resolve7(dir, entry.name);
15012
15474
  if (depth <= 2 && !existsSync11(resolve7(subdir, "__init__.py"))) {
15013
15475
  try {
15014
- const subEntries = readdirSync11(subdir);
15476
+ const subEntries = readdirSync12(subdir);
15015
15477
  if (subEntries.some((f2) => f2.endsWith(".py") && f2 !== "__init__.py")) {
15016
15478
  initPyMissing.push(entry.name);
15017
15479
  }
@@ -15112,7 +15574,7 @@ async function runValidateConfig() {
15112
15574
  return;
15113
15575
  }
15114
15576
  try {
15115
- const content = readFileSync11(configPath, "utf-8");
15577
+ const content = readFileSync12(configPath, "utf-8");
15116
15578
  const parsed = parseYaml4(content);
15117
15579
  if (!parsed || typeof parsed !== "object") {
15118
15580
  console.error("Error: massu.config.yaml is empty or not a valid YAML object");
@@ -15151,7 +15613,7 @@ var init_doctor = __esm({
15151
15613
  init_config();
15152
15614
  init_license();
15153
15615
  __filename3 = fileURLToPath3(import.meta.url);
15154
- __dirname3 = dirname6(__filename3);
15616
+ __dirname3 = dirname7(__filename3);
15155
15617
  EXPECTED_HOOKS = [
15156
15618
  "session-start.js",
15157
15619
  "session-end.js",
@@ -15197,7 +15659,7 @@ var show_template_exports = {};
15197
15659
  __export(show_template_exports, {
15198
15660
  runShowTemplate: () => runShowTemplate
15199
15661
  });
15200
- import { existsSync as existsSync12, readFileSync as readFileSync12 } from "fs";
15662
+ import { existsSync as existsSync12, readFileSync as readFileSync13 } from "fs";
15201
15663
  import { resolve as resolve8 } from "path";
15202
15664
  function normalizeBaseName(input) {
15203
15665
  return input.endsWith(".md") ? input.slice(0, -".md".length) : input;
@@ -15233,7 +15695,7 @@ async function runShowTemplate(args2) {
15233
15695
  process.exit(1);
15234
15696
  return;
15235
15697
  }
15236
- process.stdout.write(readFileSync12(file, "utf-8"));
15698
+ process.stdout.write(readFileSync13(file, "utf-8"));
15237
15699
  }
15238
15700
  var init_show_template = __esm({
15239
15701
  "src/commands/show-template.ts"() {
@@ -15286,12 +15748,12 @@ var init_passthrough = __esm({
15286
15748
  });
15287
15749
 
15288
15750
  // src/lib/fileLock.ts
15289
- import { mkdirSync as mkdirSync5, readFileSync as readFileSync13, rmSync as rmSync3, writeFileSync as writeFileSync3 } from "fs";
15290
- import { dirname as dirname7 } from "path";
15751
+ import { mkdirSync as mkdirSync6, readFileSync as readFileSync14, rmSync as rmSync3, writeFileSync as writeFileSync4 } from "fs";
15752
+ import { dirname as dirname8 } from "path";
15291
15753
  import * as lockfile from "proper-lockfile";
15292
15754
  function readLockHolderPid(lockPath) {
15293
15755
  try {
15294
- const raw = readFileSync13(`${lockPath}.pid`, "utf-8").trim();
15756
+ const raw = readFileSync14(`${lockPath}.pid`, "utf-8").trim();
15295
15757
  const pid = Number.parseInt(raw, 10);
15296
15758
  if (!Number.isFinite(pid) || pid <= 0) return null;
15297
15759
  return pid;
@@ -15310,7 +15772,7 @@ function busyWaitSync(ms) {
15310
15772
  Atomics.wait(view, 0, 0, ms);
15311
15773
  }
15312
15774
  function withFileLockSync(lockPath, fn, opts = {}) {
15313
- mkdirSync5(dirname7(lockPath), { recursive: true });
15775
+ mkdirSync6(dirname8(lockPath), { recursive: true });
15314
15776
  const staleMs = opts.staleMs ?? 3e4;
15315
15777
  const blockMs = opts.retries === 0 ? 0 : opts.blockMs ?? 3e4;
15316
15778
  const pollIntervalMs = opts.pollIntervalMs ?? 100;
@@ -15327,7 +15789,7 @@ function withFileLockSync(lockPath, fn, opts = {}) {
15327
15789
  realpath: false
15328
15790
  });
15329
15791
  try {
15330
- writeFileSync3(`${lockPath}.pid`, String(process.pid), "utf-8");
15792
+ writeFileSync4(`${lockPath}.pid`, String(process.pid), "utf-8");
15331
15793
  } catch {
15332
15794
  }
15333
15795
  break;
@@ -15416,7 +15878,7 @@ __export(config_refresh_exports, {
15416
15878
  mergeRefresh: () => mergeRefresh,
15417
15879
  runConfigRefresh: () => runConfigRefresh
15418
15880
  });
15419
- import { existsSync as existsSync13, readFileSync as readFileSync14, rmSync as rmSync4 } from "fs";
15881
+ import { existsSync as existsSync13, readFileSync as readFileSync15, rmSync as rmSync4 } from "fs";
15420
15882
  import { resolve as resolve10 } from "path";
15421
15883
  import { parse as parseYaml5 } from "yaml";
15422
15884
  function flatten(obj, prefix3 = "") {
@@ -15555,7 +16017,7 @@ async function runConfigRefresh(opts = {}) {
15555
16017
  }
15556
16018
  let existing;
15557
16019
  try {
15558
- const content = readFileSync14(configPath, "utf-8");
16020
+ const content = readFileSync15(configPath, "utf-8");
15559
16021
  const parsed = parseYaml5(content);
15560
16022
  if (!parsed || typeof parsed !== "object") {
15561
16023
  throw new Error("config is not a YAML object");
@@ -15600,7 +16062,7 @@ async function runConfigRefresh(opts = {}) {
15600
16062
  }
15601
16063
  log("Config diff:\n");
15602
16064
  log(renderDiff(diff));
15603
- const { confirm } = await Promise.resolve().then(() => (init_dist2(), dist_exports));
16065
+ const { confirm } = await Promise.resolve().then(() => (init_dist7(), dist_exports));
15604
16066
  const apply = await confirm({ message: "Apply these changes to massu.config.yaml?" });
15605
16067
  if (apply !== true) {
15606
16068
  log("Aborted; no changes written.\n");
@@ -15953,8 +16415,8 @@ var init_paths = __esm({
15953
16415
  });
15954
16416
 
15955
16417
  // src/watch/state.ts
15956
- import { closeSync as closeSync3, existsSync as existsSync15, fsyncSync as fsyncSync3, mkdirSync as mkdirSync6, openSync as openSync3, readFileSync as readFileSync15, renameSync as renameSync4, rmSync as rmSync5, writeFileSync as writeFileSync4, writeSync as writeSync3 } from "fs";
15957
- import { dirname as dirname8, resolve as resolve12 } from "path";
16418
+ import { closeSync as closeSync3, existsSync as existsSync15, fsyncSync as fsyncSync3, mkdirSync as mkdirSync7, openSync as openSync3, readFileSync as readFileSync16, renameSync as renameSync5, rmSync as rmSync5, writeFileSync as writeFileSync5, writeSync as writeSync3 } from "fs";
16419
+ import { dirname as dirname9, resolve as resolve12 } from "path";
15958
16420
  function watchStatePath(projectRoot) {
15959
16421
  return resolve12(projectRoot, ".massu", "watch-state.json");
15960
16422
  }
@@ -15964,7 +16426,7 @@ function backupStatePath(projectRoot) {
15964
16426
  function readState(projectRoot) {
15965
16427
  const path = watchStatePath(projectRoot);
15966
16428
  if (!existsSync15(path)) return { ...DEFAULT_STATE };
15967
- const content = readFileSync15(path, "utf-8");
16429
+ const content = readFileSync16(path, "utf-8");
15968
16430
  let raw;
15969
16431
  try {
15970
16432
  raw = JSON.parse(content);
@@ -16006,14 +16468,14 @@ function readState(projectRoot) {
16006
16468
  }
16007
16469
  function archiveCorrupt(projectRoot, content) {
16008
16470
  const bak = backupStatePath(projectRoot);
16009
- mkdirSync6(dirname8(bak), { recursive: true });
16010
- writeFileSync4(bak, content, "utf-8");
16471
+ mkdirSync7(dirname9(bak), { recursive: true });
16472
+ writeFileSync5(bak, content, "utf-8");
16011
16473
  }
16012
16474
  function writeStateAtomic(projectRoot, state) {
16013
16475
  const path = watchStatePath(projectRoot);
16014
16476
  writeStateAtomicCounter = writeStateAtomicCounter + 1 >>> 0;
16015
16477
  const tmp = `${path}.${process.pid}.${writeStateAtomicCounter}.tmp`;
16016
- mkdirSync6(dirname8(path), { recursive: true });
16478
+ mkdirSync7(dirname9(path), { recursive: true });
16017
16479
  let renamed = false;
16018
16480
  try {
16019
16481
  const fd = openSync3(tmp, "w");
@@ -16024,7 +16486,7 @@ function writeStateAtomic(projectRoot, state) {
16024
16486
  } finally {
16025
16487
  closeSync3(fd);
16026
16488
  }
16027
- renameSync4(tmp, path);
16489
+ renameSync5(tmp, path);
16028
16490
  renamed = true;
16029
16491
  } finally {
16030
16492
  if (!renamed && existsSync15(tmp)) {
@@ -16307,8 +16769,8 @@ __export(watch_exports, {
16307
16769
  runWatch: () => runWatch
16308
16770
  });
16309
16771
  import { spawnSync as spawnSync3 } from "child_process";
16310
- import { basename as basename5, dirname as dirname9, resolve as resolve13 } from "path";
16311
- import { appendFileSync, existsSync as existsSync16, mkdirSync as mkdirSync7, readFileSync as readFileSync16 } from "fs";
16772
+ import { basename as basename5, dirname as dirname10, resolve as resolve13 } from "path";
16773
+ import { appendFileSync, existsSync as existsSync16, mkdirSync as mkdirSync8, readFileSync as readFileSync17 } from "fs";
16312
16774
  function parseFlags(args2) {
16313
16775
  const out = {
16314
16776
  foreground: false,
@@ -16553,7 +17015,7 @@ function refreshLogPath(projectRoot) {
16553
17015
  function appendRefreshLog(projectRoot, event) {
16554
17016
  const path = refreshLogPath(projectRoot);
16555
17017
  try {
16556
- mkdirSync7(dirname9(path), { recursive: true });
17018
+ mkdirSync8(dirname10(path), { recursive: true });
16557
17019
  appendFileSync(path, JSON.stringify(event) + "\n", "utf-8");
16558
17020
  } catch {
16559
17021
  }
@@ -16564,7 +17026,7 @@ function readRefreshLog(projectRoot, limit = 10, opts = {}) {
16564
17026
  const warn = opts.warn ?? ((s) => {
16565
17027
  process.stderr.write(s);
16566
17028
  });
16567
- const lines = readFileSync16(path, "utf-8").split("\n").filter(Boolean);
17029
+ const lines = readFileSync17(path, "utf-8").split("\n").filter(Boolean);
16568
17030
  const tail = lines.slice(-limit);
16569
17031
  const out = [];
16570
17032
  let corrupt = 0;
@@ -16635,28 +17097,28 @@ var init_refresh_log = __esm({
16635
17097
 
16636
17098
  // src/security/atomic-write.ts
16637
17099
  import {
16638
- chmodSync as chmodSync3,
17100
+ chmodSync as chmodSync4,
16639
17101
  closeSync as closeSync4,
16640
17102
  existsSync as existsSync17,
16641
17103
  fsyncSync as fsyncSync4,
16642
- mkdirSync as mkdirSync8,
17104
+ mkdirSync as mkdirSync9,
16643
17105
  openSync as openSync4,
16644
- renameSync as renameSync5,
17106
+ renameSync as renameSync6,
16645
17107
  rmSync as rmSync6,
16646
17108
  statSync as statSync9,
16647
17109
  writeSync as writeSync4
16648
17110
  } from "node:fs";
16649
- import { dirname as dirname10 } from "node:path";
17111
+ import { dirname as dirname11 } from "node:path";
16650
17112
  function atomicWrite(path, content, opts = {}) {
16651
17113
  const tmpPath = `${path}.tmp`;
16652
- const parentDir = dirname10(path);
17114
+ const parentDir = dirname11(path);
16653
17115
  try {
16654
17116
  if (!existsSync17(parentDir)) {
16655
17117
  const mkdirOpts = { recursive: true };
16656
17118
  if (opts.ensureParentDirMode !== void 0) {
16657
17119
  mkdirOpts.mode = opts.ensureParentDirMode;
16658
17120
  }
16659
- mkdirSync8(parentDir, mkdirOpts);
17121
+ mkdirSync9(parentDir, mkdirOpts);
16660
17122
  }
16661
17123
  const buf = typeof content === "string" ? Buffer.from(content, "utf-8") : content;
16662
17124
  const openMode = opts.mode ?? 420;
@@ -16668,9 +17130,9 @@ function atomicWrite(path, content, opts = {}) {
16668
17130
  closeSync4(fd);
16669
17131
  }
16670
17132
  if (opts.mode !== void 0) {
16671
- chmodSync3(tmpPath, opts.mode);
17133
+ chmodSync4(tmpPath, opts.mode);
16672
17134
  }
16673
- renameSync5(tmpPath, path);
17135
+ renameSync6(tmpPath, path);
16674
17136
  return { written: true };
16675
17137
  } catch (err) {
16676
17138
  if (existsSync17(tmpPath)) {
@@ -16753,10 +17215,10 @@ var init_registry_pubkey_generated = __esm({
16753
17215
  });
16754
17216
 
16755
17217
  // src/security/adapter-verifier.ts
16756
- import { createHash as createHash5 } from "node:crypto";
17218
+ import { createHash as createHash6 } from "node:crypto";
16757
17219
  import nacl from "tweetnacl";
16758
17220
  function sha256Hex(bytes) {
16759
- return createHash5("sha256").update(bytes).digest("hex");
17221
+ return createHash6("sha256").update(bytes).digest("hex");
16760
17222
  }
16761
17223
  function reviver(key, value) {
16762
17224
  if (key === "__proto__" || key === "constructor" || key === "prototype") {
@@ -17016,12 +17478,12 @@ var init_fetcher = __esm({
17016
17478
  });
17017
17479
 
17018
17480
  // src/security/manifest-cache.ts
17019
- import { existsSync as existsSync18, readFileSync as readFileSync17, statSync as statSync10 } from "node:fs";
17020
- import { homedir as homedir4 } from "node:os";
17481
+ import { existsSync as existsSync18, readFileSync as readFileSync18, statSync as statSync10 } from "node:fs";
17482
+ import { homedir as homedir5 } from "node:os";
17021
17483
  import { resolve as resolve14 } from "node:path";
17022
17484
  import { z as z4 } from "zod";
17023
17485
  function defaultCachePaths() {
17024
- const dir = resolve14(homedir4(), ".massu");
17486
+ const dir = resolve14(homedir5(), ".massu");
17025
17487
  return {
17026
17488
  cachePath: resolve14(dir, "adapter-manifest.json"),
17027
17489
  lockPath: resolve14(dir, ".adapter-manifest.lock")
@@ -17033,7 +17495,7 @@ function loadCachedManifest(paths = defaultCachePaths()) {
17033
17495
  }
17034
17496
  let raw;
17035
17497
  try {
17036
- const content = readFileSync17(paths.cachePath, "utf-8");
17498
+ const content = readFileSync18(paths.cachePath, "utf-8");
17037
17499
  raw = JSON.parse(content);
17038
17500
  } catch (err) {
17039
17501
  return {
@@ -17222,10 +17684,10 @@ var init_adapter_origin = __esm({
17222
17684
  });
17223
17685
 
17224
17686
  // src/security/local-fingerprint.ts
17225
- import { existsSync as existsSync19, readFileSync as readFileSync18, lstatSync as lstatSync5 } from "node:fs";
17226
- import { homedir as homedir5 } from "node:os";
17687
+ import { existsSync as existsSync19, readFileSync as readFileSync19, lstatSync as lstatSync6 } from "node:fs";
17688
+ import { homedir as homedir6 } from "node:os";
17227
17689
  import { resolve as resolve15, isAbsolute } from "node:path";
17228
- import { createHash as createHash6 } from "node:crypto";
17690
+ import { createHash as createHash7 } from "node:crypto";
17229
17691
  import { z as z5 } from "zod";
17230
17692
  function computeLocalFingerprint(localPaths, projectRoot) {
17231
17693
  const tuples = [];
@@ -17233,13 +17695,13 @@ function computeLocalFingerprint(localPaths, projectRoot) {
17233
17695
  const abs = isAbsolute(p19) ? p19 : resolve15(projectRoot, p19);
17234
17696
  let contentTag;
17235
17697
  try {
17236
- const lst = lstatSync5(abs);
17698
+ const lst = lstatSync6(abs);
17237
17699
  if (lst.isSymbolicLink()) {
17238
17700
  contentTag = "<symlink>";
17239
17701
  } else if (!lst.isFile()) {
17240
17702
  contentTag = "<not-a-file>";
17241
17703
  } else {
17242
- contentTag = createHash6("sha256").update(readFileSync18(abs)).digest("hex");
17704
+ contentTag = createHash7("sha256").update(readFileSync19(abs)).digest("hex");
17243
17705
  }
17244
17706
  } catch {
17245
17707
  contentTag = "<missing>";
@@ -17248,13 +17710,13 @@ function computeLocalFingerprint(localPaths, projectRoot) {
17248
17710
  }
17249
17711
  tuples.sort((a2, b2) => a2.path < b2.path ? -1 : a2.path > b2.path ? 1 : 0);
17250
17712
  const canonical = JSON.stringify(tuples);
17251
- return createHash6("sha256").update(canonical).digest("hex");
17713
+ return createHash7("sha256").update(canonical).digest("hex");
17252
17714
  }
17253
17715
  function readFingerprintSentinel(path = FINGERPRINT_PATH) {
17254
17716
  if (!existsSync19(path)) return null;
17255
17717
  let raw;
17256
17718
  try {
17257
- raw = JSON.parse(readFileSync18(path, "utf-8"));
17719
+ raw = JSON.parse(readFileSync19(path, "utf-8"));
17258
17720
  } catch {
17259
17721
  return null;
17260
17722
  }
@@ -17302,7 +17764,7 @@ var init_local_fingerprint = __esm({
17302
17764
  "use strict";
17303
17765
  init_atomic_write();
17304
17766
  init_manifest_schema();
17305
- FINGERPRINT_PATH = resolve15(homedir5(), ".massu", "adapters-local-fingerprint.json");
17767
+ FINGERPRINT_PATH = resolve15(homedir6(), ".massu", "adapters-local-fingerprint.json");
17306
17768
  FingerprintSentinelSchema = z5.object({
17307
17769
  fingerprint: z5.string().regex(/^[0-9a-f]{64}$/),
17308
17770
  source: z5.enum(["cli", "cli-resync"]),
@@ -17318,11 +17780,11 @@ var init_local_fingerprint = __esm({
17318
17780
  });
17319
17781
 
17320
17782
  // src/security/install-tracking.ts
17321
- import { readFileSync as readFileSync19, readdirSync as readdirSync12, lstatSync as lstatSync6, existsSync as existsSync20 } from "node:fs";
17322
- import { join as join10, relative as relative5, sep } from "node:path";
17323
- import { homedir as homedir6 } from "node:os";
17783
+ import { readFileSync as readFileSync20, readdirSync as readdirSync13, lstatSync as lstatSync7, existsSync as existsSync20 } from "node:fs";
17784
+ import { join as join11, relative as relative5, sep } from "node:path";
17785
+ import { homedir as homedir7 } from "node:os";
17324
17786
  import { resolve as resolve16 } from "node:path";
17325
- import { createHash as createHash7 } from "node:crypto";
17787
+ import { createHash as createHash8 } from "node:crypto";
17326
17788
  import { z as z6 } from "zod";
17327
17789
  function containsHiddenDirs(packageDir) {
17328
17790
  for (const hidden of EXCLUDED_DIR_NAMES) {
@@ -17338,15 +17800,15 @@ function sha256OfDir(dir, opts = {}) {
17338
17800
  function walk(currentDir) {
17339
17801
  let entries;
17340
17802
  try {
17341
- entries = readdirSync12(currentDir);
17803
+ entries = readdirSync13(currentDir);
17342
17804
  } catch {
17343
17805
  return;
17344
17806
  }
17345
17807
  for (const entry of entries.sort()) {
17346
- const absPath = join10(currentDir, entry);
17808
+ const absPath = join11(currentDir, entry);
17347
17809
  let lst;
17348
17810
  try {
17349
- lst = lstatSync6(absPath);
17811
+ lst = lstatSync7(absPath);
17350
17812
  } catch {
17351
17813
  continue;
17352
17814
  }
@@ -17370,9 +17832,9 @@ function sha256OfDir(dir, opts = {}) {
17370
17832
  }
17371
17833
  walk(dir);
17372
17834
  files.sort((a2, b2) => a2.relativePath < b2.relativePath ? -1 : a2.relativePath > b2.relativePath ? 1 : 0);
17373
- const top = createHash7("sha256");
17835
+ const top = createHash8("sha256");
17374
17836
  for (const f2 of files) {
17375
- const fileHash = createHash7("sha256").update(readFileSync19(f2.absPath)).digest("hex");
17837
+ const fileHash = createHash8("sha256").update(readFileSync20(f2.absPath)).digest("hex");
17376
17838
  top.update(f2.relativePath, "utf-8");
17377
17839
  top.update("\0", "utf-8");
17378
17840
  top.update(fileHash, "utf-8");
@@ -17384,7 +17846,7 @@ function readInstalledManifest(path = INSTALLED_MANIFEST_PATH) {
17384
17846
  if (!existsSync20(path)) return {};
17385
17847
  let raw;
17386
17848
  try {
17387
- raw = JSON.parse(readFileSync19(path, "utf-8"));
17849
+ raw = JSON.parse(readFileSync20(path, "utf-8"));
17388
17850
  } catch {
17389
17851
  return {};
17390
17852
  }
@@ -17448,7 +17910,7 @@ var init_install_tracking = __esm({
17448
17910
  "src/security/install-tracking.ts"() {
17449
17911
  "use strict";
17450
17912
  init_atomic_write();
17451
- INSTALLED_MANIFEST_PATH = resolve16(homedir6(), ".massu", "adapter-manifest-installed.json");
17913
+ INSTALLED_MANIFEST_PATH = resolve16(homedir7(), ".massu", "adapter-manifest-installed.json");
17452
17914
  DEFAULT_MAX_FILE_BYTES = 64 * 1024 * 1024;
17453
17915
  EXCLUDED_DIR_NAMES = /* @__PURE__ */ new Set([".git", "node_modules", ".cache", ".tmp"]);
17454
17916
  InstallEntrySchema = z6.object({
@@ -17471,7 +17933,7 @@ var init_install_tracking = __esm({
17471
17933
  });
17472
17934
 
17473
17935
  // src/detect/adapters/discover.ts
17474
- import { existsSync as existsSync21, readdirSync as readdirSync13, readFileSync as readFileSync20, lstatSync as lstatSync7 } from "node:fs";
17936
+ import { existsSync as existsSync21, readdirSync as readdirSync14, readFileSync as readFileSync21, lstatSync as lstatSync8 } from "node:fs";
17475
17937
  import { resolve as resolve17, isAbsolute as isAbsolute2 } from "node:path";
17476
17938
  import { z as z7 } from "zod";
17477
17939
  function walkNodeModules(projectRoot, warnings) {
@@ -17482,7 +17944,7 @@ function walkNodeModules(projectRoot, warnings) {
17482
17944
  const candidates = [];
17483
17945
  let topLevelEntries;
17484
17946
  try {
17485
- topLevelEntries = readdirSync13(nodeModulesDir);
17947
+ topLevelEntries = readdirSync14(nodeModulesDir);
17486
17948
  } catch (err) {
17487
17949
  warnings.push(`failed to read node_modules: ${err instanceof Error ? err.message : String(err)}`);
17488
17950
  return [];
@@ -17492,7 +17954,7 @@ function walkNodeModules(projectRoot, warnings) {
17492
17954
  const entryPath = resolve17(nodeModulesDir, entry);
17493
17955
  let entryStat;
17494
17956
  try {
17495
- entryStat = lstatSync7(entryPath);
17957
+ entryStat = lstatSync8(entryPath);
17496
17958
  } catch {
17497
17959
  continue;
17498
17960
  }
@@ -17506,7 +17968,7 @@ function walkNodeModules(projectRoot, warnings) {
17506
17968
  if (entry.startsWith("@")) {
17507
17969
  let scopedEntries;
17508
17970
  try {
17509
- scopedEntries = readdirSync13(entryPath);
17971
+ scopedEntries = readdirSync14(entryPath);
17510
17972
  } catch {
17511
17973
  continue;
17512
17974
  }
@@ -17514,7 +17976,7 @@ function walkNodeModules(projectRoot, warnings) {
17514
17976
  const subPath = resolve17(entryPath, sub);
17515
17977
  let subStat;
17516
17978
  try {
17517
- subStat = lstatSync7(subPath);
17979
+ subStat = lstatSync8(subPath);
17518
17980
  } catch {
17519
17981
  continue;
17520
17982
  }
@@ -17534,7 +17996,7 @@ function tryReadAdapterPackage(packageDir, warnings) {
17534
17996
  if (!existsSync21(pkgJsonPath)) return null;
17535
17997
  let raw;
17536
17998
  try {
17537
- raw = JSON.parse(readFileSync20(pkgJsonPath, "utf-8"));
17999
+ raw = JSON.parse(readFileSync21(pkgJsonPath, "utf-8"));
17538
18000
  } catch (err) {
17539
18001
  warnings.push(
17540
18002
  `skipping ${packageDir}: package.json parse failed (${err instanceof Error ? err.message : String(err)})`
@@ -17750,7 +18212,7 @@ __export(adapters_exports, {
17750
18212
  runAdaptersResyncLocalFingerprint: () => runAdaptersResyncLocalFingerprint,
17751
18213
  runAdaptersSearch: () => runAdaptersSearch
17752
18214
  });
17753
- import { existsSync as existsSync22, readFileSync as readFileSync21 } from "node:fs";
18215
+ import { existsSync as existsSync22, readFileSync as readFileSync22 } from "node:fs";
17754
18216
  import { resolve as resolve18 } from "node:path";
17755
18217
  import { parseDocument } from "yaml";
17756
18218
  async function handleAdaptersSubcommand(args2) {
@@ -18028,7 +18490,7 @@ function mutateLocalArray(mutator, command) {
18028
18490
  }
18029
18491
  let yamlText;
18030
18492
  try {
18031
- yamlText = readFileSync21(yamlPath, "utf-8");
18493
+ yamlText = readFileSync22(yamlPath, "utf-8");
18032
18494
  } catch (err) {
18033
18495
  process.stderr.write(`${command}: failed to read ${yamlPath}: ${err instanceof Error ? err.message : String(err)}
18034
18496
  `);
@@ -18134,7 +18596,7 @@ async function runAdaptersInstall(args2) {
18134
18596
  }
18135
18597
  let pkgJson;
18136
18598
  try {
18137
- pkgJson = JSON.parse(readFileSync21(pkgJsonPath, "utf-8"));
18599
+ pkgJson = JSON.parse(readFileSync22(pkgJsonPath, "utf-8"));
18138
18600
  } catch (err) {
18139
18601
  process.stderr.write(`install: ${packageName} has malformed package.json: ${err instanceof Error ? err.message : String(err)}
18140
18602
  `);
@@ -18341,8 +18803,8 @@ var init_adapters2 = __esm({
18341
18803
 
18342
18804
  // src/db.ts
18343
18805
  import Database2 from "better-sqlite3";
18344
- import { dirname as dirname11, join as join11 } from "path";
18345
- import { existsSync as existsSync23, mkdirSync as mkdirSync9, readdirSync as readdirSync14, statSync as statSync11 } from "fs";
18806
+ import { dirname as dirname12, join as join12 } from "path";
18807
+ import { existsSync as existsSync23, mkdirSync as mkdirSync10, readdirSync as readdirSync15, statSync as statSync11 } from "fs";
18346
18808
  function getCodeGraphDb() {
18347
18809
  const dbPath = getResolvedPaths().codegraphDbPath;
18348
18810
  if (!existsSync23(dbPath)) {
@@ -18354,9 +18816,9 @@ function getCodeGraphDb() {
18354
18816
  }
18355
18817
  function getDataDb() {
18356
18818
  const dbPath = getResolvedPaths().dataDbPath;
18357
- const dir = dirname11(dbPath);
18819
+ const dir = dirname12(dbPath);
18358
18820
  if (!existsSync23(dir)) {
18359
- mkdirSync9(dir, { recursive: true });
18821
+ mkdirSync10(dir, { recursive: true });
18360
18822
  }
18361
18823
  const db = new Database2(dbPath);
18362
18824
  db.pragma("journal_mode = WAL");
@@ -18626,9 +19088,9 @@ function isPythonDataStale(dataDb2, pythonRoot) {
18626
19088
  const lastBuildTime = new Date(lastBuild.value).getTime();
18627
19089
  function checkDir(dir) {
18628
19090
  try {
18629
- const entries = readdirSync14(dir, { withFileTypes: true });
19091
+ const entries = readdirSync15(dir, { withFileTypes: true });
18630
19092
  for (const entry of entries) {
18631
- const fullPath = join11(dir, entry.name);
19093
+ const fullPath = join12(dir, entry.name);
18632
19094
  if (entry.isDirectory()) {
18633
19095
  if (["__pycache__", ".venv", "venv", "node_modules", ".mypy_cache", ".pytest_cache"].includes(entry.name)) continue;
18634
19096
  if (checkDir(fullPath)) return true;
@@ -18729,8 +19191,8 @@ var init_rules = __esm({
18729
19191
  });
18730
19192
 
18731
19193
  // src/import-resolver.ts
18732
- import { readFileSync as readFileSync22, existsSync as existsSync24, statSync as statSync12 } from "fs";
18733
- import { resolve as resolve20, dirname as dirname12, join as join12 } from "path";
19194
+ import { readFileSync as readFileSync23, existsSync as existsSync24, statSync as statSync12 } from "fs";
19195
+ import { resolve as resolve20, dirname as dirname13, join as join13 } from "path";
18734
19196
  function parseImports(source) {
18735
19197
  const imports = [];
18736
19198
  const lines = source.split("\n");
@@ -18788,7 +19250,7 @@ function resolveImportPath(specifier, fromFile) {
18788
19250
  const paths = getResolvedPaths();
18789
19251
  basePath = resolve20(paths.pathAlias["@"] ?? paths.srcDir, specifier.slice(2));
18790
19252
  } else {
18791
- basePath = resolve20(dirname12(fromFile), specifier);
19253
+ basePath = resolve20(dirname13(fromFile), specifier);
18792
19254
  }
18793
19255
  if (existsSync24(basePath) && !isDirectory(basePath)) {
18794
19256
  return toRelative(basePath);
@@ -18801,7 +19263,7 @@ function resolveImportPath(specifier, fromFile) {
18801
19263
  }
18802
19264
  }
18803
19265
  for (const indexFile of resolvedPaths.indexFiles) {
18804
- const indexPath = join12(basePath, indexFile);
19266
+ const indexPath = join13(basePath, indexFile);
18805
19267
  if (existsSync24(indexPath)) {
18806
19268
  return toRelative(indexPath);
18807
19269
  }
@@ -18842,7 +19304,7 @@ function buildImportIndex(dataDb2, codegraphDb2) {
18842
19304
  if (!existsSync24(absPath)) continue;
18843
19305
  let source;
18844
19306
  try {
18845
- source = readFileSync22(absPath, "utf-8");
19307
+ source = readFileSync23(absPath, "utf-8");
18846
19308
  } catch {
18847
19309
  continue;
18848
19310
  }
@@ -18878,15 +19340,15 @@ var init_import_resolver = __esm({
18878
19340
  });
18879
19341
 
18880
19342
  // src/trpc-index.ts
18881
- import { readFileSync as readFileSync23, existsSync as existsSync25, readdirSync as readdirSync15 } from "fs";
18882
- import { resolve as resolve21, join as join13 } from "path";
19343
+ import { readFileSync as readFileSync24, existsSync as existsSync25, readdirSync as readdirSync16 } from "fs";
19344
+ import { resolve as resolve21, join as join14 } from "path";
18883
19345
  function parseRootRouter() {
18884
19346
  const paths = getResolvedPaths();
18885
19347
  const rootPath = paths.rootRouterPath;
18886
19348
  if (!existsSync25(rootPath)) {
18887
19349
  throw new Error(`Root router not found at ${rootPath}`);
18888
19350
  }
18889
- const source = readFileSync23(rootPath, "utf-8");
19351
+ const source = readFileSync24(rootPath, "utf-8");
18890
19352
  const mappings = [];
18891
19353
  const importMap = /* @__PURE__ */ new Map();
18892
19354
  const importRegex = /import\s+\{[^}]*?(\w+Router)[^}]*\}\s+from\s+['"]\.\/routers\/([^'"]+)['"]/g;
@@ -18902,7 +19364,7 @@ function parseRootRouter() {
18902
19364
  filePath = routersRelPath + "/" + filePath + ext;
18903
19365
  break;
18904
19366
  }
18905
- const indexCandidate = join13(fullPath, "index.ts");
19367
+ const indexCandidate = join14(fullPath, "index.ts");
18906
19368
  if (existsSync25(indexCandidate)) {
18907
19369
  filePath = routersRelPath + "/" + filePath + "/index.ts";
18908
19370
  break;
@@ -18924,7 +19386,7 @@ function parseRootRouter() {
18924
19386
  function extractProcedures(routerFilePath) {
18925
19387
  const absPath = resolve21(getProjectRoot(), routerFilePath);
18926
19388
  if (!existsSync25(absPath)) return [];
18927
- const source = readFileSync23(absPath, "utf-8");
19389
+ const source = readFileSync24(absPath, "utf-8");
18928
19390
  const procedures = [];
18929
19391
  const seen = /* @__PURE__ */ new Set();
18930
19392
  const procRegex = /(\w+)\s*:\s*(protected|public)Procedure/g;
@@ -18959,15 +19421,15 @@ function findUICallSites(routerKey, procedureName) {
18959
19421
  return callSites;
18960
19422
  }
18961
19423
  function searchDirectory(dir, pattern, results) {
18962
- const entries = readdirSync15(dir, { withFileTypes: true });
19424
+ const entries = readdirSync16(dir, { withFileTypes: true });
18963
19425
  for (const entry of entries) {
18964
- const fullPath = join13(dir, entry.name);
19426
+ const fullPath = join14(dir, entry.name);
18965
19427
  if (entry.isDirectory()) {
18966
19428
  if (entry.name === "node_modules" || entry.name === ".next") continue;
18967
19429
  searchDirectory(fullPath, pattern, results);
18968
19430
  } else if (entry.name.endsWith(".ts") || entry.name.endsWith(".tsx")) {
18969
19431
  try {
18970
- const source = readFileSync23(fullPath, "utf-8");
19432
+ const source = readFileSync24(fullPath, "utf-8");
18971
19433
  const lines = source.split("\n");
18972
19434
  for (let i = 0; i < lines.length; i++) {
18973
19435
  if (lines[i].includes(pattern)) {
@@ -19030,7 +19492,7 @@ var init_trpc_index = __esm({
19030
19492
  });
19031
19493
 
19032
19494
  // src/page-deps.ts
19033
- import { readFileSync as readFileSync24, existsSync as existsSync26 } from "fs";
19495
+ import { readFileSync as readFileSync25, existsSync as existsSync26 } from "fs";
19034
19496
  import { resolve as resolve22 } from "path";
19035
19497
  function deriveRoute(pageFile) {
19036
19498
  let route = pageFile.replace(/^src\/app/, "").replace(/\/page\.tsx?$/, "").replace(/\/page\.jsx?$/, "");
@@ -19072,7 +19534,7 @@ function findRouterCalls(files) {
19072
19534
  const absPath = ensureWithinRoot(resolve22(projectRoot, file), projectRoot);
19073
19535
  if (!existsSync26(absPath)) continue;
19074
19536
  try {
19075
- const source = readFileSync24(absPath, "utf-8");
19537
+ const source = readFileSync25(absPath, "utf-8");
19076
19538
  const apiCallRegex = /api\.(\w+)\.\w+/g;
19077
19539
  let match;
19078
19540
  while ((match = apiCallRegex.exec(source)) !== null) {
@@ -19093,7 +19555,7 @@ function findTablesFromRouters(routerNames, dataDb2) {
19093
19555
  const absPath = ensureWithinRoot(resolve22(getProjectRoot(), proc.router_file), getProjectRoot());
19094
19556
  if (!existsSync26(absPath)) continue;
19095
19557
  try {
19096
- const source = readFileSync24(absPath, "utf-8");
19558
+ const source = readFileSync25(absPath, "utf-8");
19097
19559
  const dbPattern = getConfig().dbAccessPattern ?? "ctx.db.{table}";
19098
19560
  const regexStr = dbPattern.replace(/[.*+?^${}()|[\]\\]/g, "\\$&").replace("\\{table\\}", "(\\w+)");
19099
19561
  const tableRegex = new RegExp(regexStr + "\\.", "g");
@@ -19362,14 +19824,14 @@ var init_domains = __esm({
19362
19824
  });
19363
19825
 
19364
19826
  // src/schema-mapper.ts
19365
- import { readFileSync as readFileSync25, existsSync as existsSync27, readdirSync as readdirSync16 } from "fs";
19366
- import { join as join14 } from "path";
19827
+ import { readFileSync as readFileSync26, existsSync as existsSync27, readdirSync as readdirSync17 } from "fs";
19828
+ import { join as join15 } from "path";
19367
19829
  function parsePrismaSchema() {
19368
19830
  const schemaPath = getResolvedPaths().prismaSchemaPath;
19369
19831
  if (!existsSync27(schemaPath)) {
19370
19832
  throw new Error(`Prisma schema not found at ${schemaPath}`);
19371
19833
  }
19372
- const source = readFileSync25(schemaPath, "utf-8");
19834
+ const source = readFileSync26(schemaPath, "utf-8");
19373
19835
  const models = [];
19374
19836
  const sourceLines = source.split("\n");
19375
19837
  let i = 0;
@@ -19432,9 +19894,9 @@ function findColumnUsageInRouters(tableName) {
19432
19894
  return usage;
19433
19895
  }
19434
19896
  function scanDirectory(dir, tableName, usage) {
19435
- const entries = readdirSync16(dir, { withFileTypes: true });
19897
+ const entries = readdirSync17(dir, { withFileTypes: true });
19436
19898
  for (const entry of entries) {
19437
- const fullPath = join14(dir, entry.name);
19899
+ const fullPath = join15(dir, entry.name);
19438
19900
  if (entry.isDirectory()) {
19439
19901
  scanDirectory(fullPath, tableName, usage);
19440
19902
  } else if (entry.name.endsWith(".ts")) {
@@ -19444,7 +19906,7 @@ function scanDirectory(dir, tableName, usage) {
19444
19906
  }
19445
19907
  function scanFile(absPath, tableName, usage) {
19446
19908
  try {
19447
- const source = readFileSync25(absPath, "utf-8");
19909
+ const source = readFileSync26(absPath, "utf-8");
19448
19910
  if (!source.includes(tableName)) return;
19449
19911
  const relPath = absPath.slice(getProjectRoot().length + 1);
19450
19912
  const lines = source.split("\n");
@@ -19490,14 +19952,14 @@ function detectMismatches(models) {
19490
19952
  function findFilesUsingColumn(dir, column, tableName) {
19491
19953
  const result = [];
19492
19954
  if (!existsSync27(dir)) return result;
19493
- const entries = readdirSync16(dir, { withFileTypes: true });
19955
+ const entries = readdirSync17(dir, { withFileTypes: true });
19494
19956
  for (const entry of entries) {
19495
- const fullPath = join14(dir, entry.name);
19957
+ const fullPath = join15(dir, entry.name);
19496
19958
  if (entry.isDirectory()) {
19497
19959
  result.push(...findFilesUsingColumn(fullPath, column, tableName));
19498
19960
  } else if (entry.name.endsWith(".ts")) {
19499
19961
  try {
19500
- const source = readFileSync25(fullPath, "utf-8");
19962
+ const source = readFileSync26(fullPath, "utf-8");
19501
19963
  if (source.includes(tableName) && source.includes(column)) {
19502
19964
  result.push(fullPath.slice(getProjectRoot().length + 1));
19503
19965
  }
@@ -19642,32 +20104,32 @@ var init_import_parser = __esm({
19642
20104
  });
19643
20105
 
19644
20106
  // src/python/import-resolver.ts
19645
- import { readFileSync as readFileSync26, existsSync as existsSync28, readdirSync as readdirSync17 } from "fs";
19646
- import { resolve as resolve24, join as join15, relative as relative6, dirname as dirname13 } from "path";
20107
+ import { readFileSync as readFileSync27, existsSync as existsSync28, readdirSync as readdirSync18 } from "fs";
20108
+ import { resolve as resolve24, join as join16, relative as relative6, dirname as dirname14 } from "path";
19647
20109
  function resolvePythonModulePath(module, fromFile, pythonRoot, level) {
19648
20110
  const projectRoot = getProjectRoot();
19649
20111
  if (level > 0) {
19650
- let baseDir = dirname13(resolve24(projectRoot, fromFile));
20112
+ let baseDir = dirname14(resolve24(projectRoot, fromFile));
19651
20113
  for (let i = 1; i < level; i++) {
19652
- baseDir = dirname13(baseDir);
20114
+ baseDir = dirname14(baseDir);
19653
20115
  }
19654
20116
  const modulePart = module.replace(/^\.+/, "");
19655
20117
  if (modulePart) {
19656
20118
  const parts2 = modulePart.split(".");
19657
- return tryResolvePythonPath(join15(baseDir, ...parts2), projectRoot);
20119
+ return tryResolvePythonPath(join16(baseDir, ...parts2), projectRoot);
19658
20120
  }
19659
20121
  return tryResolvePythonPath(baseDir, projectRoot);
19660
20122
  }
19661
20123
  const parts = module.split(".");
19662
- const candidate = join15(resolve24(projectRoot, pythonRoot), ...parts);
20124
+ const candidate = join16(resolve24(projectRoot, pythonRoot), ...parts);
19663
20125
  return tryResolvePythonPath(candidate, projectRoot);
19664
20126
  }
19665
20127
  function tryResolvePythonPath(basePath, projectRoot) {
19666
20128
  if (existsSync28(basePath + ".py")) {
19667
20129
  return relative6(projectRoot, basePath + ".py");
19668
20130
  }
19669
- if (existsSync28(join15(basePath, "__init__.py"))) {
19670
- return relative6(projectRoot, join15(basePath, "__init__.py"));
20131
+ if (existsSync28(join16(basePath, "__init__.py"))) {
20132
+ return relative6(projectRoot, join16(basePath, "__init__.py"));
19671
20133
  }
19672
20134
  if (basePath.endsWith(".py") && existsSync28(basePath)) {
19673
20135
  return relative6(projectRoot, basePath);
@@ -19677,13 +20139,13 @@ function tryResolvePythonPath(basePath, projectRoot) {
19677
20139
  function walkPythonFiles(dir, excludeDirs) {
19678
20140
  const files = [];
19679
20141
  try {
19680
- const entries = readdirSync17(dir, { withFileTypes: true });
20142
+ const entries = readdirSync18(dir, { withFileTypes: true });
19681
20143
  for (const entry of entries) {
19682
20144
  if (entry.isDirectory()) {
19683
20145
  if (excludeDirs.includes(entry.name)) continue;
19684
- files.push(...walkPythonFiles(join15(dir, entry.name), excludeDirs));
20146
+ files.push(...walkPythonFiles(join16(dir, entry.name), excludeDirs));
19685
20147
  } else if (entry.name.endsWith(".py")) {
19686
- files.push(join15(dir, entry.name));
20148
+ files.push(join16(dir, entry.name));
19687
20149
  }
19688
20150
  }
19689
20151
  } catch {
@@ -19709,7 +20171,7 @@ function buildPythonImportIndex(dataDb2, pythonRoot, excludeDirs = ["__pycache__
19709
20171
  const relFile = relative6(projectRoot, absFile);
19710
20172
  let source;
19711
20173
  try {
19712
- source = readFileSync26(absFile, "utf-8");
20174
+ source = readFileSync27(absFile, "utf-8");
19713
20175
  } catch {
19714
20176
  continue;
19715
20177
  }
@@ -19975,18 +20437,18 @@ var init_route_parser = __esm({
19975
20437
  });
19976
20438
 
19977
20439
  // src/python/route-indexer.ts
19978
- import { readFileSync as readFileSync27, readdirSync as readdirSync18 } from "fs";
19979
- import { join as join16, relative as relative7 } from "path";
20440
+ import { readFileSync as readFileSync28, readdirSync as readdirSync19 } from "fs";
20441
+ import { join as join17, relative as relative7 } from "path";
19980
20442
  function walkPyFiles(dir, excludeDirs) {
19981
20443
  const files = [];
19982
20444
  try {
19983
- const entries = readdirSync18(dir, { withFileTypes: true });
20445
+ const entries = readdirSync19(dir, { withFileTypes: true });
19984
20446
  for (const entry of entries) {
19985
20447
  if (entry.isDirectory()) {
19986
20448
  if (excludeDirs.includes(entry.name)) continue;
19987
- files.push(...walkPyFiles(join16(dir, entry.name), excludeDirs));
20449
+ files.push(...walkPyFiles(join17(dir, entry.name), excludeDirs));
19988
20450
  } else if (entry.name.endsWith(".py")) {
19989
- files.push(join16(dir, entry.name));
20451
+ files.push(join17(dir, entry.name));
19990
20452
  }
19991
20453
  }
19992
20454
  } catch {
@@ -19995,7 +20457,7 @@ function walkPyFiles(dir, excludeDirs) {
19995
20457
  }
19996
20458
  function buildPythonRouteIndex(dataDb2, pythonRoot, excludeDirs = ["__pycache__", ".venv", "venv", ".mypy_cache", ".pytest_cache"]) {
19997
20459
  const projectRoot = getProjectRoot();
19998
- const absRoot = join16(projectRoot, pythonRoot);
20460
+ const absRoot = join17(projectRoot, pythonRoot);
19999
20461
  dataDb2.exec("DELETE FROM massu_py_routes");
20000
20462
  dataDb2.exec("DELETE FROM massu_py_route_callers");
20001
20463
  const insertStmt = dataDb2.prepare(
@@ -20008,7 +20470,7 @@ function buildPythonRouteIndex(dataDb2, pythonRoot, excludeDirs = ["__pycache__"
20008
20470
  const relFile = relative7(projectRoot, absFile);
20009
20471
  let source;
20010
20472
  try {
20011
- source = readFileSync27(absFile, "utf-8");
20473
+ source = readFileSync28(absFile, "utf-8");
20012
20474
  } catch {
20013
20475
  continue;
20014
20476
  }
@@ -20219,18 +20681,18 @@ var init_model_parser = __esm({
20219
20681
  });
20220
20682
 
20221
20683
  // src/python/model-indexer.ts
20222
- import { readFileSync as readFileSync28, readdirSync as readdirSync19 } from "fs";
20223
- import { join as join17, relative as relative8 } from "path";
20684
+ import { readFileSync as readFileSync29, readdirSync as readdirSync20 } from "fs";
20685
+ import { join as join18, relative as relative8 } from "path";
20224
20686
  function walkPyFiles2(dir, excludeDirs) {
20225
20687
  const files = [];
20226
20688
  try {
20227
- const entries = readdirSync19(dir, { withFileTypes: true });
20689
+ const entries = readdirSync20(dir, { withFileTypes: true });
20228
20690
  for (const entry of entries) {
20229
20691
  if (entry.isDirectory()) {
20230
20692
  if (excludeDirs.includes(entry.name)) continue;
20231
- files.push(...walkPyFiles2(join17(dir, entry.name), excludeDirs));
20693
+ files.push(...walkPyFiles2(join18(dir, entry.name), excludeDirs));
20232
20694
  } else if (entry.name.endsWith(".py")) {
20233
- files.push(join17(dir, entry.name));
20695
+ files.push(join18(dir, entry.name));
20234
20696
  }
20235
20697
  }
20236
20698
  } catch {
@@ -20239,7 +20701,7 @@ function walkPyFiles2(dir, excludeDirs) {
20239
20701
  }
20240
20702
  function buildPythonModelIndex(dataDb2, pythonRoot, excludeDirs = ["__pycache__", ".venv", "venv", ".mypy_cache", ".pytest_cache"]) {
20241
20703
  const projectRoot = getProjectRoot();
20242
- const absRoot = join17(projectRoot, pythonRoot);
20704
+ const absRoot = join18(projectRoot, pythonRoot);
20243
20705
  dataDb2.exec("DELETE FROM massu_py_models");
20244
20706
  dataDb2.exec("DELETE FROM massu_py_fk_edges");
20245
20707
  const insertModel = dataDb2.prepare(
@@ -20255,7 +20717,7 @@ function buildPythonModelIndex(dataDb2, pythonRoot, excludeDirs = ["__pycache__"
20255
20717
  const relFile = relative8(projectRoot, absFile);
20256
20718
  let source;
20257
20719
  try {
20258
- source = readFileSync28(absFile, "utf-8");
20720
+ source = readFileSync29(absFile, "utf-8");
20259
20721
  } catch {
20260
20722
  continue;
20261
20723
  }
@@ -20515,19 +20977,19 @@ var init_migration_parser = __esm({
20515
20977
  });
20516
20978
 
20517
20979
  // src/python/migration-indexer.ts
20518
- import { readFileSync as readFileSync29, readdirSync as readdirSync20 } from "fs";
20519
- import { join as join18, relative as relative9 } from "path";
20980
+ import { readFileSync as readFileSync30, readdirSync as readdirSync21 } from "fs";
20981
+ import { join as join19, relative as relative9 } from "path";
20520
20982
  function buildPythonMigrationIndex(dataDb2, alembicDir) {
20521
20983
  const projectRoot = getProjectRoot();
20522
- const absDir = join18(projectRoot, alembicDir);
20984
+ const absDir = join19(projectRoot, alembicDir);
20523
20985
  dataDb2.exec("DELETE FROM massu_py_migrations");
20524
- const versionsDir = join18(absDir, "versions");
20986
+ const versionsDir = join19(absDir, "versions");
20525
20987
  let files = [];
20526
20988
  try {
20527
- files = readdirSync20(versionsDir).filter((f2) => f2.endsWith(".py")).map((f2) => join18(versionsDir, f2));
20989
+ files = readdirSync21(versionsDir).filter((f2) => f2.endsWith(".py")).map((f2) => join19(versionsDir, f2));
20528
20990
  } catch {
20529
20991
  try {
20530
- files = readdirSync20(absDir).filter((f2) => f2.endsWith(".py") && f2 !== "env.py").map((f2) => join18(absDir, f2));
20992
+ files = readdirSync21(absDir).filter((f2) => f2.endsWith(".py") && f2 !== "env.py").map((f2) => join19(absDir, f2));
20531
20993
  } catch {
20532
20994
  }
20533
20995
  }
@@ -20541,7 +21003,7 @@ function buildPythonMigrationIndex(dataDb2, alembicDir) {
20541
21003
  for (const absFile of files) {
20542
21004
  let source;
20543
21005
  try {
20544
- source = readFileSync29(absFile, "utf-8");
21006
+ source = readFileSync30(absFile, "utf-8");
20545
21007
  } catch {
20546
21008
  continue;
20547
21009
  }
@@ -20575,12 +21037,12 @@ var init_migration_indexer = __esm({
20575
21037
  });
20576
21038
 
20577
21039
  // src/python/coupling-detector.ts
20578
- import { readFileSync as readFileSync30, readdirSync as readdirSync21 } from "fs";
20579
- import { join as join19, relative as relative10 } from "path";
21040
+ import { readFileSync as readFileSync31, readdirSync as readdirSync22 } from "fs";
21041
+ import { join as join20, relative as relative10 } from "path";
20580
21042
  function buildPythonCouplingIndex(dataDb2) {
20581
21043
  const projectRoot = getProjectRoot();
20582
21044
  const config = getConfig();
20583
- const srcDir = join19(projectRoot, config.paths.source);
21045
+ const srcDir = join20(projectRoot, config.paths.source);
20584
21046
  const routes = dataDb2.prepare("SELECT id, method, path FROM massu_py_routes").all();
20585
21047
  if (routes.length === 0) return 0;
20586
21048
  dataDb2.exec("DELETE FROM massu_py_route_callers");
@@ -20612,7 +21074,7 @@ function buildPythonCouplingIndex(dataDb2) {
20612
21074
  const relFile = relative10(projectRoot, absFile);
20613
21075
  let source;
20614
21076
  try {
20615
- source = readFileSync30(absFile, "utf-8");
21077
+ source = readFileSync31(absFile, "utf-8");
20616
21078
  } catch {
20617
21079
  continue;
20618
21080
  }
@@ -20640,13 +21102,13 @@ function walkFrontendFiles(dir) {
20640
21102
  const files = [];
20641
21103
  const exclude = ["node_modules", ".next", "dist", ".git", "__pycache__", ".venv", "venv"];
20642
21104
  try {
20643
- const entries = readdirSync21(dir, { withFileTypes: true });
21105
+ const entries = readdirSync22(dir, { withFileTypes: true });
20644
21106
  for (const entry of entries) {
20645
21107
  if (entry.isDirectory()) {
20646
21108
  if (exclude.includes(entry.name)) continue;
20647
- files.push(...walkFrontendFiles(join19(dir, entry.name)));
21109
+ files.push(...walkFrontendFiles(join20(dir, entry.name)));
20648
21110
  } else if (/\.(tsx?|jsx?)$/.test(entry.name)) {
20649
- files.push(join19(dir, entry.name));
21111
+ files.push(join20(dir, entry.name));
20650
21112
  }
20651
21113
  }
20652
21114
  } catch {
@@ -21017,7 +21479,7 @@ var init_memory_tools = __esm({
21017
21479
  });
21018
21480
 
21019
21481
  // src/docs-tools.ts
21020
- import { readFileSync as readFileSync31, existsSync as existsSync29 } from "fs";
21482
+ import { readFileSync as readFileSync32, existsSync as existsSync29 } from "fs";
21021
21483
  import { resolve as resolve25, basename as basename6 } from "path";
21022
21484
  function p3(baseName) {
21023
21485
  return `${getConfig().toolPrefix}_${baseName}`;
@@ -21076,7 +21538,7 @@ function loadDocsMap() {
21076
21538
  if (!existsSync29(mapPath)) {
21077
21539
  throw new Error(`docs-map.json not found at ${mapPath}`);
21078
21540
  }
21079
- return JSON.parse(readFileSync31(mapPath, "utf-8"));
21541
+ return JSON.parse(readFileSync32(mapPath, "utf-8"));
21080
21542
  }
21081
21543
  function matchesPattern(filePath, pattern) {
21082
21544
  const regexStr = pattern.replace(/\./g, "\\.").replace(/\*\*/g, "{{GLOBSTAR}}").replace(/\*/g, "[^/]*").replace(/\{\{GLOBSTAR\}\}/g, ".*");
@@ -21150,9 +21612,9 @@ function extractProcedureNames(routerPath) {
21150
21612
  if (!existsSync29(absPath)) {
21151
21613
  const altPath = ensureWithinRoot(resolve25(getResolvedPaths().srcDir, "../server/api/routers", basename6(routerPath)), root);
21152
21614
  if (!existsSync29(altPath)) return [];
21153
- return extractProcedureNamesFromContent(readFileSync31(altPath, "utf-8"));
21615
+ return extractProcedureNamesFromContent(readFileSync32(altPath, "utf-8"));
21154
21616
  }
21155
- return extractProcedureNamesFromContent(readFileSync31(absPath, "utf-8"));
21617
+ return extractProcedureNamesFromContent(readFileSync32(absPath, "utf-8"));
21156
21618
  }
21157
21619
  function extractProcedureNamesFromContent(content) {
21158
21620
  const procRegex = /\.(?:query|mutation)\s*\(/g;
@@ -21205,7 +21667,7 @@ function handleDocsAudit(args2) {
21205
21667
  });
21206
21668
  continue;
21207
21669
  }
21208
- const content = readFileSync31(helpPagePath, "utf-8");
21670
+ const content = readFileSync32(helpPagePath, "utf-8");
21209
21671
  const sections = extractSections(content);
21210
21672
  const frontmatter = extractFrontmatter(content);
21211
21673
  const staleReasons = [];
@@ -21247,7 +21709,7 @@ function handleDocsAudit(args2) {
21247
21709
  if (parentId === mappingId) {
21248
21710
  const guidePath = ensureWithinRoot(resolve25(getResolvedPaths().helpSitePath, `pages/user-guides/${guideName}/index.mdx`), getProjectRoot());
21249
21711
  if (existsSync29(guidePath)) {
21250
- const guideContent = readFileSync31(guidePath, "utf-8");
21712
+ const guideContent = readFileSync32(guidePath, "utf-8");
21251
21713
  const guideFrontmatter = extractFrontmatter(guideContent);
21252
21714
  if (!guideFrontmatter?.lastVerified || status === "STALE") {
21253
21715
  results.push({
@@ -21287,7 +21749,7 @@ function handleDocsCoverage(args2) {
21287
21749
  let lastVerified = null;
21288
21750
  let status = null;
21289
21751
  if (exists) {
21290
- const content = readFileSync31(helpPagePath, "utf-8");
21752
+ const content = readFileSync32(helpPagePath, "utf-8");
21291
21753
  lineCount = content.split("\n").length;
21292
21754
  hasContent = lineCount > 10;
21293
21755
  const frontmatter = extractFrontmatter(content);
@@ -22405,8 +22867,8 @@ var init_sentinel_tools = __esm({
22405
22867
  });
22406
22868
 
22407
22869
  // src/sentinel-scanner.ts
22408
- import { readFileSync as readFileSync32, existsSync as existsSync31, readdirSync as readdirSync22, statSync as statSync13 } from "fs";
22409
- import { resolve as resolve27, join as join20, basename as basename7, dirname as dirname14, relative as relative11 } from "path";
22870
+ import { readFileSync as readFileSync33, existsSync as existsSync31, readdirSync as readdirSync23, statSync as statSync13 } from "fs";
22871
+ import { resolve as resolve27, join as join21, basename as basename7, dirname as dirname15, relative as relative11 } from "path";
22410
22872
  function inferDomain(filePath) {
22411
22873
  const domains = getConfig().domains;
22412
22874
  const path = filePath.toLowerCase();
@@ -22538,7 +23000,7 @@ function scanComponentExports(dataDb2) {
22538
23000
  const basePath = resolve27(projectRoot, componentsBase);
22539
23001
  if (existsSync31(basePath)) {
22540
23002
  try {
22541
- const entries = readdirSync22(basePath, { withFileTypes: true });
23003
+ const entries = readdirSync23(basePath, { withFileTypes: true });
22542
23004
  for (const entry of entries) {
22543
23005
  if (entry.isDirectory()) {
22544
23006
  componentDirs.push(componentsBase + "/" + entry.name);
@@ -22553,7 +23015,7 @@ function scanComponentExports(dataDb2) {
22553
23015
  const files = walkDir2(absDir).filter((f2) => f2.endsWith(".tsx") || f2.endsWith(".ts"));
22554
23016
  for (const file of files) {
22555
23017
  const relPath = relative11(projectRoot, file);
22556
- const source = readFileSync32(file, "utf-8");
23018
+ const source = readFileSync33(file, "utf-8");
22557
23019
  const annotations = parseFeatureAnnotations(source);
22558
23020
  if (annotations.length > 0) {
22559
23021
  for (const ann of annotations) {
@@ -22579,7 +23041,7 @@ function scanComponentExports(dataDb2) {
22579
23041
  if (hasHandlers && exportMatch) {
22580
23042
  const componentName = exportMatch[1];
22581
23043
  const domain = inferDomain(relPath);
22582
- const subdomain = basename7(dirname14(relPath));
23044
+ const subdomain = basename7(dirname15(relPath));
22583
23045
  const featureKey = `component.${subdomain}.${componentName.replace(/([A-Z])/g, "-$1").toLowerCase().replace(/^-/, "")}`;
22584
23046
  if (!annotations.some((a2) => a2.featureKey === featureKey)) {
22585
23047
  features.push({
@@ -22602,9 +23064,9 @@ function scanComponentExports(dataDb2) {
22602
23064
  function walkDir2(dir) {
22603
23065
  const results = [];
22604
23066
  try {
22605
- const entries = readdirSync22(dir);
23067
+ const entries = readdirSync23(dir);
22606
23068
  for (const entry of entries) {
22607
- const fullPath = join20(dir, entry);
23069
+ const fullPath = join21(dir, entry);
22608
23070
  try {
22609
23071
  const stat = statSync13(fullPath);
22610
23072
  if (stat.isDirectory()) {
@@ -23592,7 +24054,7 @@ var init_audit_trail = __esm({
23592
24054
  });
23593
24055
 
23594
24056
  // src/validation-engine.ts
23595
- import { existsSync as existsSync32, readFileSync as readFileSync33 } from "fs";
24057
+ import { existsSync as existsSync32, readFileSync as readFileSync34 } from "fs";
23596
24058
  function p10(baseName) {
23597
24059
  return `${getConfig().toolPrefix}_${baseName}`;
23598
24060
  }
@@ -23632,7 +24094,7 @@ function validateFile(filePath, projectRoot) {
23632
24094
  });
23633
24095
  return checks;
23634
24096
  }
23635
- const source = readFileSync33(absPath, "utf-8");
24097
+ const source = readFileSync34(absPath, "utf-8");
23636
24098
  const lines = source.split("\n");
23637
24099
  if (activeChecks.rule_compliance !== false) {
23638
24100
  for (const ruleSet of config.rules) {
@@ -24077,7 +24539,7 @@ var init_adr_generator = __esm({
24077
24539
  });
24078
24540
 
24079
24541
  // src/security-scorer.ts
24080
- import { existsSync as existsSync33, readFileSync as readFileSync34 } from "fs";
24542
+ import { existsSync as existsSync33, readFileSync as readFileSync35 } from "fs";
24081
24543
  function p12(baseName) {
24082
24544
  return `${getConfig().toolPrefix}_${baseName}`;
24083
24545
  }
@@ -24106,7 +24568,7 @@ function scoreFileSecurity(filePath, projectRoot) {
24106
24568
  }
24107
24569
  let source;
24108
24570
  try {
24109
- source = readFileSync34(absPath, "utf-8");
24571
+ source = readFileSync35(absPath, "utf-8");
24110
24572
  } catch {
24111
24573
  return { riskScore: 0, findings: [] };
24112
24574
  }
@@ -24395,7 +24857,7 @@ var init_security_scorer = __esm({
24395
24857
  });
24396
24858
 
24397
24859
  // src/dependency-scorer.ts
24398
- import { existsSync as existsSync34, readFileSync as readFileSync35 } from "fs";
24860
+ import { existsSync as existsSync34, readFileSync as readFileSync36 } from "fs";
24399
24861
  import { resolve as resolve28 } from "path";
24400
24862
  function p13(baseName) {
24401
24863
  return `${getConfig().toolPrefix}_${baseName}`;
@@ -24431,7 +24893,7 @@ function getInstalledPackages(projectRoot) {
24431
24893
  const pkgPath = resolve28(projectRoot, "package.json");
24432
24894
  if (!existsSync34(pkgPath)) return /* @__PURE__ */ new Map();
24433
24895
  try {
24434
- const pkg = JSON.parse(readFileSync35(pkgPath, "utf-8"));
24896
+ const pkg = JSON.parse(readFileSync36(pkgPath, "utf-8"));
24435
24897
  const packages = /* @__PURE__ */ new Map();
24436
24898
  for (const [name, version] of Object.entries(pkg.dependencies ?? {})) {
24437
24899
  packages.set(name, version);
@@ -25033,8 +25495,8 @@ var init_regression_detector = __esm({
25033
25495
  });
25034
25496
 
25035
25497
  // src/knowledge-indexer.ts
25036
- import { createHash as createHash8 } from "crypto";
25037
- import { readFileSync as readFileSync36, readdirSync as readdirSync23, statSync as statSync14, existsSync as existsSync35 } from "fs";
25498
+ import { createHash as createHash9 } from "crypto";
25499
+ import { readFileSync as readFileSync37, readdirSync as readdirSync24, statSync as statSync14, existsSync as existsSync35 } from "fs";
25038
25500
  import { resolve as resolve29, relative as relative12, basename as basename8, extname as extname2 } from "path";
25039
25501
  function getKnowledgePaths() {
25040
25502
  const resolved = getResolvedPaths();
@@ -25061,7 +25523,7 @@ function discoverMarkdownFiles(baseDir) {
25061
25523
  const files = [];
25062
25524
  function walk(dir) {
25063
25525
  try {
25064
- const entries = readdirSync23(dir, { withFileTypes: true });
25526
+ const entries = readdirSync24(dir, { withFileTypes: true });
25065
25527
  for (const entry of entries) {
25066
25528
  const fullPath = resolve29(dir, entry.name);
25067
25529
  if (entry.isDirectory()) {
@@ -25121,7 +25583,7 @@ function categorizeFile(filePath) {
25121
25583
  return "root";
25122
25584
  }
25123
25585
  function hashContent2(content) {
25124
- return createHash8("sha256").update(content).digest("hex");
25586
+ return createHash9("sha256").update(content).digest("hex");
25125
25587
  }
25126
25588
  function parseCRTable(content) {
25127
25589
  const rules = [];
@@ -25389,7 +25851,7 @@ function indexAllKnowledge(db) {
25389
25851
  }
25390
25852
  for (const filePath of files) {
25391
25853
  if (!existsSync35(filePath)) continue;
25392
- const content = readFileSync36(filePath, "utf-8");
25854
+ const content = readFileSync37(filePath, "utf-8");
25393
25855
  const hash = hashContent2(content);
25394
25856
  const relPath = filePath.startsWith(paths.claudeDir) ? relative12(paths.claudeDir, filePath) : filePath.startsWith(paths.plansDir) ? "plans/" + relative12(paths.plansDir, filePath) : filePath.startsWith(paths.docsDir) ? "docs/" + relative12(paths.docsDir, filePath) : filePath.startsWith(paths.memoryDir) ? `memory/${relative12(paths.memoryDir, filePath)}` : basename8(filePath);
25395
25857
  const category = categorizeFile(filePath);
@@ -25541,7 +26003,7 @@ var init_knowledge_indexer = __esm({
25541
26003
  });
25542
26004
 
25543
26005
  // src/knowledge-tools.ts
25544
- import { readFileSync as readFileSync37, writeFileSync as writeFileSync5, appendFileSync as appendFileSync2, readdirSync as readdirSync24 } from "fs";
26006
+ import { readFileSync as readFileSync38, writeFileSync as writeFileSync6, appendFileSync as appendFileSync2, readdirSync as readdirSync25 } from "fs";
25545
26007
  import { resolve as resolve30, basename as basename9 } from "path";
25546
26008
  function p16(baseName) {
25547
26009
  return `${getConfig().toolPrefix}_${baseName}`;
@@ -26292,14 +26754,14 @@ ${crRule ? `- **CR**: ${crRule}
26292
26754
  `;
26293
26755
  let existing = "";
26294
26756
  try {
26295
- existing = readFileSync37(correctionsPath, "utf-8");
26757
+ existing = readFileSync38(correctionsPath, "utf-8");
26296
26758
  } catch {
26297
26759
  }
26298
26760
  const archiveIdx = existing.indexOf("## Archived");
26299
26761
  if (archiveIdx > 0) {
26300
26762
  const before = existing.slice(0, archiveIdx);
26301
26763
  const after = existing.slice(archiveIdx);
26302
- writeFileSync5(correctionsPath, before + entry + after);
26764
+ writeFileSync6(correctionsPath, before + entry + after);
26303
26765
  } else {
26304
26766
  appendFileSync2(correctionsPath, entry);
26305
26767
  }
@@ -26474,7 +26936,7 @@ function handleGaps(db, args2) {
26474
26936
  } else if (checkType === "routers") {
26475
26937
  try {
26476
26938
  const routersDir = getResolvedPaths().routersDir;
26477
- const routerFiles = readdirSync24(routersDir).filter((f2) => f2.endsWith(".ts") && !f2.startsWith("_"));
26939
+ const routerFiles = readdirSync25(routersDir).filter((f2) => f2.endsWith(".ts") && !f2.startsWith("_"));
26478
26940
  lines.push(`| Router | Knowledge Hits | Status |`);
26479
26941
  lines.push(`|--------|----------------|--------|`);
26480
26942
  for (const file of routerFiles) {
@@ -26630,13 +27092,13 @@ var init_knowledge_tools = __esm({
26630
27092
 
26631
27093
  // src/knowledge-db.ts
26632
27094
  import Database3 from "better-sqlite3";
26633
- import { dirname as dirname15 } from "path";
26634
- import { existsSync as existsSync37, mkdirSync as mkdirSync10 } from "fs";
27095
+ import { dirname as dirname16 } from "path";
27096
+ import { existsSync as existsSync37, mkdirSync as mkdirSync11 } from "fs";
26635
27097
  function getKnowledgeDb() {
26636
27098
  const dbPath = getResolvedPaths().knowledgeDbPath;
26637
- const dir = dirname15(dbPath);
27099
+ const dir = dirname16(dbPath);
26638
27100
  if (!existsSync37(dir)) {
26639
- mkdirSync10(dir, { recursive: true });
27101
+ mkdirSync11(dir, { recursive: true });
26640
27102
  }
26641
27103
  const db = new Database3(dbPath);
26642
27104
  db.pragma("journal_mode = WAL");
@@ -27369,7 +27831,7 @@ var init_python_tools = __esm({
27369
27831
  });
27370
27832
 
27371
27833
  // src/tools.ts
27372
- import { readFileSync as readFileSync38, existsSync as existsSync38 } from "fs";
27834
+ import { readFileSync as readFileSync39, existsSync as existsSync38 } from "fs";
27373
27835
  import { resolve as resolve31, basename as basename10 } from "path";
27374
27836
  function prefix2() {
27375
27837
  return getConfig().toolPrefix;
@@ -27806,7 +28268,7 @@ function handleContext(file, dataDb2, codegraphDb2) {
27806
28268
  const root = getProjectRoot();
27807
28269
  const absFilePath = ensureWithinRoot(resolve31(resolvedPaths.srcDir, "..", file), root);
27808
28270
  if (existsSync38(absFilePath)) {
27809
- const fileContent = readFileSync38(absFilePath, "utf-8").slice(0, 3e3);
28271
+ const fileContent = readFileSync39(absFilePath, "utf-8").slice(0, 3e3);
27810
28272
  const keywords = [];
27811
28273
  if (fileContent.includes("ctx.db")) keywords.push("database", "schema");
27812
28274
  if (fileContent.includes("BigInt") || fileContent.includes("Decimal")) keywords.push("BigInt", "serialization");
@@ -28234,7 +28696,7 @@ function handleSchema(args2) {
28234
28696
  if (!existsSync38(absPath)) {
28235
28697
  return text17(`File not found: ${file}`);
28236
28698
  }
28237
- const source = readFileSync38(absPath, "utf-8");
28699
+ const source = readFileSync39(absPath, "utf-8");
28238
28700
  const config = getConfig();
28239
28701
  const dbPattern = config.dbAccessPattern ?? "ctx.db.{table}";
28240
28702
  const regexStr = dbPattern.replace(/[.*+?^${}()|[\]\\]/g, "\\$&").replace("\\{table\\}", "(\\w+)");
@@ -28312,8 +28774,8 @@ var init_tools = __esm({
28312
28774
 
28313
28775
  // src/server.ts
28314
28776
  var server_exports = {};
28315
- import { readFileSync as readFileSync39 } from "fs";
28316
- import { resolve as resolve32, dirname as dirname16 } from "path";
28777
+ import { readFileSync as readFileSync40 } from "fs";
28778
+ import { resolve as resolve32, dirname as dirname17 } from "path";
28317
28779
  import { fileURLToPath as fileURLToPath4 } from "url";
28318
28780
  function getDb() {
28319
28781
  if (!codegraphDb) codegraphDb = getCodeGraphDb();
@@ -28405,10 +28867,10 @@ var init_server = __esm({
28405
28867
  init_tools();
28406
28868
  init_memory_db();
28407
28869
  init_license();
28408
- __dirname4 = dirname16(fileURLToPath4(import.meta.url));
28870
+ __dirname4 = dirname17(fileURLToPath4(import.meta.url));
28409
28871
  PKG_VERSION = (() => {
28410
28872
  try {
28411
- const pkg = JSON.parse(readFileSync39(resolve32(__dirname4, "..", "package.json"), "utf-8"));
28873
+ const pkg = JSON.parse(readFileSync40(resolve32(__dirname4, "..", "package.json"), "utf-8"));
28412
28874
  return pkg.version ?? "0.0.0";
28413
28875
  } catch {
28414
28876
  return "0.0.0";
@@ -28711,7 +29173,7 @@ var config_upgrade_exports = {};
28711
29173
  __export(config_upgrade_exports, {
28712
29174
  runConfigUpgrade: () => runConfigUpgrade
28713
29175
  });
28714
- import { existsSync as existsSync39, readFileSync as readFileSync40, writeFileSync as writeFileSync6, copyFileSync, unlinkSync as unlinkSync2 } from "fs";
29176
+ import { existsSync as existsSync39, readFileSync as readFileSync41, writeFileSync as writeFileSync7, copyFileSync, unlinkSync as unlinkSync3 } from "fs";
28715
29177
  import { resolve as resolve33 } from "path";
28716
29178
  import { parse as parseYaml6 } from "yaml";
28717
29179
  async function runConfigUpgrade(opts = {}) {
@@ -28730,7 +29192,7 @@ async function runConfigUpgrade(opts = {}) {
28730
29192
  }
28731
29193
  try {
28732
29194
  copyFileSync(bakPath, configPath);
28733
- unlinkSync2(bakPath);
29195
+ unlinkSync3(bakPath);
28734
29196
  log("Config restored from backup.\n");
28735
29197
  return { exitCode: 0, action: "rolled-back" };
28736
29198
  } catch (e2) {
@@ -28746,7 +29208,7 @@ async function runConfigUpgrade(opts = {}) {
28746
29208
  }
28747
29209
  let existing;
28748
29210
  try {
28749
- const content = readFileSync40(configPath, "utf-8");
29211
+ const content = readFileSync41(configPath, "utf-8");
28750
29212
  const parsed = parseYaml6(content);
28751
29213
  if (!parsed || typeof parsed !== "object") {
28752
29214
  throw new Error("config is not a YAML object");
@@ -28769,8 +29231,8 @@ async function runConfigUpgrade(opts = {}) {
28769
29231
  fingerprint: computeFingerprint(detection)
28770
29232
  };
28771
29233
  try {
28772
- const original = readFileSync40(configPath, "utf-8");
28773
- writeFileSync6(bakPath, original, "utf-8");
29234
+ const original = readFileSync41(configPath, "utf-8");
29235
+ writeFileSync7(bakPath, original, "utf-8");
28774
29236
  } catch (e2) {
28775
29237
  const message = `Failed to write backup: ${e2 instanceof Error ? e2.message : String(e2)}`;
28776
29238
  err(message + "\n");
@@ -28803,7 +29265,7 @@ var config_check_drift_exports = {};
28803
29265
  __export(config_check_drift_exports, {
28804
29266
  runConfigCheckDrift: () => runConfigCheckDrift
28805
29267
  });
28806
- import { existsSync as existsSync40, readFileSync as readFileSync41 } from "fs";
29268
+ import { existsSync as existsSync40, readFileSync as readFileSync42 } from "fs";
28807
29269
  import { resolve as resolve34 } from "path";
28808
29270
  import { parse as parseYaml7 } from "yaml";
28809
29271
  function renderChanges(changes) {
@@ -28831,7 +29293,7 @@ async function runConfigCheckDrift(opts = {}) {
28831
29293
  }
28832
29294
  let config;
28833
29295
  try {
28834
- const content = readFileSync41(configPath, "utf-8");
29296
+ const content = readFileSync42(configPath, "utf-8");
28835
29297
  const parsed = parseYaml7(content);
28836
29298
  if (!parsed || typeof parsed !== "object") {
28837
29299
  throw new Error("config is not a YAML object");
@@ -28898,11 +29360,11 @@ var init_config_check_drift = __esm({
28898
29360
  });
28899
29361
 
28900
29362
  // src/cli.ts
28901
- import { readFileSync as readFileSync42 } from "fs";
28902
- import { resolve as resolve35, dirname as dirname17 } from "path";
29363
+ import { readFileSync as readFileSync43 } from "fs";
29364
+ import { resolve as resolve35, dirname as dirname18 } from "path";
28903
29365
  import { fileURLToPath as fileURLToPath5 } from "url";
28904
29366
  var __filename4 = fileURLToPath5(import.meta.url);
28905
- var __dirname5 = dirname17(__filename4);
29367
+ var __dirname5 = dirname18(__filename4);
28906
29368
  var args = process.argv.slice(2);
28907
29369
  var subcommand = args[0];
28908
29370
  async function main() {
@@ -29084,7 +29546,7 @@ Examples:
29084
29546
  }
29085
29547
  function printVersion() {
29086
29548
  try {
29087
- const pkg = JSON.parse(readFileSync42(resolve35(__dirname5, "../package.json"), "utf-8"));
29549
+ const pkg = JSON.parse(readFileSync43(resolve35(__dirname5, "../package.json"), "utf-8"));
29088
29550
  console.log(`massu v${pkg.version}`);
29089
29551
  } catch {
29090
29552
  console.log("massu v0.1.0");