@massu/core 1.6.0 → 1.6.1

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,1239 +11159,43 @@ var init_python_flask = __esm({
11159
11159
  }
11160
11160
  });
11161
11161
 
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";
11582
- function extractPrefixBase4(prefix3) {
11583
- if (!prefix3.startsWith("/"))
11584
- return null;
11585
- const stripped = prefix3.replace(/^\/+/, "");
11586
- const firstSeg = stripped.split("/")[0];
11587
- if (!firstSeg)
11588
- return null;
11589
- return "/" + firstSeg;
11590
- }
11591
- var ROUTE_METHOD_QUERY, MOUNT_PREFIX_QUERY, MIDDLEWARE_USE_QUERY, goChiAdapter;
11592
- var init_dist = __esm({
11593
- "../adapter-go-chi/dist/index.js"() {
11594
- "use strict";
11595
- init_adapter();
11596
- ROUTE_METHOD_QUERY = `
11597
- (call_expression
11598
- function: (selector_expression
11599
- field: (field_identifier) @method (#match? @method "^(Get|Post|Put|Delete|Patch|Head|Options|Connect|Trace)$"))
11600
- arguments: (argument_list
11601
- .
11602
- (interpreted_string_literal) @route_path))
11603
- `;
11604
- MOUNT_PREFIX_QUERY = `
11605
- (call_expression
11606
- function: (selector_expression
11607
- field: (field_identifier) @_field (#eq? @_field "Mount"))
11608
- arguments: (argument_list
11609
- .
11610
- (interpreted_string_literal) @mount_path))
11611
- `;
11612
- MIDDLEWARE_USE_QUERY = `
11613
- (call_expression
11614
- function: (selector_expression
11615
- field: (field_identifier) @_use (#eq? @_use "Use"))
11616
- arguments: (argument_list
11617
- .
11618
- (selector_expression
11619
- operand: (identifier) @_pkg (#eq? @_pkg "middleware")
11620
- field: (field_identifier) @middleware_name)))
11621
- `;
11622
- goChiAdapter = {
11623
- id: "go-chi",
11624
- languages: ["go"],
11625
- matches(signals) {
11626
- if (!signals.goMod)
11627
- return false;
11628
- if (/github\.com\/go-chi\/chi/i.test(signals.goMod))
11629
- return true;
11630
- return false;
11631
- },
11632
- async introspect(files, _rootDir) {
11633
- if (files.length === 0) {
11634
- return { conventions: {}, provenance: [], confidence: "none" };
11635
- }
11636
- let language;
11637
- try {
11638
- language = await loadGrammar2("go");
11639
- } catch (e2) {
11640
- return { conventions: {}, provenance: [], confidence: "none" };
11641
- }
11642
- const parser = new Parser8();
11643
- parser.setLanguage(language);
11644
- const routeMethods = /* @__PURE__ */ new Map();
11645
- const mountBases = /* @__PURE__ */ new Map();
11646
- const middlewareNames = /* @__PURE__ */ new Map();
11647
- try {
11648
- for (const file of files) {
11649
- const skip = isParsableSource2(file.content, file.size);
11650
- if (skip) {
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
- `);
11653
- continue;
11654
- }
11655
- try {
11656
- for (const hit of runQuery2(parser, file.content, ROUTE_METHOD_QUERY, "chi-route-method", file.path)) {
11657
- const method = hit.captures.method;
11658
- if (method && !routeMethods.has(method)) {
11659
- routeMethods.set(method, { line: hit.line, file: file.path });
11660
- }
11661
- }
11662
- for (const hit of runQuery2(parser, file.content, MOUNT_PREFIX_QUERY, "chi-mount-prefix", file.path)) {
11663
- const raw = hit.captures.mount_path;
11664
- if (!raw)
11665
- continue;
11666
- const literal = raw.replace(/^["`]/, "").replace(/["`]$/, "");
11667
- const base = extractPrefixBase4(literal);
11668
- if (base && !mountBases.has(base)) {
11669
- mountBases.set(base, { line: hit.line, file: file.path });
11670
- }
11671
- }
11672
- for (const hit of runQuery2(parser, file.content, MIDDLEWARE_USE_QUERY, "chi-middleware-use", file.path)) {
11673
- const name = hit.captures.middleware_name;
11674
- if (name && !middlewareNames.has(name)) {
11675
- middlewareNames.set(name, { line: hit.line, file: file.path });
11676
- }
11677
- }
11678
- } catch (e2) {
11679
- if (e2 instanceof InvalidQueryError2) {
11680
- throw e2;
11681
- }
11682
- continue;
11683
- }
11684
- }
11685
- } finally {
11686
- try {
11687
- parser.delete();
11688
- } catch {
11689
- }
11690
- }
11691
- const conventions = {};
11692
- const provenance = [];
11693
- if (routeMethods.size === 1) {
11694
- const [name, { line, file }] = routeMethods.entries().next().value;
11695
- conventions.route_method = name;
11696
- provenance.push({ field: "route_method", sourceFile: file, line, query: "chi-route-method" });
11697
- } else if (routeMethods.size >= 2) {
11698
- const [name, { line, file }] = routeMethods.entries().next().value;
11699
- conventions.route_method = name;
11700
- provenance.push({ field: "route_method", sourceFile: file, line, query: "chi-route-method" });
11701
- }
11702
- if (mountBases.size >= 1) {
11703
- const [base, { line, file }] = mountBases.entries().next().value;
11704
- conventions.mount_prefix_base = base;
11705
- provenance.push({ field: "mount_prefix_base", sourceFile: file, line, query: "chi-mount-prefix" });
11706
- }
11707
- if (middlewareNames.size >= 1) {
11708
- const [name, { line, file }] = middlewareNames.entries().next().value;
11709
- conventions.middleware_name = name;
11710
- provenance.push({ field: "middleware_name", sourceFile: file, line, query: "chi-middleware-use" });
11711
- }
11712
- let confidence;
11713
- if (Object.keys(conventions).length === 0) {
11714
- confidence = "none";
11715
- } else if (routeMethods.size === 1) {
11716
- confidence = "high";
11717
- } else if (routeMethods.size >= 2) {
11718
- confidence = "low";
11719
- } else {
11720
- confidence = "medium";
11721
- }
11722
- return { conventions, provenance, confidence };
11723
- }
11724
- };
11725
- }
11726
- });
11727
-
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";
11738
- function extractRootController(target) {
11739
- const idx = target.indexOf("#");
11740
- if (idx <= 0)
11741
- return null;
11742
- const controller = target.slice(0, idx).trim();
11743
- return controller || null;
11744
- }
11745
- var ROUTE_METHOD_QUERY2, NAMESPACE_QUERY, ROOT_ROUTE_QUERY, railsAdapter;
11746
- var init_dist2 = __esm({
11747
- "../adapter-rails/dist/index.js"() {
11748
- "use strict";
11749
- init_adapter();
11750
- ROUTE_METHOD_QUERY2 = `
11751
- (call
11752
- method: (identifier) @method (#match? @method "^(get|post|put|patch|delete|options|head)$")
11753
- arguments: (argument_list
11754
- .
11755
- (string) @route_path))
11756
- `;
11757
- NAMESPACE_QUERY = `
11758
- (call
11759
- method: (identifier) @_method (#eq? @_method "namespace")
11760
- arguments: (argument_list
11761
- .
11762
- [
11763
- (simple_symbol) @namespace_symbol
11764
- (string) @namespace_string
11765
- ]))
11766
- `;
11767
- ROOT_ROUTE_QUERY = `
11768
- (call
11769
- method: (identifier) @_method (#eq? @_method "root")
11770
- arguments: (argument_list
11771
- .
11772
- (string) @root_target))
11773
-
11774
- (call
11775
- method: (identifier) @_method (#eq? @_method "root")
11776
- arguments: (argument_list
11777
- (pair
11778
- key: (hash_key_symbol) @_key (#eq? @_key "to")
11779
- value: (string) @root_target)))
11780
- `;
11781
- railsAdapter = {
11782
- id: "rails",
11783
- languages: ["ruby"],
11784
- matches(signals) {
11785
- if (!signals.gemfile)
11786
- return false;
11787
- return /^\s*gem\s+['"]rails['"]/im.test(signals.gemfile);
11788
- },
11789
- async introspect(files, _rootDir) {
11790
- if (files.length === 0) {
11791
- return { conventions: {}, provenance: [], confidence: "none" };
11792
- }
11793
- let language;
11794
- try {
11795
- language = await loadGrammar2("ruby");
11796
- } catch (e2) {
11797
- return { conventions: {}, provenance: [], confidence: "none" };
11798
- }
11799
- const parser = new Parser9();
11800
- parser.setLanguage(language);
11801
- const routeMethods = /* @__PURE__ */ new Map();
11802
- const namespaces = /* @__PURE__ */ new Map();
11803
- const rootControllers = /* @__PURE__ */ new Map();
11804
- try {
11805
- for (const file of files) {
11806
- const skip = isParsableSource2(file.content, file.size);
11807
- if (skip) {
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
- `);
11810
- continue;
11811
- }
11812
- try {
11813
- for (const hit of runQuery2(parser, file.content, ROUTE_METHOD_QUERY2, "rails-route-method", file.path)) {
11814
- const method = hit.captures.method;
11815
- if (method && !routeMethods.has(method)) {
11816
- routeMethods.set(method, { line: hit.line, file: file.path });
11817
- }
11818
- }
11819
- for (const hit of runQuery2(parser, file.content, NAMESPACE_QUERY, "rails-namespace", file.path)) {
11820
- const symbolRaw = hit.captures.namespace_symbol;
11821
- const stringRaw = hit.captures.namespace_string;
11822
- const name = symbolRaw ? symbolRaw.replace(/^:/, "") : stringRaw ? stringRaw.replace(/^['"]/, "").replace(/['"]$/, "") : null;
11823
- if (!name)
11824
- continue;
11825
- const path = "/" + name;
11826
- if (!namespaces.has(path)) {
11827
- namespaces.set(path, { line: hit.line, file: file.path });
11828
- }
11829
- }
11830
- for (const hit of runQuery2(parser, file.content, ROOT_ROUTE_QUERY, "rails-root", file.path)) {
11831
- const raw = hit.captures.root_target;
11832
- if (!raw)
11833
- continue;
11834
- const literal = raw.replace(/^['"]/, "").replace(/['"]$/, "");
11835
- const controller = extractRootController(literal);
11836
- if (controller && !rootControllers.has(controller)) {
11837
- rootControllers.set(controller, { line: hit.line, file: file.path });
11838
- }
11839
- }
11840
- } catch (e2) {
11841
- if (e2 instanceof InvalidQueryError2) {
11842
- throw e2;
11843
- }
11844
- continue;
11845
- }
11846
- }
11847
- } finally {
11848
- try {
11849
- parser.delete();
11850
- } catch {
11851
- }
11852
- }
11853
- const conventions = {};
11854
- const provenance = [];
11855
- if (routeMethods.size === 1) {
11856
- const [name, { line, file }] = routeMethods.entries().next().value;
11857
- conventions.route_method = name;
11858
- provenance.push({ field: "route_method", sourceFile: file, line, query: "rails-route-method" });
11859
- } else if (routeMethods.size >= 2) {
11860
- const [name, { line, file }] = routeMethods.entries().next().value;
11861
- conventions.route_method = name;
11862
- provenance.push({ field: "route_method", sourceFile: file, line, query: "rails-route-method" });
11863
- }
11864
- if (namespaces.size >= 1) {
11865
- const [path, { line, file }] = namespaces.entries().next().value;
11866
- conventions.api_namespace = path;
11867
- provenance.push({ field: "api_namespace", sourceFile: file, line, query: "rails-namespace" });
11868
- }
11869
- if (rootControllers.size >= 1) {
11870
- const [name, { line, file }] = rootControllers.entries().next().value;
11871
- conventions.root_controller = name;
11872
- provenance.push({ field: "root_controller", sourceFile: file, line, query: "rails-root" });
11873
- }
11874
- let confidence;
11875
- if (Object.keys(conventions).length === 0) {
11876
- confidence = "none";
11877
- } else if (routeMethods.size === 1) {
11878
- confidence = "high";
11879
- } else if (routeMethods.size >= 2) {
11880
- confidence = "low";
11881
- } else {
11882
- confidence = "medium";
11883
- }
11884
- return { conventions, provenance, confidence };
11885
- }
11886
- };
11887
- }
11888
- });
11889
-
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";
11900
- function extractPrefixBase5(prefix3) {
11901
- if (!prefix3.startsWith("/"))
11902
- return null;
11903
- const stripped = prefix3.replace(/^\/+/, "");
11904
- const firstSeg = stripped.split("/")[0];
11905
- if (!firstSeg)
11906
- return null;
11907
- return "/" + firstSeg;
11908
- }
11909
- var ROUTE_METHOD_QUERY3, SCOPE_PATH_QUERY, ROUTER_MODULE_QUERY, phoenixAdapter;
11910
- var init_dist3 = __esm({
11911
- "../adapter-phoenix/dist/index.js"() {
11912
- "use strict";
11913
- init_adapter();
11914
- ROUTE_METHOD_QUERY3 = `
11915
- (call
11916
- (identifier) @method (#match? @method "^(get|post|put|patch|delete|options|head)$")
11917
- (arguments
11918
- .
11919
- (string) @route_path))
11920
- `;
11921
- SCOPE_PATH_QUERY = `
11922
- (call
11923
- (identifier) @_method (#eq? @_method "scope")
11924
- (arguments
11925
- .
11926
- (string) @scope_path)
11927
- (do_block))
11928
- `;
11929
- ROUTER_MODULE_QUERY = `
11930
- (call
11931
- (identifier) @_method (#eq? @_method "defmodule")
11932
- (arguments
11933
- .
11934
- (alias) @module_name (#match? @module_name "Router$"))
11935
- (do_block))
11936
- `;
11937
- phoenixAdapter = {
11938
- id: "phoenix",
11939
- languages: ["elixir"],
11940
- matches(signals) {
11941
- if (!signals.mixExs)
11942
- return false;
11943
- return /\{\s*:phoenix\b(?!_)/.test(signals.mixExs);
11944
- },
11945
- async introspect(files, _rootDir) {
11946
- if (files.length === 0) {
11947
- return { conventions: {}, provenance: [], confidence: "none" };
11948
- }
11949
- let language;
11950
- try {
11951
- language = await loadGrammar2("elixir");
11952
- } catch (e2) {
11953
- return { conventions: {}, provenance: [], confidence: "none" };
11954
- }
11955
- const parser = new Parser10();
11956
- parser.setLanguage(language);
11957
- const routeMethods = /* @__PURE__ */ new Map();
11958
- const scopePaths = /* @__PURE__ */ new Map();
11959
- const routerModules = /* @__PURE__ */ new Map();
11960
- try {
11961
- for (const file of files) {
11962
- const skip = isParsableSource2(file.content, file.size);
11963
- if (skip) {
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
- `);
11966
- continue;
11967
- }
11968
- try {
11969
- for (const hit of runQuery2(parser, file.content, ROUTE_METHOD_QUERY3, "phoenix-route-method", file.path)) {
11970
- const method = hit.captures.method;
11971
- if (method && !routeMethods.has(method)) {
11972
- routeMethods.set(method, { line: hit.line, file: file.path });
11973
- }
11974
- }
11975
- for (const hit of runQuery2(parser, file.content, SCOPE_PATH_QUERY, "phoenix-scope-path", file.path)) {
11976
- const raw = hit.captures.scope_path;
11977
- if (!raw)
11978
- continue;
11979
- const literal = raw.replace(/^["']/, "").replace(/["']$/, "");
11980
- const base = extractPrefixBase5(literal);
11981
- if (base && !scopePaths.has(base)) {
11982
- scopePaths.set(base, { line: hit.line, file: file.path });
11983
- }
11984
- }
11985
- for (const hit of runQuery2(parser, file.content, ROUTER_MODULE_QUERY, "phoenix-router-module", file.path)) {
11986
- const name = hit.captures.module_name;
11987
- if (name && !routerModules.has(name)) {
11988
- routerModules.set(name, { line: hit.line, file: file.path });
11989
- }
11990
- }
11991
- } catch (e2) {
11992
- if (e2 instanceof InvalidQueryError2) {
11993
- throw e2;
11994
- }
11995
- continue;
11996
- }
11997
- }
11998
- } finally {
11999
- try {
12000
- parser.delete();
12001
- } catch {
12002
- }
12003
- }
12004
- const conventions = {};
12005
- const provenance = [];
12006
- if (routeMethods.size === 1) {
12007
- const [name, { line, file }] = routeMethods.entries().next().value;
12008
- conventions.route_method = name;
12009
- provenance.push({ field: "route_method", sourceFile: file, line, query: "phoenix-route-method" });
12010
- } else if (routeMethods.size >= 2) {
12011
- const [name, { line, file }] = routeMethods.entries().next().value;
12012
- conventions.route_method = name;
12013
- provenance.push({ field: "route_method", sourceFile: file, line, query: "phoenix-route-method" });
12014
- }
12015
- if (scopePaths.size >= 1) {
12016
- const [base, { line, file }] = scopePaths.entries().next().value;
12017
- conventions.scope_prefix_base = base;
12018
- provenance.push({ field: "scope_prefix_base", sourceFile: file, line, query: "phoenix-scope-path" });
12019
- }
12020
- if (routerModules.size >= 1) {
12021
- const [name, { line, file }] = routerModules.entries().next().value;
12022
- conventions.router_module = name;
12023
- provenance.push({ field: "router_module", sourceFile: file, line, query: "phoenix-router-module" });
12024
- }
12025
- let confidence;
12026
- if (Object.keys(conventions).length === 0) {
12027
- confidence = "none";
12028
- } else if (routeMethods.size === 1) {
12029
- confidence = "high";
12030
- } else if (routeMethods.size >= 2) {
12031
- confidence = "low";
12032
- } else {
12033
- confidence = "medium";
12034
- }
12035
- return { conventions, provenance, confidence };
12036
- }
12037
- };
11162
+ // src/detect/adapters/go-chi.ts
11163
+ import { goChiAdapter } from "@massu/adapter-go-chi";
11164
+ var init_go_chi = __esm({
11165
+ "src/detect/adapters/go-chi.ts"() {
11166
+ "use strict";
12038
11167
  }
12039
11168
  });
12040
11169
 
12041
- // src/detect/adapters/phoenix.ts
12042
- var init_phoenix = __esm({
12043
- "src/detect/adapters/phoenix.ts"() {
11170
+ // src/detect/adapters/rails.ts
11171
+ import { railsAdapter } from "@massu/adapter-rails";
11172
+ var init_rails = __esm({
11173
+ "src/detect/adapters/rails.ts"() {
12044
11174
  "use strict";
12045
- init_dist3();
12046
11175
  }
12047
11176
  });
12048
11177
 
12049
- // ../adapter-aspnet/dist/index.js
12050
- import { Parser as Parser11 } from "web-tree-sitter";
12051
- function extractPrefixBase6(prefix3) {
12052
- const stripped = prefix3.replace(/^\/+/, "");
12053
- const firstSeg = stripped.split("/")[0];
12054
- if (!firstSeg)
12055
- return null;
12056
- return "/" + firstSeg;
12057
- }
12058
- var MAP_VERB_QUERY, HTTP_ATTR_QUERY, ROUTE_ATTR_QUERY, CONTROLLER_CLASS_QUERY, aspnetAdapter;
12059
- var init_dist4 = __esm({
12060
- "../adapter-aspnet/dist/index.js"() {
11178
+ // src/detect/adapters/phoenix.ts
11179
+ import { phoenixAdapter } from "@massu/adapter-phoenix";
11180
+ var init_phoenix = __esm({
11181
+ "src/detect/adapters/phoenix.ts"() {
12061
11182
  "use strict";
12062
- init_adapter();
12063
- MAP_VERB_QUERY = `
12064
- (invocation_expression
12065
- function: (member_access_expression
12066
- name: (identifier) @method (#match? @method "^Map(Get|Post|Put|Patch|Delete|Head|Options)$"))
12067
- arguments: (argument_list
12068
- .
12069
- (argument (string_literal) @route_path)))
12070
- `;
12071
- HTTP_ATTR_QUERY = `
12072
- (attribute
12073
- name: (identifier) @attr_name (#match? @attr_name "^Http(Get|Post|Put|Patch|Delete|Head|Options)$"))
12074
- `;
12075
- ROUTE_ATTR_QUERY = `
12076
- (attribute
12077
- name: (identifier) @_attr_name (#eq? @_attr_name "Route")
12078
- (attribute_argument_list
12079
- (attribute_argument (string_literal) @route_template)))
12080
- `;
12081
- CONTROLLER_CLASS_QUERY = `
12082
- (class_declaration
12083
- name: (identifier) @class_name (#match? @class_name "Controller$"))
12084
- `;
12085
- aspnetAdapter = {
12086
- id: "aspnet",
12087
- languages: ["csharp"],
12088
- matches(signals) {
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;
12095
- return false;
12096
- },
12097
- async introspect(files, _rootDir) {
12098
- if (files.length === 0) {
12099
- return { conventions: {}, provenance: [], confidence: "none" };
12100
- }
12101
- let language;
12102
- try {
12103
- language = await loadGrammar2("csharp");
12104
- } catch (e2) {
12105
- return { conventions: {}, provenance: [], confidence: "none" };
12106
- }
12107
- const parser = new Parser11();
12108
- parser.setLanguage(language);
12109
- const routeMethods = /* @__PURE__ */ new Map();
12110
- const prefixBases = /* @__PURE__ */ new Map();
12111
- const controllerClasses = /* @__PURE__ */ new Map();
12112
- try {
12113
- for (const file of files) {
12114
- const skip = isParsableSource2(file.content, file.size);
12115
- if (skip) {
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
- `);
12118
- continue;
12119
- }
12120
- try {
12121
- for (const hit of runQuery2(parser, file.content, MAP_VERB_QUERY, "aspnet-map-verb", file.path)) {
12122
- const methodRaw = hit.captures.method;
12123
- if (!methodRaw)
12124
- continue;
12125
- const verb = methodRaw.replace(/^Map/, "");
12126
- if (!routeMethods.has(verb)) {
12127
- routeMethods.set(verb, { line: hit.line, file: file.path });
12128
- }
12129
- const pathRaw = hit.captures.route_path;
12130
- if (pathRaw) {
12131
- const literal = pathRaw.replace(/^["']/, "").replace(/["']$/, "");
12132
- const base = extractPrefixBase6(literal);
12133
- if (base && !prefixBases.has(base)) {
12134
- prefixBases.set(base, { line: hit.line, file: file.path });
12135
- }
12136
- }
12137
- }
12138
- for (const hit of runQuery2(parser, file.content, HTTP_ATTR_QUERY, "aspnet-http-attr", file.path)) {
12139
- const attrRaw = hit.captures.attr_name;
12140
- if (!attrRaw)
12141
- continue;
12142
- const verb = attrRaw.replace(/^Http/, "");
12143
- if (!routeMethods.has(verb)) {
12144
- routeMethods.set(verb, { line: hit.line, file: file.path });
12145
- }
12146
- }
12147
- for (const hit of runQuery2(parser, file.content, ROUTE_ATTR_QUERY, "aspnet-route-attr", file.path)) {
12148
- const tplRaw = hit.captures.route_template;
12149
- if (!tplRaw)
12150
- continue;
12151
- const literal = tplRaw.replace(/^["']/, "").replace(/["']$/, "");
12152
- const base = extractPrefixBase6(literal);
12153
- if (base && !prefixBases.has(base)) {
12154
- prefixBases.set(base, { line: hit.line, file: file.path });
12155
- }
12156
- }
12157
- for (const hit of runQuery2(parser, file.content, CONTROLLER_CLASS_QUERY, "aspnet-controller-class", file.path)) {
12158
- const name = hit.captures.class_name;
12159
- if (name && !controllerClasses.has(name)) {
12160
- controllerClasses.set(name, { line: hit.line, file: file.path });
12161
- }
12162
- }
12163
- } catch (e2) {
12164
- if (e2 instanceof InvalidQueryError2) {
12165
- throw e2;
12166
- }
12167
- continue;
12168
- }
12169
- }
12170
- } finally {
12171
- try {
12172
- parser.delete();
12173
- } catch {
12174
- }
12175
- }
12176
- const conventions = {};
12177
- const provenance = [];
12178
- if (routeMethods.size === 1) {
12179
- const [name, { line, file }] = routeMethods.entries().next().value;
12180
- conventions.route_method = name;
12181
- provenance.push({ field: "route_method", sourceFile: file, line, query: "aspnet-map-verb" });
12182
- } else if (routeMethods.size >= 2) {
12183
- const [name, { line, file }] = routeMethods.entries().next().value;
12184
- conventions.route_method = name;
12185
- provenance.push({ field: "route_method", sourceFile: file, line, query: "aspnet-map-verb" });
12186
- }
12187
- if (prefixBases.size >= 1) {
12188
- const [base, { line, file }] = prefixBases.entries().next().value;
12189
- conventions.route_prefix_base = base;
12190
- provenance.push({ field: "route_prefix_base", sourceFile: file, line, query: "aspnet-route-prefix" });
12191
- }
12192
- if (controllerClasses.size >= 1) {
12193
- const [name, { line, file }] = controllerClasses.entries().next().value;
12194
- conventions.controller_class = name;
12195
- provenance.push({ field: "controller_class", sourceFile: file, line, query: "aspnet-controller-class" });
12196
- }
12197
- let confidence;
12198
- if (Object.keys(conventions).length === 0) {
12199
- confidence = "none";
12200
- } else if (routeMethods.size === 1) {
12201
- confidence = "high";
12202
- } else if (routeMethods.size >= 2) {
12203
- confidence = "low";
12204
- } else {
12205
- confidence = "medium";
12206
- }
12207
- return { conventions, provenance, confidence };
12208
- }
12209
- };
12210
11183
  }
12211
11184
  });
12212
11185
 
12213
11186
  // src/detect/adapters/aspnet.ts
11187
+ import { aspnetAdapter } from "@massu/adapter-aspnet";
12214
11188
  var init_aspnet = __esm({
12215
11189
  "src/detect/adapters/aspnet.ts"() {
12216
11190
  "use strict";
12217
- init_dist4();
12218
- }
12219
- });
12220
-
12221
- // ../adapter-spring/dist/index.js
12222
- import { Parser as Parser12 } from "web-tree-sitter";
12223
- function extractPrefixBase7(prefix3) {
12224
- const stripped = prefix3.replace(/^\/+/, "");
12225
- const firstSeg = stripped.split("/")[0];
12226
- if (!firstSeg)
12227
- return null;
12228
- return "/" + firstSeg;
12229
- }
12230
- var HTTP_MAPPING_QUERY, HTTP_MAPPING_NO_ARGS_QUERY, REQUEST_MAPPING_QUERY, CONTROLLER_CLASS_QUERY2, springAdapter;
12231
- var init_dist5 = __esm({
12232
- "../adapter-spring/dist/index.js"() {
12233
- "use strict";
12234
- init_adapter();
12235
- HTTP_MAPPING_QUERY = `
12236
- (annotation
12237
- name: (identifier) @method (#match? @method "^(Get|Post|Put|Patch|Delete|Head|Options)Mapping$")
12238
- arguments: (annotation_argument_list
12239
- (string_literal) @route_path))
12240
- `;
12241
- HTTP_MAPPING_NO_ARGS_QUERY = `
12242
- (marker_annotation
12243
- name: (identifier) @method (#match? @method "^(Get|Post|Put|Patch|Delete|Head|Options)Mapping$"))
12244
- `;
12245
- REQUEST_MAPPING_QUERY = `
12246
- (annotation
12247
- name: (identifier) @_name (#eq? @_name "RequestMapping")
12248
- arguments: (annotation_argument_list
12249
- (string_literal) @route_template))
12250
- `;
12251
- CONTROLLER_CLASS_QUERY2 = `
12252
- (class_declaration
12253
- (modifiers
12254
- (marker_annotation
12255
- name: (identifier) @_anno (#match? @_anno "^(RestController|Controller)$")))
12256
- name: (identifier) @class_name)
12257
-
12258
- (class_declaration
12259
- (modifiers
12260
- (annotation
12261
- name: (identifier) @_anno (#match? @_anno "^(RestController|Controller)$")))
12262
- name: (identifier) @class_name)
12263
- `;
12264
- springAdapter = {
12265
- id: "spring",
12266
- languages: ["java"],
12267
- matches(signals) {
12268
- if (signals.pomXml && /\bspring-boot-starter[\w-]*\b/.test(signals.pomXml)) {
12269
- return true;
12270
- }
12271
- if (signals.gradleBuild && /\bspring-boot-starter[\w-]*\b/.test(signals.gradleBuild)) {
12272
- return true;
12273
- }
12274
- if (signals.pomXml && /\borg\.springframework\b/.test(signals.pomXml)) {
12275
- return true;
12276
- }
12277
- if (signals.gradleBuild && /\borg\.springframework\b/.test(signals.gradleBuild)) {
12278
- return true;
12279
- }
12280
- return false;
12281
- },
12282
- async introspect(files, _rootDir) {
12283
- if (files.length === 0) {
12284
- return { conventions: {}, provenance: [], confidence: "none" };
12285
- }
12286
- let language;
12287
- try {
12288
- language = await loadGrammar2("java");
12289
- } catch (e2) {
12290
- return { conventions: {}, provenance: [], confidence: "none" };
12291
- }
12292
- const parser = new Parser12();
12293
- parser.setLanguage(language);
12294
- const routeMethods = /* @__PURE__ */ new Map();
12295
- const prefixBases = /* @__PURE__ */ new Map();
12296
- const controllerClasses = /* @__PURE__ */ new Map();
12297
- try {
12298
- for (const file of files) {
12299
- const skip = isParsableSource2(file.content, file.size);
12300
- if (skip) {
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
- `);
12303
- continue;
12304
- }
12305
- try {
12306
- for (const hit of runQuery2(parser, file.content, HTTP_MAPPING_QUERY, "spring-http-mapping", file.path)) {
12307
- const methodRaw = hit.captures.method;
12308
- if (!methodRaw)
12309
- continue;
12310
- const verb = methodRaw.replace(/Mapping$/, "");
12311
- if (!routeMethods.has(verb)) {
12312
- routeMethods.set(verb, { line: hit.line, file: file.path });
12313
- }
12314
- }
12315
- for (const hit of runQuery2(parser, file.content, HTTP_MAPPING_NO_ARGS_QUERY, "spring-http-mapping-marker", file.path)) {
12316
- const methodRaw = hit.captures.method;
12317
- if (!methodRaw)
12318
- continue;
12319
- const verb = methodRaw.replace(/Mapping$/, "");
12320
- if (!routeMethods.has(verb)) {
12321
- routeMethods.set(verb, { line: hit.line, file: file.path });
12322
- }
12323
- }
12324
- for (const hit of runQuery2(parser, file.content, REQUEST_MAPPING_QUERY, "spring-request-mapping", file.path)) {
12325
- const tplRaw = hit.captures.route_template;
12326
- if (!tplRaw)
12327
- continue;
12328
- const literal = tplRaw.replace(/^["']/, "").replace(/["']$/, "");
12329
- const base = extractPrefixBase7(literal);
12330
- if (base && !prefixBases.has(base)) {
12331
- prefixBases.set(base, { line: hit.line, file: file.path });
12332
- }
12333
- }
12334
- for (const hit of runQuery2(parser, file.content, CONTROLLER_CLASS_QUERY2, "spring-controller-class", file.path)) {
12335
- const name = hit.captures.class_name;
12336
- if (name && !controllerClasses.has(name)) {
12337
- controllerClasses.set(name, { line: hit.line, file: file.path });
12338
- }
12339
- }
12340
- } catch (e2) {
12341
- if (e2 instanceof InvalidQueryError2) {
12342
- throw e2;
12343
- }
12344
- continue;
12345
- }
12346
- }
12347
- } finally {
12348
- try {
12349
- parser.delete();
12350
- } catch {
12351
- }
12352
- }
12353
- const conventions = {};
12354
- const provenance = [];
12355
- if (routeMethods.size === 1) {
12356
- const [name, { line, file }] = routeMethods.entries().next().value;
12357
- conventions.route_method = name;
12358
- provenance.push({ field: "route_method", sourceFile: file, line, query: "spring-http-mapping" });
12359
- } else if (routeMethods.size >= 2) {
12360
- const [name, { line, file }] = routeMethods.entries().next().value;
12361
- conventions.route_method = name;
12362
- provenance.push({ field: "route_method", sourceFile: file, line, query: "spring-http-mapping" });
12363
- }
12364
- if (prefixBases.size >= 1) {
12365
- const [base, { line, file }] = prefixBases.entries().next().value;
12366
- conventions.route_prefix_base = base;
12367
- provenance.push({ field: "route_prefix_base", sourceFile: file, line, query: "spring-request-mapping" });
12368
- }
12369
- if (controllerClasses.size >= 1) {
12370
- const [name, { line, file }] = controllerClasses.entries().next().value;
12371
- conventions.controller_class = name;
12372
- provenance.push({ field: "controller_class", sourceFile: file, line, query: "spring-controller-class" });
12373
- }
12374
- let confidence;
12375
- if (Object.keys(conventions).length === 0) {
12376
- confidence = "none";
12377
- } else if (routeMethods.size === 1) {
12378
- confidence = "high";
12379
- } else if (routeMethods.size >= 2) {
12380
- confidence = "low";
12381
- } else {
12382
- confidence = "medium";
12383
- }
12384
- return { conventions, provenance, confidence };
12385
- }
12386
- };
12387
11191
  }
12388
11192
  });
12389
11193
 
12390
11194
  // src/detect/adapters/spring.ts
11195
+ import { springAdapter } from "@massu/adapter-spring";
12391
11196
  var init_spring = __esm({
12392
11197
  "src/detect/adapters/spring.ts"() {
12393
11198
  "use strict";
12394
- init_dist5();
12395
11199
  }
12396
11200
  });
12397
11201
 
@@ -12402,8 +11206,8 @@ __export(file_sampler_exports, {
12402
11206
  SAMPLE_TEST_FILE_PATTERNS: () => SAMPLE_TEST_FILE_PATTERNS,
12403
11207
  sampleFilesForAdapter: () => sampleFilesForAdapter
12404
11208
  });
12405
- import { readdirSync as readdirSync10, readFileSync as readFileSync10, lstatSync as lstatSync5 } from "node:fs";
12406
- import { join as join10, extname } from "node:path";
11209
+ import { readdirSync as readdirSync9, readFileSync as readFileSync9, lstatSync as lstatSync4 } from "node:fs";
11210
+ import { join as join9, extname } from "node:path";
12407
11211
  function sampleFilesForAdapter(adapter, projectRoot, detection, options = {}) {
12408
11212
  const maxDepth = options.maxDepth ?? DEFAULT_MAX_DEPTH;
12409
11213
  const maxFiles = options.maxFilesPerAdapter ?? DEFAULT_MAX_FILES;
@@ -12418,7 +11222,7 @@ function sampleFilesForAdapter(adapter, projectRoot, detection, options = {}) {
12418
11222
  const langDetection = detection.sourceDirs[langKey];
12419
11223
  const candidateDirs = [];
12420
11224
  if (langDetection?.source_dirs && langDetection.source_dirs.length > 0) {
12421
- candidateDirs.push(...langDetection.source_dirs.map((d2) => join10(projectRoot, d2)));
11225
+ candidateDirs.push(...langDetection.source_dirs.map((d2) => join9(projectRoot, d2)));
12422
11226
  } else {
12423
11227
  candidateDirs.push(projectRoot);
12424
11228
  }
@@ -12434,7 +11238,7 @@ function walkDir(dir, exts, testPatterns, lang, maxDepth, curDepth, out, seen, m
12434
11238
  if (out.length >= maxFiles) return;
12435
11239
  let entries;
12436
11240
  try {
12437
- entries = readdirSync10(dir);
11241
+ entries = readdirSync9(dir);
12438
11242
  } catch {
12439
11243
  return;
12440
11244
  }
@@ -12442,10 +11246,10 @@ function walkDir(dir, exts, testPatterns, lang, maxDepth, curDepth, out, seen, m
12442
11246
  if (out.length >= maxFiles) return;
12443
11247
  if (entry.startsWith(".")) continue;
12444
11248
  if (IGNORED_DIRS3.has(entry)) continue;
12445
- const fullPath = join10(dir, entry);
11249
+ const fullPath = join9(dir, entry);
12446
11250
  let st;
12447
11251
  try {
12448
- st = lstatSync5(fullPath);
11252
+ st = lstatSync4(fullPath);
12449
11253
  } catch {
12450
11254
  continue;
12451
11255
  }
@@ -12463,7 +11267,7 @@ function walkDir(dir, exts, testPatterns, lang, maxDepth, curDepth, out, seen, m
12463
11267
  seen.add(fullPath);
12464
11268
  let content;
12465
11269
  try {
12466
- content = readFileSync10(fullPath, "utf-8");
11270
+ content = readFileSync9(fullPath, "utf-8");
12467
11271
  } catch {
12468
11272
  continue;
12469
11273
  }
@@ -12701,7 +11505,7 @@ var init_detect = __esm({
12701
11505
  });
12702
11506
 
12703
11507
  // src/detect/drift.ts
12704
- import { createHash as createHash4 } from "crypto";
11508
+ import { createHash as createHash3 } from "crypto";
12705
11509
  function summarizeDetection(det) {
12706
11510
  const languages = Array.from(new Set(det.manifests.map((m3) => m3.language))).sort();
12707
11511
  const frameworks = {};
@@ -12732,7 +11536,7 @@ function summarizeDetection(det) {
12732
11536
  function computeFingerprint(det) {
12733
11537
  const data = summarizeDetection(det);
12734
11538
  const stable = JSON.stringify(data, Object.keys(data).sort());
12735
- return createHash4("sha256").update(stable).digest("hex");
11539
+ return createHash3("sha256").update(stable).digest("hex");
12736
11540
  }
12737
11541
  function stringOf(v3) {
12738
11542
  if (typeof v3 === "string") return v3;
@@ -13082,7 +11886,7 @@ function cD({ input: t = $, output: u2 = j, overwrite: F = true, hideCursor: e2
13082
11886
  };
13083
11887
  }
13084
11888
  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;
13085
- var init_dist6 = __esm({
11889
+ var init_dist = __esm({
13086
11890
  "../../node_modules/@clack/core/dist/index.mjs"() {
13087
11891
  import_sisteransi = __toESM(require_src(), 1);
13088
11892
  import_picocolors = __toESM(require_picocolors(), 1);
@@ -13500,10 +12304,10 @@ function X2() {
13500
12304
  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";
13501
12305
  }
13502
12306
  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;
13503
- var init_dist7 = __esm({
12307
+ var init_dist2 = __esm({
13504
12308
  "../../node_modules/@clack/prompts/dist/index.mjs"() {
13505
- init_dist6();
13506
- init_dist6();
12309
+ init_dist();
12310
+ init_dist();
13507
12311
  import_picocolors2 = __toESM(require_picocolors(), 1);
13508
12312
  import_sisteransi2 = __toESM(require_src(), 1);
13509
12313
  E = X2();
@@ -13891,10 +12695,10 @@ __export(init_exports, {
13891
12695
  validateWrittenConfig: () => validateWrittenConfig,
13892
12696
  writeConfigAtomic: () => writeConfigAtomic
13893
12697
  });
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";
12698
+ 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";
12699
+ import { resolve as resolve6, basename as basename4, dirname as dirname5 } from "path";
13896
12700
  import { fileURLToPath as fileURLToPath2 } from "url";
13897
- import { homedir as homedir4 } from "os";
12701
+ import { homedir as homedir3 } from "os";
13898
12702
  import { stringify as yamlStringify, parse as yamlParse } from "yaml";
13899
12703
  function detectFramework(projectRoot) {
13900
12704
  const result = {
@@ -13906,7 +12710,7 @@ function detectFramework(projectRoot) {
13906
12710
  const pkgPath = resolve6(projectRoot, "package.json");
13907
12711
  if (!existsSync10(pkgPath)) return result;
13908
12712
  try {
13909
- const pkg = JSON.parse(readFileSync11(pkgPath, "utf-8"));
12713
+ const pkg = JSON.parse(readFileSync10(pkgPath, "utf-8"));
13910
12714
  const allDeps = {
13911
12715
  ...pkg.dependencies,
13912
12716
  ...pkg.devDependencies
@@ -13953,7 +12757,7 @@ function detectPython(projectRoot) {
13953
12757
  const filePath = resolve6(projectRoot, file);
13954
12758
  if (existsSync10(filePath)) {
13955
12759
  try {
13956
- const content = readFileSync11(filePath, "utf-8").toLowerCase();
12760
+ const content = readFileSync10(filePath, "utf-8").toLowerCase();
13957
12761
  if (content.includes("fastapi")) result.hasFastapi = true;
13958
12762
  if (content.includes("sqlalchemy")) result.hasSqlalchemy = true;
13959
12763
  } catch {
@@ -13978,7 +12782,7 @@ function detectPython(projectRoot) {
13978
12782
  }
13979
12783
  if (existsSync10(candidatePath)) {
13980
12784
  try {
13981
- const files = readdirSync11(candidatePath);
12785
+ const files = readdirSync10(candidatePath);
13982
12786
  if (files.some((f2) => f2.endsWith(".py"))) {
13983
12787
  result.root = candidate;
13984
12788
  break;
@@ -14043,7 +12847,7 @@ function generateConfig(projectRoot, framework) {
14043
12847
  # Documentation: https://massu.ai/docs/getting-started/configuration
14044
12848
 
14045
12849
  ${yamlStringify(config)}`;
14046
- writeFileSync3(configPath, yamlContent, "utf-8");
12850
+ writeFileSync2(configPath, yamlContent, "utf-8");
14047
12851
  return true;
14048
12852
  }
14049
12853
  function monorepoCommonRoot(packages) {
@@ -14214,7 +13018,7 @@ function applyVariantTemplate(config, templatesDir) {
14214
13018
  if (!existsSync10(templatePath)) return config;
14215
13019
  let template;
14216
13020
  try {
14217
- template = yamlParse(readFileSync11(templatePath, "utf-8"));
13021
+ template = yamlParse(readFileSync10(templatePath, "utf-8"));
14218
13022
  } catch {
14219
13023
  return config;
14220
13024
  }
@@ -14281,7 +13085,7 @@ function writeConfigAtomic(configPath, content) {
14281
13085
  }
14282
13086
  }
14283
13087
  try {
14284
- mkdirSync5(dirname6(configPath), { recursive: true });
13088
+ mkdirSync4(dirname5(configPath), { recursive: true });
14285
13089
  const fd = openSync2(tmpPath, "w", 420);
14286
13090
  try {
14287
13091
  const buf = Buffer.from(content, "utf-8");
@@ -14294,10 +13098,10 @@ function writeConfigAtomic(configPath, content) {
14294
13098
  if (parsed === null || typeof parsed !== "object") {
14295
13099
  throw new Error("Generated config is not a valid YAML object");
14296
13100
  }
14297
- renameSync4(tmpPath, configPath);
13101
+ renameSync3(tmpPath, configPath);
14298
13102
  if (existingMode !== void 0) {
14299
13103
  try {
14300
- chmodSync3(configPath, existingMode);
13104
+ chmodSync2(configPath, existingMode);
14301
13105
  } catch {
14302
13106
  }
14303
13107
  }
@@ -14315,7 +13119,7 @@ function writeConfigAtomic(configPath, content) {
14315
13119
  function validateWrittenConfig(configPath, projectRoot, checkPaths = true) {
14316
13120
  try {
14317
13121
  if (!existsSync10(configPath)) return "Config file does not exist after write";
14318
- const content = readFileSync11(configPath, "utf-8");
13122
+ const content = readFileSync10(configPath, "utf-8");
14319
13123
  const parsed = yamlParse(content);
14320
13124
  if (parsed === null || typeof parsed !== "object") {
14321
13125
  return "Config is not a valid YAML object";
@@ -14416,9 +13220,9 @@ function copyTemplateConfig(templateName, targetPath, projectName) {
14416
13220
  return { success: false, error: `Template '${templateName}' not found at ${srcPath}` };
14417
13221
  }
14418
13222
  try {
14419
- let content = readFileSync11(srcPath, "utf-8");
13223
+ let content = readFileSync10(srcPath, "utf-8");
14420
13224
  content = content.replace(/\{\{PROJECT_NAME\}\}/g, projectName);
14421
- writeFileSync3(targetPath, content, "utf-8");
13225
+ writeFileSync2(targetPath, content, "utf-8");
14422
13226
  return { success: true };
14423
13227
  } catch (err) {
14424
13228
  return { success: false, error: err instanceof Error ? err.message : String(err) };
@@ -14429,7 +13233,7 @@ function registerMcpServer(projectRoot) {
14429
13233
  let existing = {};
14430
13234
  if (existsSync10(mcpPath)) {
14431
13235
  try {
14432
- existing = JSON.parse(readFileSync11(mcpPath, "utf-8"));
13236
+ existing = JSON.parse(readFileSync10(mcpPath, "utf-8"));
14433
13237
  } catch {
14434
13238
  existing = {};
14435
13239
  }
@@ -14444,7 +13248,7 @@ function registerMcpServer(projectRoot) {
14444
13248
  args: ["-y", "@massu/core"]
14445
13249
  };
14446
13250
  existing.mcpServers = servers;
14447
- writeFileSync3(mcpPath, JSON.stringify(existing, null, 2) + "\n", "utf-8");
13251
+ writeFileSync2(mcpPath, JSON.stringify(existing, null, 2) + "\n", "utf-8");
14448
13252
  return true;
14449
13253
  }
14450
13254
  function resolveHooksDir() {
@@ -14549,12 +13353,12 @@ function installHooks(projectRoot) {
14549
13353
  const claudeDir = resolve6(projectRoot, claudeDirName);
14550
13354
  const settingsPath = resolve6(claudeDir, "settings.local.json");
14551
13355
  if (!existsSync10(claudeDir)) {
14552
- mkdirSync5(claudeDir, { recursive: true });
13356
+ mkdirSync4(claudeDir, { recursive: true });
14553
13357
  }
14554
13358
  let settings = {};
14555
13359
  if (existsSync10(settingsPath)) {
14556
13360
  try {
14557
- settings = JSON.parse(readFileSync11(settingsPath, "utf-8"));
13361
+ settings = JSON.parse(readFileSync10(settingsPath, "utf-8"));
14558
13362
  } catch {
14559
13363
  settings = {};
14560
13364
  }
@@ -14568,15 +13372,15 @@ function installHooks(projectRoot) {
14568
13372
  }
14569
13373
  }
14570
13374
  settings.hooks = hooksConfig;
14571
- writeFileSync3(settingsPath, JSON.stringify(settings, null, 2) + "\n", "utf-8");
13375
+ writeFileSync2(settingsPath, JSON.stringify(settings, null, 2) + "\n", "utf-8");
14572
13376
  return { installed: true, count: hookCount };
14573
13377
  }
14574
13378
  function initMemoryDir(projectRoot) {
14575
13379
  const encodedRoot = "-" + projectRoot.replace(/\//g, "-");
14576
- const memoryDir = resolve6(homedir4(), `.claude/projects/${encodedRoot}/memory`);
13380
+ const memoryDir = resolve6(homedir3(), `.claude/projects/${encodedRoot}/memory`);
14577
13381
  let created = false;
14578
13382
  if (!existsSync10(memoryDir)) {
14579
- mkdirSync5(memoryDir, { recursive: true });
13383
+ mkdirSync4(memoryDir, { recursive: true });
14580
13384
  created = true;
14581
13385
  }
14582
13386
  const memoryMdPath = resolve6(memoryDir, "MEMORY.md");
@@ -14597,7 +13401,7 @@ function initMemoryDir(projectRoot) {
14597
13401
  ## File Index
14598
13402
  <!-- Significant files and directories -->
14599
13403
  `;
14600
- writeFileSync3(memoryMdPath, memoryContent, "utf-8");
13404
+ writeFileSync2(memoryMdPath, memoryContent, "utf-8");
14601
13405
  memoryMdCreated = true;
14602
13406
  }
14603
13407
  return { created, memoryMdCreated };
@@ -14849,8 +13653,8 @@ function installSideEffects(projectRoot, log, skipCommands = false, emptyStack =
14849
13653
  "\u2014 Massu"
14850
13654
  ].join("\n");
14851
13655
  try {
14852
- mkdirSync5(resolve6(cmdResult.claudeDir, "commands"), { recursive: true });
14853
- writeFileSync3(placeholderPath, placeholderBody, "utf-8");
13656
+ mkdirSync4(resolve6(cmdResult.claudeDir, "commands"), { recursive: true });
13657
+ writeFileSync2(placeholderPath, placeholderBody, "utf-8");
14854
13658
  log(" Wrote _massu-needs-stack.md placeholder (no stack detected yet)");
14855
13659
  } catch {
14856
13660
  }
@@ -14869,8 +13673,8 @@ function installSideEffects(projectRoot, log, skipCommands = false, emptyStack =
14869
13673
  (async () => {
14870
13674
  try {
14871
13675
  const encodedRoot = projectRoot.replace(/\//g, "-");
14872
- const memoryDir = resolve6(homedir4(), ".claude", "projects", encodedRoot, "memory");
14873
- const memFiles = existsSync10(memoryDir) ? readdirSync11(memoryDir).filter((f2) => f2.endsWith(".md") && f2 !== "MEMORY.md") : [];
13676
+ const memoryDir = resolve6(homedir3(), ".claude", "projects", encodedRoot, "memory");
13677
+ const memFiles = existsSync10(memoryDir) ? readdirSync10(memoryDir).filter((f2) => f2.endsWith(".md") && f2 !== "MEMORY.md") : [];
14874
13678
  if (memFiles.length > 0) {
14875
13679
  const { getMemoryDb: getMemoryDb2 } = await Promise.resolve().then(() => (init_memory_db(), memory_db_exports));
14876
13680
  const db = getMemoryDb2();
@@ -14893,7 +13697,7 @@ function installSideEffects(projectRoot, log, skipCommands = false, emptyStack =
14893
13697
  }
14894
13698
  async function promptOverwrite(configPath) {
14895
13699
  try {
14896
- const { confirm, isCancel } = await Promise.resolve().then(() => (init_dist7(), dist_exports));
13700
+ const { confirm, isCancel } = await Promise.resolve().then(() => (init_dist2(), dist_exports));
14897
13701
  const res = await confirm({
14898
13702
  message: `massu.config.yaml already exists at ${configPath}. Overwrite?`,
14899
13703
  initialValue: false
@@ -14906,7 +13710,7 @@ async function promptOverwrite(configPath) {
14906
13710
  }
14907
13711
  async function promptStackConfirm() {
14908
13712
  try {
14909
- const { confirm, isCancel } = await Promise.resolve().then(() => (init_dist7(), dist_exports));
13713
+ const { confirm, isCancel } = await Promise.resolve().then(() => (init_dist2(), dist_exports));
14910
13714
  const res = await confirm({
14911
13715
  message: "Generate massu.config.yaml from detected stack?",
14912
13716
  initialValue: true
@@ -14930,7 +13734,7 @@ var init_init = __esm({
14930
13734
  init_detect();
14931
13735
  init_drift();
14932
13736
  __filename2 = fileURLToPath2(import.meta.url);
14933
- __dirname2 = dirname6(__filename2);
13737
+ __dirname2 = dirname5(__filename2);
14934
13738
  FRAMEWORK_TO_TEMPLATE_ID = {
14935
13739
  rails: "rails",
14936
13740
  phoenix: "phoenix",
@@ -14952,7 +13756,7 @@ var init_init = __esm({
14952
13756
  });
14953
13757
 
14954
13758
  // src/license.ts
14955
- import { createHash as createHash5 } from "crypto";
13759
+ import { createHash as createHash4 } from "crypto";
14956
13760
  function tierLevel(tier) {
14957
13761
  return TIER_LEVELS[tier] ?? 0;
14958
13762
  }
@@ -14977,7 +13781,7 @@ function annotateToolDefinitions(defs) {
14977
13781
  });
14978
13782
  }
14979
13783
  async function validateLicense(apiKey) {
14980
- const keyHash = createHash5("sha256").update(apiKey).digest("hex");
13784
+ const keyHash = createHash4("sha256").update(apiKey).digest("hex");
14981
13785
  const memDb = getMemoryDb();
14982
13786
  try {
14983
13787
  const cached = memDb.prepare(
@@ -15038,7 +13842,7 @@ async function validateLicense(apiKey) {
15038
13842
  }
15039
13843
  }
15040
13844
  function updateLicenseCache(apiKey, tier, validUntil, features = []) {
15041
- const keyHash = createHash5("sha256").update(apiKey).digest("hex");
13845
+ const keyHash = createHash4("sha256").update(apiKey).digest("hex");
15042
13846
  const memDb = getMemoryDb();
15043
13847
  try {
15044
13848
  memDb.prepare(`
@@ -15246,8 +14050,8 @@ __export(doctor_exports, {
15246
14050
  runDoctor: () => runDoctor,
15247
14051
  runValidateConfig: () => runValidateConfig
15248
14052
  });
15249
- import { existsSync as existsSync11, readFileSync as readFileSync12, readdirSync as readdirSync12 } from "fs";
15250
- import { resolve as resolve7, dirname as dirname7 } from "path";
14053
+ import { existsSync as existsSync11, readFileSync as readFileSync11, readdirSync as readdirSync11 } from "fs";
14054
+ import { resolve as resolve7, dirname as dirname6 } from "path";
15251
14055
  import { fileURLToPath as fileURLToPath3 } from "url";
15252
14056
  import { parse as parseYaml4 } from "yaml";
15253
14057
  function checkConfig(projectRoot) {
@@ -15256,7 +14060,7 @@ function checkConfig(projectRoot) {
15256
14060
  return { name: "Configuration", status: "fail", detail: "massu.config.yaml not found. Run: npx massu init" };
15257
14061
  }
15258
14062
  try {
15259
- const content = readFileSync12(configPath, "utf-8");
14063
+ const content = readFileSync11(configPath, "utf-8");
15260
14064
  const parsed = parseYaml4(content);
15261
14065
  if (!parsed || typeof parsed !== "object") {
15262
14066
  return { name: "Configuration", status: "fail", detail: "massu.config.yaml is empty or invalid YAML" };
@@ -15272,7 +14076,7 @@ function checkMcpServer(projectRoot) {
15272
14076
  return { name: "MCP Server", status: "fail", detail: ".mcp.json not found. Run: npx massu init" };
15273
14077
  }
15274
14078
  try {
15275
- const content = JSON.parse(readFileSync12(mcpPath, "utf-8"));
14079
+ const content = JSON.parse(readFileSync11(mcpPath, "utf-8"));
15276
14080
  const servers = content.mcpServers ?? {};
15277
14081
  if (!servers.massu) {
15278
14082
  return { name: "MCP Server", status: "fail", detail: "massu not registered in .mcp.json. Run: npx massu init" };
@@ -15288,7 +14092,7 @@ function checkHooksConfig(projectRoot) {
15288
14092
  return { name: "Hooks Config", status: "fail", detail: ".claude/settings.local.json not found. Run: npx massu init" };
15289
14093
  }
15290
14094
  try {
15291
- const content = JSON.parse(readFileSync12(settingsPath, "utf-8"));
14095
+ const content = JSON.parse(readFileSync11(settingsPath, "utf-8"));
15292
14096
  if (!content.hooks) {
15293
14097
  return { name: "Hooks Config", status: "fail", detail: "No hooks configured. Run: npx massu install-hooks" };
15294
14098
  }
@@ -15399,7 +14203,7 @@ function checkShellHooksWired(_projectRoot2) {
15399
14203
  };
15400
14204
  }
15401
14205
  try {
15402
- const content = JSON.parse(readFileSync12(settingsPath, "utf-8"));
14206
+ const content = JSON.parse(readFileSync11(settingsPath, "utf-8"));
15403
14207
  const hooks = content.hooks ?? {};
15404
14208
  const hasSessionStart = Array.isArray(hooks.SessionStart) && hooks.SessionStart.length > 0;
15405
14209
  const hasPreToolUse = Array.isArray(hooks.PreToolUse) && hooks.PreToolUse.length > 0;
@@ -15465,7 +14269,7 @@ function checkPythonHealth(projectRoot) {
15465
14269
  function scanDir(dir, depth) {
15466
14270
  if (depth > 5) return;
15467
14271
  try {
15468
- const entries = readdirSync12(dir, { withFileTypes: true });
14272
+ const entries = readdirSync11(dir, { withFileTypes: true });
15469
14273
  for (const entry of entries) {
15470
14274
  if (entry.isDirectory()) {
15471
14275
  const excludeDirs = config.python?.exclude_dirs || ["__pycache__", ".venv", "venv", ".mypy_cache", ".pytest_cache"];
@@ -15473,7 +14277,7 @@ function checkPythonHealth(projectRoot) {
15473
14277
  const subdir = resolve7(dir, entry.name);
15474
14278
  if (depth <= 2 && !existsSync11(resolve7(subdir, "__init__.py"))) {
15475
14279
  try {
15476
- const subEntries = readdirSync12(subdir);
14280
+ const subEntries = readdirSync11(subdir);
15477
14281
  if (subEntries.some((f2) => f2.endsWith(".py") && f2 !== "__init__.py")) {
15478
14282
  initPyMissing.push(entry.name);
15479
14283
  }
@@ -15574,7 +14378,7 @@ async function runValidateConfig() {
15574
14378
  return;
15575
14379
  }
15576
14380
  try {
15577
- const content = readFileSync12(configPath, "utf-8");
14381
+ const content = readFileSync11(configPath, "utf-8");
15578
14382
  const parsed = parseYaml4(content);
15579
14383
  if (!parsed || typeof parsed !== "object") {
15580
14384
  console.error("Error: massu.config.yaml is empty or not a valid YAML object");
@@ -15613,7 +14417,7 @@ var init_doctor = __esm({
15613
14417
  init_config();
15614
14418
  init_license();
15615
14419
  __filename3 = fileURLToPath3(import.meta.url);
15616
- __dirname3 = dirname7(__filename3);
14420
+ __dirname3 = dirname6(__filename3);
15617
14421
  EXPECTED_HOOKS = [
15618
14422
  "session-start.js",
15619
14423
  "session-end.js",
@@ -15659,7 +14463,7 @@ var show_template_exports = {};
15659
14463
  __export(show_template_exports, {
15660
14464
  runShowTemplate: () => runShowTemplate
15661
14465
  });
15662
- import { existsSync as existsSync12, readFileSync as readFileSync13 } from "fs";
14466
+ import { existsSync as existsSync12, readFileSync as readFileSync12 } from "fs";
15663
14467
  import { resolve as resolve8 } from "path";
15664
14468
  function normalizeBaseName(input) {
15665
14469
  return input.endsWith(".md") ? input.slice(0, -".md".length) : input;
@@ -15695,7 +14499,7 @@ async function runShowTemplate(args2) {
15695
14499
  process.exit(1);
15696
14500
  return;
15697
14501
  }
15698
- process.stdout.write(readFileSync13(file, "utf-8"));
14502
+ process.stdout.write(readFileSync12(file, "utf-8"));
15699
14503
  }
15700
14504
  var init_show_template = __esm({
15701
14505
  "src/commands/show-template.ts"() {
@@ -15748,12 +14552,12 @@ var init_passthrough = __esm({
15748
14552
  });
15749
14553
 
15750
14554
  // src/lib/fileLock.ts
15751
- import { mkdirSync as mkdirSync6, readFileSync as readFileSync14, rmSync as rmSync3, writeFileSync as writeFileSync4 } from "fs";
15752
- import { dirname as dirname8 } from "path";
14555
+ import { mkdirSync as mkdirSync5, readFileSync as readFileSync13, rmSync as rmSync3, writeFileSync as writeFileSync3 } from "fs";
14556
+ import { dirname as dirname7 } from "path";
15753
14557
  import * as lockfile from "proper-lockfile";
15754
14558
  function readLockHolderPid(lockPath) {
15755
14559
  try {
15756
- const raw = readFileSync14(`${lockPath}.pid`, "utf-8").trim();
14560
+ const raw = readFileSync13(`${lockPath}.pid`, "utf-8").trim();
15757
14561
  const pid = Number.parseInt(raw, 10);
15758
14562
  if (!Number.isFinite(pid) || pid <= 0) return null;
15759
14563
  return pid;
@@ -15772,7 +14576,7 @@ function busyWaitSync(ms) {
15772
14576
  Atomics.wait(view, 0, 0, ms);
15773
14577
  }
15774
14578
  function withFileLockSync(lockPath, fn, opts = {}) {
15775
- mkdirSync6(dirname8(lockPath), { recursive: true });
14579
+ mkdirSync5(dirname7(lockPath), { recursive: true });
15776
14580
  const staleMs = opts.staleMs ?? 3e4;
15777
14581
  const blockMs = opts.retries === 0 ? 0 : opts.blockMs ?? 3e4;
15778
14582
  const pollIntervalMs = opts.pollIntervalMs ?? 100;
@@ -15789,7 +14593,7 @@ function withFileLockSync(lockPath, fn, opts = {}) {
15789
14593
  realpath: false
15790
14594
  });
15791
14595
  try {
15792
- writeFileSync4(`${lockPath}.pid`, String(process.pid), "utf-8");
14596
+ writeFileSync3(`${lockPath}.pid`, String(process.pid), "utf-8");
15793
14597
  } catch {
15794
14598
  }
15795
14599
  break;
@@ -15878,7 +14682,7 @@ __export(config_refresh_exports, {
15878
14682
  mergeRefresh: () => mergeRefresh,
15879
14683
  runConfigRefresh: () => runConfigRefresh
15880
14684
  });
15881
- import { existsSync as existsSync13, readFileSync as readFileSync15, rmSync as rmSync4 } from "fs";
14685
+ import { existsSync as existsSync13, readFileSync as readFileSync14, rmSync as rmSync4 } from "fs";
15882
14686
  import { resolve as resolve10 } from "path";
15883
14687
  import { parse as parseYaml5 } from "yaml";
15884
14688
  function flatten(obj, prefix3 = "") {
@@ -16017,7 +14821,7 @@ async function runConfigRefresh(opts = {}) {
16017
14821
  }
16018
14822
  let existing;
16019
14823
  try {
16020
- const content = readFileSync15(configPath, "utf-8");
14824
+ const content = readFileSync14(configPath, "utf-8");
16021
14825
  const parsed = parseYaml5(content);
16022
14826
  if (!parsed || typeof parsed !== "object") {
16023
14827
  throw new Error("config is not a YAML object");
@@ -16062,7 +14866,7 @@ async function runConfigRefresh(opts = {}) {
16062
14866
  }
16063
14867
  log("Config diff:\n");
16064
14868
  log(renderDiff(diff));
16065
- const { confirm } = await Promise.resolve().then(() => (init_dist7(), dist_exports));
14869
+ const { confirm } = await Promise.resolve().then(() => (init_dist2(), dist_exports));
16066
14870
  const apply = await confirm({ message: "Apply these changes to massu.config.yaml?" });
16067
14871
  if (apply !== true) {
16068
14872
  log("Aborted; no changes written.\n");
@@ -16415,8 +15219,8 @@ var init_paths = __esm({
16415
15219
  });
16416
15220
 
16417
15221
  // src/watch/state.ts
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";
15222
+ 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";
15223
+ import { dirname as dirname8, resolve as resolve12 } from "path";
16420
15224
  function watchStatePath(projectRoot) {
16421
15225
  return resolve12(projectRoot, ".massu", "watch-state.json");
16422
15226
  }
@@ -16426,7 +15230,7 @@ function backupStatePath(projectRoot) {
16426
15230
  function readState(projectRoot) {
16427
15231
  const path = watchStatePath(projectRoot);
16428
15232
  if (!existsSync15(path)) return { ...DEFAULT_STATE };
16429
- const content = readFileSync16(path, "utf-8");
15233
+ const content = readFileSync15(path, "utf-8");
16430
15234
  let raw;
16431
15235
  try {
16432
15236
  raw = JSON.parse(content);
@@ -16468,14 +15272,14 @@ function readState(projectRoot) {
16468
15272
  }
16469
15273
  function archiveCorrupt(projectRoot, content) {
16470
15274
  const bak = backupStatePath(projectRoot);
16471
- mkdirSync7(dirname9(bak), { recursive: true });
16472
- writeFileSync5(bak, content, "utf-8");
15275
+ mkdirSync6(dirname8(bak), { recursive: true });
15276
+ writeFileSync4(bak, content, "utf-8");
16473
15277
  }
16474
15278
  function writeStateAtomic(projectRoot, state) {
16475
15279
  const path = watchStatePath(projectRoot);
16476
15280
  writeStateAtomicCounter = writeStateAtomicCounter + 1 >>> 0;
16477
15281
  const tmp = `${path}.${process.pid}.${writeStateAtomicCounter}.tmp`;
16478
- mkdirSync7(dirname9(path), { recursive: true });
15282
+ mkdirSync6(dirname8(path), { recursive: true });
16479
15283
  let renamed = false;
16480
15284
  try {
16481
15285
  const fd = openSync3(tmp, "w");
@@ -16486,7 +15290,7 @@ function writeStateAtomic(projectRoot, state) {
16486
15290
  } finally {
16487
15291
  closeSync3(fd);
16488
15292
  }
16489
- renameSync5(tmp, path);
15293
+ renameSync4(tmp, path);
16490
15294
  renamed = true;
16491
15295
  } finally {
16492
15296
  if (!renamed && existsSync15(tmp)) {
@@ -16769,8 +15573,8 @@ __export(watch_exports, {
16769
15573
  runWatch: () => runWatch
16770
15574
  });
16771
15575
  import { spawnSync as spawnSync3 } from "child_process";
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";
15576
+ import { basename as basename5, dirname as dirname9, resolve as resolve13 } from "path";
15577
+ import { appendFileSync, existsSync as existsSync16, mkdirSync as mkdirSync7, readFileSync as readFileSync16 } from "fs";
16774
15578
  function parseFlags(args2) {
16775
15579
  const out = {
16776
15580
  foreground: false,
@@ -17015,7 +15819,7 @@ function refreshLogPath(projectRoot) {
17015
15819
  function appendRefreshLog(projectRoot, event) {
17016
15820
  const path = refreshLogPath(projectRoot);
17017
15821
  try {
17018
- mkdirSync8(dirname10(path), { recursive: true });
15822
+ mkdirSync7(dirname9(path), { recursive: true });
17019
15823
  appendFileSync(path, JSON.stringify(event) + "\n", "utf-8");
17020
15824
  } catch {
17021
15825
  }
@@ -17026,7 +15830,7 @@ function readRefreshLog(projectRoot, limit = 10, opts = {}) {
17026
15830
  const warn = opts.warn ?? ((s) => {
17027
15831
  process.stderr.write(s);
17028
15832
  });
17029
- const lines = readFileSync17(path, "utf-8").split("\n").filter(Boolean);
15833
+ const lines = readFileSync16(path, "utf-8").split("\n").filter(Boolean);
17030
15834
  const tail = lines.slice(-limit);
17031
15835
  const out = [];
17032
15836
  let corrupt = 0;
@@ -17097,28 +15901,28 @@ var init_refresh_log = __esm({
17097
15901
 
17098
15902
  // src/security/atomic-write.ts
17099
15903
  import {
17100
- chmodSync as chmodSync4,
15904
+ chmodSync as chmodSync3,
17101
15905
  closeSync as closeSync4,
17102
15906
  existsSync as existsSync17,
17103
15907
  fsyncSync as fsyncSync4,
17104
- mkdirSync as mkdirSync9,
15908
+ mkdirSync as mkdirSync8,
17105
15909
  openSync as openSync4,
17106
- renameSync as renameSync6,
15910
+ renameSync as renameSync5,
17107
15911
  rmSync as rmSync6,
17108
15912
  statSync as statSync9,
17109
15913
  writeSync as writeSync4
17110
15914
  } from "node:fs";
17111
- import { dirname as dirname11 } from "node:path";
15915
+ import { dirname as dirname10 } from "node:path";
17112
15916
  function atomicWrite(path, content, opts = {}) {
17113
15917
  const tmpPath = `${path}.tmp`;
17114
- const parentDir = dirname11(path);
15918
+ const parentDir = dirname10(path);
17115
15919
  try {
17116
15920
  if (!existsSync17(parentDir)) {
17117
15921
  const mkdirOpts = { recursive: true };
17118
15922
  if (opts.ensureParentDirMode !== void 0) {
17119
15923
  mkdirOpts.mode = opts.ensureParentDirMode;
17120
15924
  }
17121
- mkdirSync9(parentDir, mkdirOpts);
15925
+ mkdirSync8(parentDir, mkdirOpts);
17122
15926
  }
17123
15927
  const buf = typeof content === "string" ? Buffer.from(content, "utf-8") : content;
17124
15928
  const openMode = opts.mode ?? 420;
@@ -17130,9 +15934,9 @@ function atomicWrite(path, content, opts = {}) {
17130
15934
  closeSync4(fd);
17131
15935
  }
17132
15936
  if (opts.mode !== void 0) {
17133
- chmodSync4(tmpPath, opts.mode);
15937
+ chmodSync3(tmpPath, opts.mode);
17134
15938
  }
17135
- renameSync6(tmpPath, path);
15939
+ renameSync5(tmpPath, path);
17136
15940
  return { written: true };
17137
15941
  } catch (err) {
17138
15942
  if (existsSync17(tmpPath)) {
@@ -17215,10 +16019,10 @@ var init_registry_pubkey_generated = __esm({
17215
16019
  });
17216
16020
 
17217
16021
  // src/security/adapter-verifier.ts
17218
- import { createHash as createHash6 } from "node:crypto";
16022
+ import { createHash as createHash5 } from "node:crypto";
17219
16023
  import nacl from "tweetnacl";
17220
16024
  function sha256Hex(bytes) {
17221
- return createHash6("sha256").update(bytes).digest("hex");
16025
+ return createHash5("sha256").update(bytes).digest("hex");
17222
16026
  }
17223
16027
  function reviver(key, value) {
17224
16028
  if (key === "__proto__" || key === "constructor" || key === "prototype") {
@@ -17478,12 +16282,12 @@ var init_fetcher = __esm({
17478
16282
  });
17479
16283
 
17480
16284
  // src/security/manifest-cache.ts
17481
- import { existsSync as existsSync18, readFileSync as readFileSync18, statSync as statSync10 } from "node:fs";
17482
- import { homedir as homedir5 } from "node:os";
16285
+ import { existsSync as existsSync18, readFileSync as readFileSync17, statSync as statSync10 } from "node:fs";
16286
+ import { homedir as homedir4 } from "node:os";
17483
16287
  import { resolve as resolve14 } from "node:path";
17484
16288
  import { z as z4 } from "zod";
17485
16289
  function defaultCachePaths() {
17486
- const dir = resolve14(homedir5(), ".massu");
16290
+ const dir = resolve14(homedir4(), ".massu");
17487
16291
  return {
17488
16292
  cachePath: resolve14(dir, "adapter-manifest.json"),
17489
16293
  lockPath: resolve14(dir, ".adapter-manifest.lock")
@@ -17495,7 +16299,7 @@ function loadCachedManifest(paths = defaultCachePaths()) {
17495
16299
  }
17496
16300
  let raw;
17497
16301
  try {
17498
- const content = readFileSync18(paths.cachePath, "utf-8");
16302
+ const content = readFileSync17(paths.cachePath, "utf-8");
17499
16303
  raw = JSON.parse(content);
17500
16304
  } catch (err) {
17501
16305
  return {
@@ -17684,10 +16488,10 @@ var init_adapter_origin = __esm({
17684
16488
  });
17685
16489
 
17686
16490
  // src/security/local-fingerprint.ts
17687
- import { existsSync as existsSync19, readFileSync as readFileSync19, lstatSync as lstatSync6 } from "node:fs";
17688
- import { homedir as homedir6 } from "node:os";
16491
+ import { existsSync as existsSync19, readFileSync as readFileSync18, lstatSync as lstatSync5 } from "node:fs";
16492
+ import { homedir as homedir5 } from "node:os";
17689
16493
  import { resolve as resolve15, isAbsolute } from "node:path";
17690
- import { createHash as createHash7 } from "node:crypto";
16494
+ import { createHash as createHash6 } from "node:crypto";
17691
16495
  import { z as z5 } from "zod";
17692
16496
  function computeLocalFingerprint(localPaths, projectRoot) {
17693
16497
  const tuples = [];
@@ -17695,13 +16499,13 @@ function computeLocalFingerprint(localPaths, projectRoot) {
17695
16499
  const abs = isAbsolute(p19) ? p19 : resolve15(projectRoot, p19);
17696
16500
  let contentTag;
17697
16501
  try {
17698
- const lst = lstatSync6(abs);
16502
+ const lst = lstatSync5(abs);
17699
16503
  if (lst.isSymbolicLink()) {
17700
16504
  contentTag = "<symlink>";
17701
16505
  } else if (!lst.isFile()) {
17702
16506
  contentTag = "<not-a-file>";
17703
16507
  } else {
17704
- contentTag = createHash7("sha256").update(readFileSync19(abs)).digest("hex");
16508
+ contentTag = createHash6("sha256").update(readFileSync18(abs)).digest("hex");
17705
16509
  }
17706
16510
  } catch {
17707
16511
  contentTag = "<missing>";
@@ -17710,13 +16514,13 @@ function computeLocalFingerprint(localPaths, projectRoot) {
17710
16514
  }
17711
16515
  tuples.sort((a2, b2) => a2.path < b2.path ? -1 : a2.path > b2.path ? 1 : 0);
17712
16516
  const canonical = JSON.stringify(tuples);
17713
- return createHash7("sha256").update(canonical).digest("hex");
16517
+ return createHash6("sha256").update(canonical).digest("hex");
17714
16518
  }
17715
16519
  function readFingerprintSentinel(path = FINGERPRINT_PATH) {
17716
16520
  if (!existsSync19(path)) return null;
17717
16521
  let raw;
17718
16522
  try {
17719
- raw = JSON.parse(readFileSync19(path, "utf-8"));
16523
+ raw = JSON.parse(readFileSync18(path, "utf-8"));
17720
16524
  } catch {
17721
16525
  return null;
17722
16526
  }
@@ -17764,7 +16568,7 @@ var init_local_fingerprint = __esm({
17764
16568
  "use strict";
17765
16569
  init_atomic_write();
17766
16570
  init_manifest_schema();
17767
- FINGERPRINT_PATH = resolve15(homedir6(), ".massu", "adapters-local-fingerprint.json");
16571
+ FINGERPRINT_PATH = resolve15(homedir5(), ".massu", "adapters-local-fingerprint.json");
17768
16572
  FingerprintSentinelSchema = z5.object({
17769
16573
  fingerprint: z5.string().regex(/^[0-9a-f]{64}$/),
17770
16574
  source: z5.enum(["cli", "cli-resync"]),
@@ -17780,11 +16584,11 @@ var init_local_fingerprint = __esm({
17780
16584
  });
17781
16585
 
17782
16586
  // src/security/install-tracking.ts
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";
16587
+ import { readFileSync as readFileSync19, readdirSync as readdirSync12, lstatSync as lstatSync6, existsSync as existsSync20 } from "node:fs";
16588
+ import { join as join10, relative as relative5, sep } from "node:path";
16589
+ import { homedir as homedir6 } from "node:os";
17786
16590
  import { resolve as resolve16 } from "node:path";
17787
- import { createHash as createHash8 } from "node:crypto";
16591
+ import { createHash as createHash7 } from "node:crypto";
17788
16592
  import { z as z6 } from "zod";
17789
16593
  function containsHiddenDirs(packageDir) {
17790
16594
  for (const hidden of EXCLUDED_DIR_NAMES) {
@@ -17800,15 +16604,15 @@ function sha256OfDir(dir, opts = {}) {
17800
16604
  function walk(currentDir) {
17801
16605
  let entries;
17802
16606
  try {
17803
- entries = readdirSync13(currentDir);
16607
+ entries = readdirSync12(currentDir);
17804
16608
  } catch {
17805
16609
  return;
17806
16610
  }
17807
16611
  for (const entry of entries.sort()) {
17808
- const absPath = join11(currentDir, entry);
16612
+ const absPath = join10(currentDir, entry);
17809
16613
  let lst;
17810
16614
  try {
17811
- lst = lstatSync7(absPath);
16615
+ lst = lstatSync6(absPath);
17812
16616
  } catch {
17813
16617
  continue;
17814
16618
  }
@@ -17832,9 +16636,9 @@ function sha256OfDir(dir, opts = {}) {
17832
16636
  }
17833
16637
  walk(dir);
17834
16638
  files.sort((a2, b2) => a2.relativePath < b2.relativePath ? -1 : a2.relativePath > b2.relativePath ? 1 : 0);
17835
- const top = createHash8("sha256");
16639
+ const top = createHash7("sha256");
17836
16640
  for (const f2 of files) {
17837
- const fileHash = createHash8("sha256").update(readFileSync20(f2.absPath)).digest("hex");
16641
+ const fileHash = createHash7("sha256").update(readFileSync19(f2.absPath)).digest("hex");
17838
16642
  top.update(f2.relativePath, "utf-8");
17839
16643
  top.update("\0", "utf-8");
17840
16644
  top.update(fileHash, "utf-8");
@@ -17846,7 +16650,7 @@ function readInstalledManifest(path = INSTALLED_MANIFEST_PATH) {
17846
16650
  if (!existsSync20(path)) return {};
17847
16651
  let raw;
17848
16652
  try {
17849
- raw = JSON.parse(readFileSync20(path, "utf-8"));
16653
+ raw = JSON.parse(readFileSync19(path, "utf-8"));
17850
16654
  } catch {
17851
16655
  return {};
17852
16656
  }
@@ -17910,7 +16714,7 @@ var init_install_tracking = __esm({
17910
16714
  "src/security/install-tracking.ts"() {
17911
16715
  "use strict";
17912
16716
  init_atomic_write();
17913
- INSTALLED_MANIFEST_PATH = resolve16(homedir7(), ".massu", "adapter-manifest-installed.json");
16717
+ INSTALLED_MANIFEST_PATH = resolve16(homedir6(), ".massu", "adapter-manifest-installed.json");
17914
16718
  DEFAULT_MAX_FILE_BYTES = 64 * 1024 * 1024;
17915
16719
  EXCLUDED_DIR_NAMES = /* @__PURE__ */ new Set([".git", "node_modules", ".cache", ".tmp"]);
17916
16720
  InstallEntrySchema = z6.object({
@@ -17933,7 +16737,7 @@ var init_install_tracking = __esm({
17933
16737
  });
17934
16738
 
17935
16739
  // src/detect/adapters/discover.ts
17936
- import { existsSync as existsSync21, readdirSync as readdirSync14, readFileSync as readFileSync21, lstatSync as lstatSync8 } from "node:fs";
16740
+ import { existsSync as existsSync21, readdirSync as readdirSync13, readFileSync as readFileSync20, lstatSync as lstatSync7 } from "node:fs";
17937
16741
  import { resolve as resolve17, isAbsolute as isAbsolute2 } from "node:path";
17938
16742
  import { z as z7 } from "zod";
17939
16743
  function walkNodeModules(projectRoot, warnings) {
@@ -17944,7 +16748,7 @@ function walkNodeModules(projectRoot, warnings) {
17944
16748
  const candidates = [];
17945
16749
  let topLevelEntries;
17946
16750
  try {
17947
- topLevelEntries = readdirSync14(nodeModulesDir);
16751
+ topLevelEntries = readdirSync13(nodeModulesDir);
17948
16752
  } catch (err) {
17949
16753
  warnings.push(`failed to read node_modules: ${err instanceof Error ? err.message : String(err)}`);
17950
16754
  return [];
@@ -17954,7 +16758,7 @@ function walkNodeModules(projectRoot, warnings) {
17954
16758
  const entryPath = resolve17(nodeModulesDir, entry);
17955
16759
  let entryStat;
17956
16760
  try {
17957
- entryStat = lstatSync8(entryPath);
16761
+ entryStat = lstatSync7(entryPath);
17958
16762
  } catch {
17959
16763
  continue;
17960
16764
  }
@@ -17968,7 +16772,7 @@ function walkNodeModules(projectRoot, warnings) {
17968
16772
  if (entry.startsWith("@")) {
17969
16773
  let scopedEntries;
17970
16774
  try {
17971
- scopedEntries = readdirSync14(entryPath);
16775
+ scopedEntries = readdirSync13(entryPath);
17972
16776
  } catch {
17973
16777
  continue;
17974
16778
  }
@@ -17976,7 +16780,7 @@ function walkNodeModules(projectRoot, warnings) {
17976
16780
  const subPath = resolve17(entryPath, sub);
17977
16781
  let subStat;
17978
16782
  try {
17979
- subStat = lstatSync8(subPath);
16783
+ subStat = lstatSync7(subPath);
17980
16784
  } catch {
17981
16785
  continue;
17982
16786
  }
@@ -17996,7 +16800,7 @@ function tryReadAdapterPackage(packageDir, warnings) {
17996
16800
  if (!existsSync21(pkgJsonPath)) return null;
17997
16801
  let raw;
17998
16802
  try {
17999
- raw = JSON.parse(readFileSync21(pkgJsonPath, "utf-8"));
16803
+ raw = JSON.parse(readFileSync20(pkgJsonPath, "utf-8"));
18000
16804
  } catch (err) {
18001
16805
  warnings.push(
18002
16806
  `skipping ${packageDir}: package.json parse failed (${err instanceof Error ? err.message : String(err)})`
@@ -18212,7 +17016,7 @@ __export(adapters_exports, {
18212
17016
  runAdaptersResyncLocalFingerprint: () => runAdaptersResyncLocalFingerprint,
18213
17017
  runAdaptersSearch: () => runAdaptersSearch
18214
17018
  });
18215
- import { existsSync as existsSync22, readFileSync as readFileSync22 } from "node:fs";
17019
+ import { existsSync as existsSync22, readFileSync as readFileSync21 } from "node:fs";
18216
17020
  import { resolve as resolve18 } from "node:path";
18217
17021
  import { parseDocument } from "yaml";
18218
17022
  async function handleAdaptersSubcommand(args2) {
@@ -18490,7 +17294,7 @@ function mutateLocalArray(mutator, command) {
18490
17294
  }
18491
17295
  let yamlText;
18492
17296
  try {
18493
- yamlText = readFileSync22(yamlPath, "utf-8");
17297
+ yamlText = readFileSync21(yamlPath, "utf-8");
18494
17298
  } catch (err) {
18495
17299
  process.stderr.write(`${command}: failed to read ${yamlPath}: ${err instanceof Error ? err.message : String(err)}
18496
17300
  `);
@@ -18596,7 +17400,7 @@ async function runAdaptersInstall(args2) {
18596
17400
  }
18597
17401
  let pkgJson;
18598
17402
  try {
18599
- pkgJson = JSON.parse(readFileSync22(pkgJsonPath, "utf-8"));
17403
+ pkgJson = JSON.parse(readFileSync21(pkgJsonPath, "utf-8"));
18600
17404
  } catch (err) {
18601
17405
  process.stderr.write(`install: ${packageName} has malformed package.json: ${err instanceof Error ? err.message : String(err)}
18602
17406
  `);
@@ -18803,8 +17607,8 @@ var init_adapters2 = __esm({
18803
17607
 
18804
17608
  // src/db.ts
18805
17609
  import Database2 from "better-sqlite3";
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";
17610
+ import { dirname as dirname11, join as join11 } from "path";
17611
+ import { existsSync as existsSync23, mkdirSync as mkdirSync9, readdirSync as readdirSync14, statSync as statSync11 } from "fs";
18808
17612
  function getCodeGraphDb() {
18809
17613
  const dbPath = getResolvedPaths().codegraphDbPath;
18810
17614
  if (!existsSync23(dbPath)) {
@@ -18816,9 +17620,9 @@ function getCodeGraphDb() {
18816
17620
  }
18817
17621
  function getDataDb() {
18818
17622
  const dbPath = getResolvedPaths().dataDbPath;
18819
- const dir = dirname12(dbPath);
17623
+ const dir = dirname11(dbPath);
18820
17624
  if (!existsSync23(dir)) {
18821
- mkdirSync10(dir, { recursive: true });
17625
+ mkdirSync9(dir, { recursive: true });
18822
17626
  }
18823
17627
  const db = new Database2(dbPath);
18824
17628
  db.pragma("journal_mode = WAL");
@@ -19088,9 +17892,9 @@ function isPythonDataStale(dataDb2, pythonRoot) {
19088
17892
  const lastBuildTime = new Date(lastBuild.value).getTime();
19089
17893
  function checkDir(dir) {
19090
17894
  try {
19091
- const entries = readdirSync15(dir, { withFileTypes: true });
17895
+ const entries = readdirSync14(dir, { withFileTypes: true });
19092
17896
  for (const entry of entries) {
19093
- const fullPath = join12(dir, entry.name);
17897
+ const fullPath = join11(dir, entry.name);
19094
17898
  if (entry.isDirectory()) {
19095
17899
  if (["__pycache__", ".venv", "venv", "node_modules", ".mypy_cache", ".pytest_cache"].includes(entry.name)) continue;
19096
17900
  if (checkDir(fullPath)) return true;
@@ -19191,8 +17995,8 @@ var init_rules = __esm({
19191
17995
  });
19192
17996
 
19193
17997
  // src/import-resolver.ts
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";
17998
+ import { readFileSync as readFileSync22, existsSync as existsSync24, statSync as statSync12 } from "fs";
17999
+ import { resolve as resolve20, dirname as dirname12, join as join12 } from "path";
19196
18000
  function parseImports(source) {
19197
18001
  const imports = [];
19198
18002
  const lines = source.split("\n");
@@ -19250,7 +18054,7 @@ function resolveImportPath(specifier, fromFile) {
19250
18054
  const paths = getResolvedPaths();
19251
18055
  basePath = resolve20(paths.pathAlias["@"] ?? paths.srcDir, specifier.slice(2));
19252
18056
  } else {
19253
- basePath = resolve20(dirname13(fromFile), specifier);
18057
+ basePath = resolve20(dirname12(fromFile), specifier);
19254
18058
  }
19255
18059
  if (existsSync24(basePath) && !isDirectory(basePath)) {
19256
18060
  return toRelative(basePath);
@@ -19263,7 +18067,7 @@ function resolveImportPath(specifier, fromFile) {
19263
18067
  }
19264
18068
  }
19265
18069
  for (const indexFile of resolvedPaths.indexFiles) {
19266
- const indexPath = join13(basePath, indexFile);
18070
+ const indexPath = join12(basePath, indexFile);
19267
18071
  if (existsSync24(indexPath)) {
19268
18072
  return toRelative(indexPath);
19269
18073
  }
@@ -19304,7 +18108,7 @@ function buildImportIndex(dataDb2, codegraphDb2) {
19304
18108
  if (!existsSync24(absPath)) continue;
19305
18109
  let source;
19306
18110
  try {
19307
- source = readFileSync23(absPath, "utf-8");
18111
+ source = readFileSync22(absPath, "utf-8");
19308
18112
  } catch {
19309
18113
  continue;
19310
18114
  }
@@ -19340,15 +18144,15 @@ var init_import_resolver = __esm({
19340
18144
  });
19341
18145
 
19342
18146
  // src/trpc-index.ts
19343
- import { readFileSync as readFileSync24, existsSync as existsSync25, readdirSync as readdirSync16 } from "fs";
19344
- import { resolve as resolve21, join as join14 } from "path";
18147
+ import { readFileSync as readFileSync23, existsSync as existsSync25, readdirSync as readdirSync15 } from "fs";
18148
+ import { resolve as resolve21, join as join13 } from "path";
19345
18149
  function parseRootRouter() {
19346
18150
  const paths = getResolvedPaths();
19347
18151
  const rootPath = paths.rootRouterPath;
19348
18152
  if (!existsSync25(rootPath)) {
19349
18153
  throw new Error(`Root router not found at ${rootPath}`);
19350
18154
  }
19351
- const source = readFileSync24(rootPath, "utf-8");
18155
+ const source = readFileSync23(rootPath, "utf-8");
19352
18156
  const mappings = [];
19353
18157
  const importMap = /* @__PURE__ */ new Map();
19354
18158
  const importRegex = /import\s+\{[^}]*?(\w+Router)[^}]*\}\s+from\s+['"]\.\/routers\/([^'"]+)['"]/g;
@@ -19364,7 +18168,7 @@ function parseRootRouter() {
19364
18168
  filePath = routersRelPath + "/" + filePath + ext;
19365
18169
  break;
19366
18170
  }
19367
- const indexCandidate = join14(fullPath, "index.ts");
18171
+ const indexCandidate = join13(fullPath, "index.ts");
19368
18172
  if (existsSync25(indexCandidate)) {
19369
18173
  filePath = routersRelPath + "/" + filePath + "/index.ts";
19370
18174
  break;
@@ -19386,7 +18190,7 @@ function parseRootRouter() {
19386
18190
  function extractProcedures(routerFilePath) {
19387
18191
  const absPath = resolve21(getProjectRoot(), routerFilePath);
19388
18192
  if (!existsSync25(absPath)) return [];
19389
- const source = readFileSync24(absPath, "utf-8");
18193
+ const source = readFileSync23(absPath, "utf-8");
19390
18194
  const procedures = [];
19391
18195
  const seen = /* @__PURE__ */ new Set();
19392
18196
  const procRegex = /(\w+)\s*:\s*(protected|public)Procedure/g;
@@ -19421,15 +18225,15 @@ function findUICallSites(routerKey, procedureName) {
19421
18225
  return callSites;
19422
18226
  }
19423
18227
  function searchDirectory(dir, pattern, results) {
19424
- const entries = readdirSync16(dir, { withFileTypes: true });
18228
+ const entries = readdirSync15(dir, { withFileTypes: true });
19425
18229
  for (const entry of entries) {
19426
- const fullPath = join14(dir, entry.name);
18230
+ const fullPath = join13(dir, entry.name);
19427
18231
  if (entry.isDirectory()) {
19428
18232
  if (entry.name === "node_modules" || entry.name === ".next") continue;
19429
18233
  searchDirectory(fullPath, pattern, results);
19430
18234
  } else if (entry.name.endsWith(".ts") || entry.name.endsWith(".tsx")) {
19431
18235
  try {
19432
- const source = readFileSync24(fullPath, "utf-8");
18236
+ const source = readFileSync23(fullPath, "utf-8");
19433
18237
  const lines = source.split("\n");
19434
18238
  for (let i = 0; i < lines.length; i++) {
19435
18239
  if (lines[i].includes(pattern)) {
@@ -19492,7 +18296,7 @@ var init_trpc_index = __esm({
19492
18296
  });
19493
18297
 
19494
18298
  // src/page-deps.ts
19495
- import { readFileSync as readFileSync25, existsSync as existsSync26 } from "fs";
18299
+ import { readFileSync as readFileSync24, existsSync as existsSync26 } from "fs";
19496
18300
  import { resolve as resolve22 } from "path";
19497
18301
  function deriveRoute(pageFile) {
19498
18302
  let route = pageFile.replace(/^src\/app/, "").replace(/\/page\.tsx?$/, "").replace(/\/page\.jsx?$/, "");
@@ -19534,7 +18338,7 @@ function findRouterCalls(files) {
19534
18338
  const absPath = ensureWithinRoot(resolve22(projectRoot, file), projectRoot);
19535
18339
  if (!existsSync26(absPath)) continue;
19536
18340
  try {
19537
- const source = readFileSync25(absPath, "utf-8");
18341
+ const source = readFileSync24(absPath, "utf-8");
19538
18342
  const apiCallRegex = /api\.(\w+)\.\w+/g;
19539
18343
  let match;
19540
18344
  while ((match = apiCallRegex.exec(source)) !== null) {
@@ -19555,7 +18359,7 @@ function findTablesFromRouters(routerNames, dataDb2) {
19555
18359
  const absPath = ensureWithinRoot(resolve22(getProjectRoot(), proc.router_file), getProjectRoot());
19556
18360
  if (!existsSync26(absPath)) continue;
19557
18361
  try {
19558
- const source = readFileSync25(absPath, "utf-8");
18362
+ const source = readFileSync24(absPath, "utf-8");
19559
18363
  const dbPattern = getConfig().dbAccessPattern ?? "ctx.db.{table}";
19560
18364
  const regexStr = dbPattern.replace(/[.*+?^${}()|[\]\\]/g, "\\$&").replace("\\{table\\}", "(\\w+)");
19561
18365
  const tableRegex = new RegExp(regexStr + "\\.", "g");
@@ -19824,14 +18628,14 @@ var init_domains = __esm({
19824
18628
  });
19825
18629
 
19826
18630
  // src/schema-mapper.ts
19827
- import { readFileSync as readFileSync26, existsSync as existsSync27, readdirSync as readdirSync17 } from "fs";
19828
- import { join as join15 } from "path";
18631
+ import { readFileSync as readFileSync25, existsSync as existsSync27, readdirSync as readdirSync16 } from "fs";
18632
+ import { join as join14 } from "path";
19829
18633
  function parsePrismaSchema() {
19830
18634
  const schemaPath = getResolvedPaths().prismaSchemaPath;
19831
18635
  if (!existsSync27(schemaPath)) {
19832
18636
  throw new Error(`Prisma schema not found at ${schemaPath}`);
19833
18637
  }
19834
- const source = readFileSync26(schemaPath, "utf-8");
18638
+ const source = readFileSync25(schemaPath, "utf-8");
19835
18639
  const models = [];
19836
18640
  const sourceLines = source.split("\n");
19837
18641
  let i = 0;
@@ -19894,9 +18698,9 @@ function findColumnUsageInRouters(tableName) {
19894
18698
  return usage;
19895
18699
  }
19896
18700
  function scanDirectory(dir, tableName, usage) {
19897
- const entries = readdirSync17(dir, { withFileTypes: true });
18701
+ const entries = readdirSync16(dir, { withFileTypes: true });
19898
18702
  for (const entry of entries) {
19899
- const fullPath = join15(dir, entry.name);
18703
+ const fullPath = join14(dir, entry.name);
19900
18704
  if (entry.isDirectory()) {
19901
18705
  scanDirectory(fullPath, tableName, usage);
19902
18706
  } else if (entry.name.endsWith(".ts")) {
@@ -19906,7 +18710,7 @@ function scanDirectory(dir, tableName, usage) {
19906
18710
  }
19907
18711
  function scanFile(absPath, tableName, usage) {
19908
18712
  try {
19909
- const source = readFileSync26(absPath, "utf-8");
18713
+ const source = readFileSync25(absPath, "utf-8");
19910
18714
  if (!source.includes(tableName)) return;
19911
18715
  const relPath = absPath.slice(getProjectRoot().length + 1);
19912
18716
  const lines = source.split("\n");
@@ -19952,14 +18756,14 @@ function detectMismatches(models) {
19952
18756
  function findFilesUsingColumn(dir, column, tableName) {
19953
18757
  const result = [];
19954
18758
  if (!existsSync27(dir)) return result;
19955
- const entries = readdirSync17(dir, { withFileTypes: true });
18759
+ const entries = readdirSync16(dir, { withFileTypes: true });
19956
18760
  for (const entry of entries) {
19957
- const fullPath = join15(dir, entry.name);
18761
+ const fullPath = join14(dir, entry.name);
19958
18762
  if (entry.isDirectory()) {
19959
18763
  result.push(...findFilesUsingColumn(fullPath, column, tableName));
19960
18764
  } else if (entry.name.endsWith(".ts")) {
19961
18765
  try {
19962
- const source = readFileSync26(fullPath, "utf-8");
18766
+ const source = readFileSync25(fullPath, "utf-8");
19963
18767
  if (source.includes(tableName) && source.includes(column)) {
19964
18768
  result.push(fullPath.slice(getProjectRoot().length + 1));
19965
18769
  }
@@ -20104,32 +18908,32 @@ var init_import_parser = __esm({
20104
18908
  });
20105
18909
 
20106
18910
  // src/python/import-resolver.ts
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";
18911
+ import { readFileSync as readFileSync26, existsSync as existsSync28, readdirSync as readdirSync17 } from "fs";
18912
+ import { resolve as resolve24, join as join15, relative as relative6, dirname as dirname13 } from "path";
20109
18913
  function resolvePythonModulePath(module, fromFile, pythonRoot, level) {
20110
18914
  const projectRoot = getProjectRoot();
20111
18915
  if (level > 0) {
20112
- let baseDir = dirname14(resolve24(projectRoot, fromFile));
18916
+ let baseDir = dirname13(resolve24(projectRoot, fromFile));
20113
18917
  for (let i = 1; i < level; i++) {
20114
- baseDir = dirname14(baseDir);
18918
+ baseDir = dirname13(baseDir);
20115
18919
  }
20116
18920
  const modulePart = module.replace(/^\.+/, "");
20117
18921
  if (modulePart) {
20118
18922
  const parts2 = modulePart.split(".");
20119
- return tryResolvePythonPath(join16(baseDir, ...parts2), projectRoot);
18923
+ return tryResolvePythonPath(join15(baseDir, ...parts2), projectRoot);
20120
18924
  }
20121
18925
  return tryResolvePythonPath(baseDir, projectRoot);
20122
18926
  }
20123
18927
  const parts = module.split(".");
20124
- const candidate = join16(resolve24(projectRoot, pythonRoot), ...parts);
18928
+ const candidate = join15(resolve24(projectRoot, pythonRoot), ...parts);
20125
18929
  return tryResolvePythonPath(candidate, projectRoot);
20126
18930
  }
20127
18931
  function tryResolvePythonPath(basePath, projectRoot) {
20128
18932
  if (existsSync28(basePath + ".py")) {
20129
18933
  return relative6(projectRoot, basePath + ".py");
20130
18934
  }
20131
- if (existsSync28(join16(basePath, "__init__.py"))) {
20132
- return relative6(projectRoot, join16(basePath, "__init__.py"));
18935
+ if (existsSync28(join15(basePath, "__init__.py"))) {
18936
+ return relative6(projectRoot, join15(basePath, "__init__.py"));
20133
18937
  }
20134
18938
  if (basePath.endsWith(".py") && existsSync28(basePath)) {
20135
18939
  return relative6(projectRoot, basePath);
@@ -20139,13 +18943,13 @@ function tryResolvePythonPath(basePath, projectRoot) {
20139
18943
  function walkPythonFiles(dir, excludeDirs) {
20140
18944
  const files = [];
20141
18945
  try {
20142
- const entries = readdirSync18(dir, { withFileTypes: true });
18946
+ const entries = readdirSync17(dir, { withFileTypes: true });
20143
18947
  for (const entry of entries) {
20144
18948
  if (entry.isDirectory()) {
20145
18949
  if (excludeDirs.includes(entry.name)) continue;
20146
- files.push(...walkPythonFiles(join16(dir, entry.name), excludeDirs));
18950
+ files.push(...walkPythonFiles(join15(dir, entry.name), excludeDirs));
20147
18951
  } else if (entry.name.endsWith(".py")) {
20148
- files.push(join16(dir, entry.name));
18952
+ files.push(join15(dir, entry.name));
20149
18953
  }
20150
18954
  }
20151
18955
  } catch {
@@ -20171,7 +18975,7 @@ function buildPythonImportIndex(dataDb2, pythonRoot, excludeDirs = ["__pycache__
20171
18975
  const relFile = relative6(projectRoot, absFile);
20172
18976
  let source;
20173
18977
  try {
20174
- source = readFileSync27(absFile, "utf-8");
18978
+ source = readFileSync26(absFile, "utf-8");
20175
18979
  } catch {
20176
18980
  continue;
20177
18981
  }
@@ -20437,18 +19241,18 @@ var init_route_parser = __esm({
20437
19241
  });
20438
19242
 
20439
19243
  // src/python/route-indexer.ts
20440
- import { readFileSync as readFileSync28, readdirSync as readdirSync19 } from "fs";
20441
- import { join as join17, relative as relative7 } from "path";
19244
+ import { readFileSync as readFileSync27, readdirSync as readdirSync18 } from "fs";
19245
+ import { join as join16, relative as relative7 } from "path";
20442
19246
  function walkPyFiles(dir, excludeDirs) {
20443
19247
  const files = [];
20444
19248
  try {
20445
- const entries = readdirSync19(dir, { withFileTypes: true });
19249
+ const entries = readdirSync18(dir, { withFileTypes: true });
20446
19250
  for (const entry of entries) {
20447
19251
  if (entry.isDirectory()) {
20448
19252
  if (excludeDirs.includes(entry.name)) continue;
20449
- files.push(...walkPyFiles(join17(dir, entry.name), excludeDirs));
19253
+ files.push(...walkPyFiles(join16(dir, entry.name), excludeDirs));
20450
19254
  } else if (entry.name.endsWith(".py")) {
20451
- files.push(join17(dir, entry.name));
19255
+ files.push(join16(dir, entry.name));
20452
19256
  }
20453
19257
  }
20454
19258
  } catch {
@@ -20457,7 +19261,7 @@ function walkPyFiles(dir, excludeDirs) {
20457
19261
  }
20458
19262
  function buildPythonRouteIndex(dataDb2, pythonRoot, excludeDirs = ["__pycache__", ".venv", "venv", ".mypy_cache", ".pytest_cache"]) {
20459
19263
  const projectRoot = getProjectRoot();
20460
- const absRoot = join17(projectRoot, pythonRoot);
19264
+ const absRoot = join16(projectRoot, pythonRoot);
20461
19265
  dataDb2.exec("DELETE FROM massu_py_routes");
20462
19266
  dataDb2.exec("DELETE FROM massu_py_route_callers");
20463
19267
  const insertStmt = dataDb2.prepare(
@@ -20470,7 +19274,7 @@ function buildPythonRouteIndex(dataDb2, pythonRoot, excludeDirs = ["__pycache__"
20470
19274
  const relFile = relative7(projectRoot, absFile);
20471
19275
  let source;
20472
19276
  try {
20473
- source = readFileSync28(absFile, "utf-8");
19277
+ source = readFileSync27(absFile, "utf-8");
20474
19278
  } catch {
20475
19279
  continue;
20476
19280
  }
@@ -20681,18 +19485,18 @@ var init_model_parser = __esm({
20681
19485
  });
20682
19486
 
20683
19487
  // src/python/model-indexer.ts
20684
- import { readFileSync as readFileSync29, readdirSync as readdirSync20 } from "fs";
20685
- import { join as join18, relative as relative8 } from "path";
19488
+ import { readFileSync as readFileSync28, readdirSync as readdirSync19 } from "fs";
19489
+ import { join as join17, relative as relative8 } from "path";
20686
19490
  function walkPyFiles2(dir, excludeDirs) {
20687
19491
  const files = [];
20688
19492
  try {
20689
- const entries = readdirSync20(dir, { withFileTypes: true });
19493
+ const entries = readdirSync19(dir, { withFileTypes: true });
20690
19494
  for (const entry of entries) {
20691
19495
  if (entry.isDirectory()) {
20692
19496
  if (excludeDirs.includes(entry.name)) continue;
20693
- files.push(...walkPyFiles2(join18(dir, entry.name), excludeDirs));
19497
+ files.push(...walkPyFiles2(join17(dir, entry.name), excludeDirs));
20694
19498
  } else if (entry.name.endsWith(".py")) {
20695
- files.push(join18(dir, entry.name));
19499
+ files.push(join17(dir, entry.name));
20696
19500
  }
20697
19501
  }
20698
19502
  } catch {
@@ -20701,7 +19505,7 @@ function walkPyFiles2(dir, excludeDirs) {
20701
19505
  }
20702
19506
  function buildPythonModelIndex(dataDb2, pythonRoot, excludeDirs = ["__pycache__", ".venv", "venv", ".mypy_cache", ".pytest_cache"]) {
20703
19507
  const projectRoot = getProjectRoot();
20704
- const absRoot = join18(projectRoot, pythonRoot);
19508
+ const absRoot = join17(projectRoot, pythonRoot);
20705
19509
  dataDb2.exec("DELETE FROM massu_py_models");
20706
19510
  dataDb2.exec("DELETE FROM massu_py_fk_edges");
20707
19511
  const insertModel = dataDb2.prepare(
@@ -20717,7 +19521,7 @@ function buildPythonModelIndex(dataDb2, pythonRoot, excludeDirs = ["__pycache__"
20717
19521
  const relFile = relative8(projectRoot, absFile);
20718
19522
  let source;
20719
19523
  try {
20720
- source = readFileSync29(absFile, "utf-8");
19524
+ source = readFileSync28(absFile, "utf-8");
20721
19525
  } catch {
20722
19526
  continue;
20723
19527
  }
@@ -20977,19 +19781,19 @@ var init_migration_parser = __esm({
20977
19781
  });
20978
19782
 
20979
19783
  // src/python/migration-indexer.ts
20980
- import { readFileSync as readFileSync30, readdirSync as readdirSync21 } from "fs";
20981
- import { join as join19, relative as relative9 } from "path";
19784
+ import { readFileSync as readFileSync29, readdirSync as readdirSync20 } from "fs";
19785
+ import { join as join18, relative as relative9 } from "path";
20982
19786
  function buildPythonMigrationIndex(dataDb2, alembicDir) {
20983
19787
  const projectRoot = getProjectRoot();
20984
- const absDir = join19(projectRoot, alembicDir);
19788
+ const absDir = join18(projectRoot, alembicDir);
20985
19789
  dataDb2.exec("DELETE FROM massu_py_migrations");
20986
- const versionsDir = join19(absDir, "versions");
19790
+ const versionsDir = join18(absDir, "versions");
20987
19791
  let files = [];
20988
19792
  try {
20989
- files = readdirSync21(versionsDir).filter((f2) => f2.endsWith(".py")).map((f2) => join19(versionsDir, f2));
19793
+ files = readdirSync20(versionsDir).filter((f2) => f2.endsWith(".py")).map((f2) => join18(versionsDir, f2));
20990
19794
  } catch {
20991
19795
  try {
20992
- files = readdirSync21(absDir).filter((f2) => f2.endsWith(".py") && f2 !== "env.py").map((f2) => join19(absDir, f2));
19796
+ files = readdirSync20(absDir).filter((f2) => f2.endsWith(".py") && f2 !== "env.py").map((f2) => join18(absDir, f2));
20993
19797
  } catch {
20994
19798
  }
20995
19799
  }
@@ -21003,7 +19807,7 @@ function buildPythonMigrationIndex(dataDb2, alembicDir) {
21003
19807
  for (const absFile of files) {
21004
19808
  let source;
21005
19809
  try {
21006
- source = readFileSync30(absFile, "utf-8");
19810
+ source = readFileSync29(absFile, "utf-8");
21007
19811
  } catch {
21008
19812
  continue;
21009
19813
  }
@@ -21037,12 +19841,12 @@ var init_migration_indexer = __esm({
21037
19841
  });
21038
19842
 
21039
19843
  // src/python/coupling-detector.ts
21040
- import { readFileSync as readFileSync31, readdirSync as readdirSync22 } from "fs";
21041
- import { join as join20, relative as relative10 } from "path";
19844
+ import { readFileSync as readFileSync30, readdirSync as readdirSync21 } from "fs";
19845
+ import { join as join19, relative as relative10 } from "path";
21042
19846
  function buildPythonCouplingIndex(dataDb2) {
21043
19847
  const projectRoot = getProjectRoot();
21044
19848
  const config = getConfig();
21045
- const srcDir = join20(projectRoot, config.paths.source);
19849
+ const srcDir = join19(projectRoot, config.paths.source);
21046
19850
  const routes = dataDb2.prepare("SELECT id, method, path FROM massu_py_routes").all();
21047
19851
  if (routes.length === 0) return 0;
21048
19852
  dataDb2.exec("DELETE FROM massu_py_route_callers");
@@ -21074,7 +19878,7 @@ function buildPythonCouplingIndex(dataDb2) {
21074
19878
  const relFile = relative10(projectRoot, absFile);
21075
19879
  let source;
21076
19880
  try {
21077
- source = readFileSync31(absFile, "utf-8");
19881
+ source = readFileSync30(absFile, "utf-8");
21078
19882
  } catch {
21079
19883
  continue;
21080
19884
  }
@@ -21102,13 +19906,13 @@ function walkFrontendFiles(dir) {
21102
19906
  const files = [];
21103
19907
  const exclude = ["node_modules", ".next", "dist", ".git", "__pycache__", ".venv", "venv"];
21104
19908
  try {
21105
- const entries = readdirSync22(dir, { withFileTypes: true });
19909
+ const entries = readdirSync21(dir, { withFileTypes: true });
21106
19910
  for (const entry of entries) {
21107
19911
  if (entry.isDirectory()) {
21108
19912
  if (exclude.includes(entry.name)) continue;
21109
- files.push(...walkFrontendFiles(join20(dir, entry.name)));
19913
+ files.push(...walkFrontendFiles(join19(dir, entry.name)));
21110
19914
  } else if (/\.(tsx?|jsx?)$/.test(entry.name)) {
21111
- files.push(join20(dir, entry.name));
19915
+ files.push(join19(dir, entry.name));
21112
19916
  }
21113
19917
  }
21114
19918
  } catch {
@@ -21479,7 +20283,7 @@ var init_memory_tools = __esm({
21479
20283
  });
21480
20284
 
21481
20285
  // src/docs-tools.ts
21482
- import { readFileSync as readFileSync32, existsSync as existsSync29 } from "fs";
20286
+ import { readFileSync as readFileSync31, existsSync as existsSync29 } from "fs";
21483
20287
  import { resolve as resolve25, basename as basename6 } from "path";
21484
20288
  function p3(baseName) {
21485
20289
  return `${getConfig().toolPrefix}_${baseName}`;
@@ -21538,7 +20342,7 @@ function loadDocsMap() {
21538
20342
  if (!existsSync29(mapPath)) {
21539
20343
  throw new Error(`docs-map.json not found at ${mapPath}`);
21540
20344
  }
21541
- return JSON.parse(readFileSync32(mapPath, "utf-8"));
20345
+ return JSON.parse(readFileSync31(mapPath, "utf-8"));
21542
20346
  }
21543
20347
  function matchesPattern(filePath, pattern) {
21544
20348
  const regexStr = pattern.replace(/\./g, "\\.").replace(/\*\*/g, "{{GLOBSTAR}}").replace(/\*/g, "[^/]*").replace(/\{\{GLOBSTAR\}\}/g, ".*");
@@ -21612,9 +20416,9 @@ function extractProcedureNames(routerPath) {
21612
20416
  if (!existsSync29(absPath)) {
21613
20417
  const altPath = ensureWithinRoot(resolve25(getResolvedPaths().srcDir, "../server/api/routers", basename6(routerPath)), root);
21614
20418
  if (!existsSync29(altPath)) return [];
21615
- return extractProcedureNamesFromContent(readFileSync32(altPath, "utf-8"));
20419
+ return extractProcedureNamesFromContent(readFileSync31(altPath, "utf-8"));
21616
20420
  }
21617
- return extractProcedureNamesFromContent(readFileSync32(absPath, "utf-8"));
20421
+ return extractProcedureNamesFromContent(readFileSync31(absPath, "utf-8"));
21618
20422
  }
21619
20423
  function extractProcedureNamesFromContent(content) {
21620
20424
  const procRegex = /\.(?:query|mutation)\s*\(/g;
@@ -21667,7 +20471,7 @@ function handleDocsAudit(args2) {
21667
20471
  });
21668
20472
  continue;
21669
20473
  }
21670
- const content = readFileSync32(helpPagePath, "utf-8");
20474
+ const content = readFileSync31(helpPagePath, "utf-8");
21671
20475
  const sections = extractSections(content);
21672
20476
  const frontmatter = extractFrontmatter(content);
21673
20477
  const staleReasons = [];
@@ -21709,7 +20513,7 @@ function handleDocsAudit(args2) {
21709
20513
  if (parentId === mappingId) {
21710
20514
  const guidePath = ensureWithinRoot(resolve25(getResolvedPaths().helpSitePath, `pages/user-guides/${guideName}/index.mdx`), getProjectRoot());
21711
20515
  if (existsSync29(guidePath)) {
21712
- const guideContent = readFileSync32(guidePath, "utf-8");
20516
+ const guideContent = readFileSync31(guidePath, "utf-8");
21713
20517
  const guideFrontmatter = extractFrontmatter(guideContent);
21714
20518
  if (!guideFrontmatter?.lastVerified || status === "STALE") {
21715
20519
  results.push({
@@ -21749,7 +20553,7 @@ function handleDocsCoverage(args2) {
21749
20553
  let lastVerified = null;
21750
20554
  let status = null;
21751
20555
  if (exists) {
21752
- const content = readFileSync32(helpPagePath, "utf-8");
20556
+ const content = readFileSync31(helpPagePath, "utf-8");
21753
20557
  lineCount = content.split("\n").length;
21754
20558
  hasContent = lineCount > 10;
21755
20559
  const frontmatter = extractFrontmatter(content);
@@ -22867,8 +21671,8 @@ var init_sentinel_tools = __esm({
22867
21671
  });
22868
21672
 
22869
21673
  // src/sentinel-scanner.ts
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";
21674
+ import { readFileSync as readFileSync32, existsSync as existsSync31, readdirSync as readdirSync22, statSync as statSync13 } from "fs";
21675
+ import { resolve as resolve27, join as join20, basename as basename7, dirname as dirname14, relative as relative11 } from "path";
22872
21676
  function inferDomain(filePath) {
22873
21677
  const domains = getConfig().domains;
22874
21678
  const path = filePath.toLowerCase();
@@ -23000,7 +21804,7 @@ function scanComponentExports(dataDb2) {
23000
21804
  const basePath = resolve27(projectRoot, componentsBase);
23001
21805
  if (existsSync31(basePath)) {
23002
21806
  try {
23003
- const entries = readdirSync23(basePath, { withFileTypes: true });
21807
+ const entries = readdirSync22(basePath, { withFileTypes: true });
23004
21808
  for (const entry of entries) {
23005
21809
  if (entry.isDirectory()) {
23006
21810
  componentDirs.push(componentsBase + "/" + entry.name);
@@ -23015,7 +21819,7 @@ function scanComponentExports(dataDb2) {
23015
21819
  const files = walkDir2(absDir).filter((f2) => f2.endsWith(".tsx") || f2.endsWith(".ts"));
23016
21820
  for (const file of files) {
23017
21821
  const relPath = relative11(projectRoot, file);
23018
- const source = readFileSync33(file, "utf-8");
21822
+ const source = readFileSync32(file, "utf-8");
23019
21823
  const annotations = parseFeatureAnnotations(source);
23020
21824
  if (annotations.length > 0) {
23021
21825
  for (const ann of annotations) {
@@ -23041,7 +21845,7 @@ function scanComponentExports(dataDb2) {
23041
21845
  if (hasHandlers && exportMatch) {
23042
21846
  const componentName = exportMatch[1];
23043
21847
  const domain = inferDomain(relPath);
23044
- const subdomain = basename7(dirname15(relPath));
21848
+ const subdomain = basename7(dirname14(relPath));
23045
21849
  const featureKey = `component.${subdomain}.${componentName.replace(/([A-Z])/g, "-$1").toLowerCase().replace(/^-/, "")}`;
23046
21850
  if (!annotations.some((a2) => a2.featureKey === featureKey)) {
23047
21851
  features.push({
@@ -23064,9 +21868,9 @@ function scanComponentExports(dataDb2) {
23064
21868
  function walkDir2(dir) {
23065
21869
  const results = [];
23066
21870
  try {
23067
- const entries = readdirSync23(dir);
21871
+ const entries = readdirSync22(dir);
23068
21872
  for (const entry of entries) {
23069
- const fullPath = join21(dir, entry);
21873
+ const fullPath = join20(dir, entry);
23070
21874
  try {
23071
21875
  const stat = statSync13(fullPath);
23072
21876
  if (stat.isDirectory()) {
@@ -24054,7 +22858,7 @@ var init_audit_trail = __esm({
24054
22858
  });
24055
22859
 
24056
22860
  // src/validation-engine.ts
24057
- import { existsSync as existsSync32, readFileSync as readFileSync34 } from "fs";
22861
+ import { existsSync as existsSync32, readFileSync as readFileSync33 } from "fs";
24058
22862
  function p10(baseName) {
24059
22863
  return `${getConfig().toolPrefix}_${baseName}`;
24060
22864
  }
@@ -24094,7 +22898,7 @@ function validateFile(filePath, projectRoot) {
24094
22898
  });
24095
22899
  return checks;
24096
22900
  }
24097
- const source = readFileSync34(absPath, "utf-8");
22901
+ const source = readFileSync33(absPath, "utf-8");
24098
22902
  const lines = source.split("\n");
24099
22903
  if (activeChecks.rule_compliance !== false) {
24100
22904
  for (const ruleSet of config.rules) {
@@ -24539,7 +23343,7 @@ var init_adr_generator = __esm({
24539
23343
  });
24540
23344
 
24541
23345
  // src/security-scorer.ts
24542
- import { existsSync as existsSync33, readFileSync as readFileSync35 } from "fs";
23346
+ import { existsSync as existsSync33, readFileSync as readFileSync34 } from "fs";
24543
23347
  function p12(baseName) {
24544
23348
  return `${getConfig().toolPrefix}_${baseName}`;
24545
23349
  }
@@ -24568,7 +23372,7 @@ function scoreFileSecurity(filePath, projectRoot) {
24568
23372
  }
24569
23373
  let source;
24570
23374
  try {
24571
- source = readFileSync35(absPath, "utf-8");
23375
+ source = readFileSync34(absPath, "utf-8");
24572
23376
  } catch {
24573
23377
  return { riskScore: 0, findings: [] };
24574
23378
  }
@@ -24857,7 +23661,7 @@ var init_security_scorer = __esm({
24857
23661
  });
24858
23662
 
24859
23663
  // src/dependency-scorer.ts
24860
- import { existsSync as existsSync34, readFileSync as readFileSync36 } from "fs";
23664
+ import { existsSync as existsSync34, readFileSync as readFileSync35 } from "fs";
24861
23665
  import { resolve as resolve28 } from "path";
24862
23666
  function p13(baseName) {
24863
23667
  return `${getConfig().toolPrefix}_${baseName}`;
@@ -24893,7 +23697,7 @@ function getInstalledPackages(projectRoot) {
24893
23697
  const pkgPath = resolve28(projectRoot, "package.json");
24894
23698
  if (!existsSync34(pkgPath)) return /* @__PURE__ */ new Map();
24895
23699
  try {
24896
- const pkg = JSON.parse(readFileSync36(pkgPath, "utf-8"));
23700
+ const pkg = JSON.parse(readFileSync35(pkgPath, "utf-8"));
24897
23701
  const packages = /* @__PURE__ */ new Map();
24898
23702
  for (const [name, version] of Object.entries(pkg.dependencies ?? {})) {
24899
23703
  packages.set(name, version);
@@ -25495,8 +24299,8 @@ var init_regression_detector = __esm({
25495
24299
  });
25496
24300
 
25497
24301
  // src/knowledge-indexer.ts
25498
- import { createHash as createHash9 } from "crypto";
25499
- import { readFileSync as readFileSync37, readdirSync as readdirSync24, statSync as statSync14, existsSync as existsSync35 } from "fs";
24302
+ import { createHash as createHash8 } from "crypto";
24303
+ import { readFileSync as readFileSync36, readdirSync as readdirSync23, statSync as statSync14, existsSync as existsSync35 } from "fs";
25500
24304
  import { resolve as resolve29, relative as relative12, basename as basename8, extname as extname2 } from "path";
25501
24305
  function getKnowledgePaths() {
25502
24306
  const resolved = getResolvedPaths();
@@ -25523,7 +24327,7 @@ function discoverMarkdownFiles(baseDir) {
25523
24327
  const files = [];
25524
24328
  function walk(dir) {
25525
24329
  try {
25526
- const entries = readdirSync24(dir, { withFileTypes: true });
24330
+ const entries = readdirSync23(dir, { withFileTypes: true });
25527
24331
  for (const entry of entries) {
25528
24332
  const fullPath = resolve29(dir, entry.name);
25529
24333
  if (entry.isDirectory()) {
@@ -25583,7 +24387,7 @@ function categorizeFile(filePath) {
25583
24387
  return "root";
25584
24388
  }
25585
24389
  function hashContent2(content) {
25586
- return createHash9("sha256").update(content).digest("hex");
24390
+ return createHash8("sha256").update(content).digest("hex");
25587
24391
  }
25588
24392
  function parseCRTable(content) {
25589
24393
  const rules = [];
@@ -25851,7 +24655,7 @@ function indexAllKnowledge(db) {
25851
24655
  }
25852
24656
  for (const filePath of files) {
25853
24657
  if (!existsSync35(filePath)) continue;
25854
- const content = readFileSync37(filePath, "utf-8");
24658
+ const content = readFileSync36(filePath, "utf-8");
25855
24659
  const hash = hashContent2(content);
25856
24660
  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);
25857
24661
  const category = categorizeFile(filePath);
@@ -26003,7 +24807,7 @@ var init_knowledge_indexer = __esm({
26003
24807
  });
26004
24808
 
26005
24809
  // src/knowledge-tools.ts
26006
- import { readFileSync as readFileSync38, writeFileSync as writeFileSync6, appendFileSync as appendFileSync2, readdirSync as readdirSync25 } from "fs";
24810
+ import { readFileSync as readFileSync37, writeFileSync as writeFileSync5, appendFileSync as appendFileSync2, readdirSync as readdirSync24 } from "fs";
26007
24811
  import { resolve as resolve30, basename as basename9 } from "path";
26008
24812
  function p16(baseName) {
26009
24813
  return `${getConfig().toolPrefix}_${baseName}`;
@@ -26754,14 +25558,14 @@ ${crRule ? `- **CR**: ${crRule}
26754
25558
  `;
26755
25559
  let existing = "";
26756
25560
  try {
26757
- existing = readFileSync38(correctionsPath, "utf-8");
25561
+ existing = readFileSync37(correctionsPath, "utf-8");
26758
25562
  } catch {
26759
25563
  }
26760
25564
  const archiveIdx = existing.indexOf("## Archived");
26761
25565
  if (archiveIdx > 0) {
26762
25566
  const before = existing.slice(0, archiveIdx);
26763
25567
  const after = existing.slice(archiveIdx);
26764
- writeFileSync6(correctionsPath, before + entry + after);
25568
+ writeFileSync5(correctionsPath, before + entry + after);
26765
25569
  } else {
26766
25570
  appendFileSync2(correctionsPath, entry);
26767
25571
  }
@@ -26936,7 +25740,7 @@ function handleGaps(db, args2) {
26936
25740
  } else if (checkType === "routers") {
26937
25741
  try {
26938
25742
  const routersDir = getResolvedPaths().routersDir;
26939
- const routerFiles = readdirSync25(routersDir).filter((f2) => f2.endsWith(".ts") && !f2.startsWith("_"));
25743
+ const routerFiles = readdirSync24(routersDir).filter((f2) => f2.endsWith(".ts") && !f2.startsWith("_"));
26940
25744
  lines.push(`| Router | Knowledge Hits | Status |`);
26941
25745
  lines.push(`|--------|----------------|--------|`);
26942
25746
  for (const file of routerFiles) {
@@ -27092,13 +25896,13 @@ var init_knowledge_tools = __esm({
27092
25896
 
27093
25897
  // src/knowledge-db.ts
27094
25898
  import Database3 from "better-sqlite3";
27095
- import { dirname as dirname16 } from "path";
27096
- import { existsSync as existsSync37, mkdirSync as mkdirSync11 } from "fs";
25899
+ import { dirname as dirname15 } from "path";
25900
+ import { existsSync as existsSync37, mkdirSync as mkdirSync10 } from "fs";
27097
25901
  function getKnowledgeDb() {
27098
25902
  const dbPath = getResolvedPaths().knowledgeDbPath;
27099
- const dir = dirname16(dbPath);
25903
+ const dir = dirname15(dbPath);
27100
25904
  if (!existsSync37(dir)) {
27101
- mkdirSync11(dir, { recursive: true });
25905
+ mkdirSync10(dir, { recursive: true });
27102
25906
  }
27103
25907
  const db = new Database3(dbPath);
27104
25908
  db.pragma("journal_mode = WAL");
@@ -27831,7 +26635,7 @@ var init_python_tools = __esm({
27831
26635
  });
27832
26636
 
27833
26637
  // src/tools.ts
27834
- import { readFileSync as readFileSync39, existsSync as existsSync38 } from "fs";
26638
+ import { readFileSync as readFileSync38, existsSync as existsSync38 } from "fs";
27835
26639
  import { resolve as resolve31, basename as basename10 } from "path";
27836
26640
  function prefix2() {
27837
26641
  return getConfig().toolPrefix;
@@ -28268,7 +27072,7 @@ function handleContext(file, dataDb2, codegraphDb2) {
28268
27072
  const root = getProjectRoot();
28269
27073
  const absFilePath = ensureWithinRoot(resolve31(resolvedPaths.srcDir, "..", file), root);
28270
27074
  if (existsSync38(absFilePath)) {
28271
- const fileContent = readFileSync39(absFilePath, "utf-8").slice(0, 3e3);
27075
+ const fileContent = readFileSync38(absFilePath, "utf-8").slice(0, 3e3);
28272
27076
  const keywords = [];
28273
27077
  if (fileContent.includes("ctx.db")) keywords.push("database", "schema");
28274
27078
  if (fileContent.includes("BigInt") || fileContent.includes("Decimal")) keywords.push("BigInt", "serialization");
@@ -28696,7 +27500,7 @@ function handleSchema(args2) {
28696
27500
  if (!existsSync38(absPath)) {
28697
27501
  return text17(`File not found: ${file}`);
28698
27502
  }
28699
- const source = readFileSync39(absPath, "utf-8");
27503
+ const source = readFileSync38(absPath, "utf-8");
28700
27504
  const config = getConfig();
28701
27505
  const dbPattern = config.dbAccessPattern ?? "ctx.db.{table}";
28702
27506
  const regexStr = dbPattern.replace(/[.*+?^${}()|[\]\\]/g, "\\$&").replace("\\{table\\}", "(\\w+)");
@@ -28774,8 +27578,8 @@ var init_tools = __esm({
28774
27578
 
28775
27579
  // src/server.ts
28776
27580
  var server_exports = {};
28777
- import { readFileSync as readFileSync40 } from "fs";
28778
- import { resolve as resolve32, dirname as dirname17 } from "path";
27581
+ import { readFileSync as readFileSync39 } from "fs";
27582
+ import { resolve as resolve32, dirname as dirname16 } from "path";
28779
27583
  import { fileURLToPath as fileURLToPath4 } from "url";
28780
27584
  function getDb() {
28781
27585
  if (!codegraphDb) codegraphDb = getCodeGraphDb();
@@ -28867,10 +27671,10 @@ var init_server = __esm({
28867
27671
  init_tools();
28868
27672
  init_memory_db();
28869
27673
  init_license();
28870
- __dirname4 = dirname17(fileURLToPath4(import.meta.url));
27674
+ __dirname4 = dirname16(fileURLToPath4(import.meta.url));
28871
27675
  PKG_VERSION = (() => {
28872
27676
  try {
28873
- const pkg = JSON.parse(readFileSync40(resolve32(__dirname4, "..", "package.json"), "utf-8"));
27677
+ const pkg = JSON.parse(readFileSync39(resolve32(__dirname4, "..", "package.json"), "utf-8"));
28874
27678
  return pkg.version ?? "0.0.0";
28875
27679
  } catch {
28876
27680
  return "0.0.0";
@@ -29173,7 +27977,7 @@ var config_upgrade_exports = {};
29173
27977
  __export(config_upgrade_exports, {
29174
27978
  runConfigUpgrade: () => runConfigUpgrade
29175
27979
  });
29176
- import { existsSync as existsSync39, readFileSync as readFileSync41, writeFileSync as writeFileSync7, copyFileSync, unlinkSync as unlinkSync3 } from "fs";
27980
+ import { existsSync as existsSync39, readFileSync as readFileSync40, writeFileSync as writeFileSync6, copyFileSync, unlinkSync as unlinkSync2 } from "fs";
29177
27981
  import { resolve as resolve33 } from "path";
29178
27982
  import { parse as parseYaml6 } from "yaml";
29179
27983
  async function runConfigUpgrade(opts = {}) {
@@ -29192,7 +27996,7 @@ async function runConfigUpgrade(opts = {}) {
29192
27996
  }
29193
27997
  try {
29194
27998
  copyFileSync(bakPath, configPath);
29195
- unlinkSync3(bakPath);
27999
+ unlinkSync2(bakPath);
29196
28000
  log("Config restored from backup.\n");
29197
28001
  return { exitCode: 0, action: "rolled-back" };
29198
28002
  } catch (e2) {
@@ -29208,7 +28012,7 @@ async function runConfigUpgrade(opts = {}) {
29208
28012
  }
29209
28013
  let existing;
29210
28014
  try {
29211
- const content = readFileSync41(configPath, "utf-8");
28015
+ const content = readFileSync40(configPath, "utf-8");
29212
28016
  const parsed = parseYaml6(content);
29213
28017
  if (!parsed || typeof parsed !== "object") {
29214
28018
  throw new Error("config is not a YAML object");
@@ -29231,8 +28035,8 @@ async function runConfigUpgrade(opts = {}) {
29231
28035
  fingerprint: computeFingerprint(detection)
29232
28036
  };
29233
28037
  try {
29234
- const original = readFileSync41(configPath, "utf-8");
29235
- writeFileSync7(bakPath, original, "utf-8");
28038
+ const original = readFileSync40(configPath, "utf-8");
28039
+ writeFileSync6(bakPath, original, "utf-8");
29236
28040
  } catch (e2) {
29237
28041
  const message = `Failed to write backup: ${e2 instanceof Error ? e2.message : String(e2)}`;
29238
28042
  err(message + "\n");
@@ -29265,7 +28069,7 @@ var config_check_drift_exports = {};
29265
28069
  __export(config_check_drift_exports, {
29266
28070
  runConfigCheckDrift: () => runConfigCheckDrift
29267
28071
  });
29268
- import { existsSync as existsSync40, readFileSync as readFileSync42 } from "fs";
28072
+ import { existsSync as existsSync40, readFileSync as readFileSync41 } from "fs";
29269
28073
  import { resolve as resolve34 } from "path";
29270
28074
  import { parse as parseYaml7 } from "yaml";
29271
28075
  function renderChanges(changes) {
@@ -29293,7 +28097,7 @@ async function runConfigCheckDrift(opts = {}) {
29293
28097
  }
29294
28098
  let config;
29295
28099
  try {
29296
- const content = readFileSync42(configPath, "utf-8");
28100
+ const content = readFileSync41(configPath, "utf-8");
29297
28101
  const parsed = parseYaml7(content);
29298
28102
  if (!parsed || typeof parsed !== "object") {
29299
28103
  throw new Error("config is not a YAML object");
@@ -29360,11 +28164,11 @@ var init_config_check_drift = __esm({
29360
28164
  });
29361
28165
 
29362
28166
  // src/cli.ts
29363
- import { readFileSync as readFileSync43 } from "fs";
29364
- import { resolve as resolve35, dirname as dirname18 } from "path";
28167
+ import { readFileSync as readFileSync42 } from "fs";
28168
+ import { resolve as resolve35, dirname as dirname17 } from "path";
29365
28169
  import { fileURLToPath as fileURLToPath5 } from "url";
29366
28170
  var __filename4 = fileURLToPath5(import.meta.url);
29367
- var __dirname5 = dirname18(__filename4);
28171
+ var __dirname5 = dirname17(__filename4);
29368
28172
  var args = process.argv.slice(2);
29369
28173
  var subcommand = args[0];
29370
28174
  async function main() {
@@ -29546,7 +28350,7 @@ Examples:
29546
28350
  }
29547
28351
  function printVersion() {
29548
28352
  try {
29549
- const pkg = JSON.parse(readFileSync43(resolve35(__dirname5, "../package.json"), "utf-8"));
28353
+ const pkg = JSON.parse(readFileSync42(resolve35(__dirname5, "../package.json"), "utf-8"));
29550
28354
  console.log(`massu v${pkg.version}`);
29551
28355
  } catch {
29552
28356
  console.log("massu v0.1.0");