@massu/core 1.6.0 → 1.6.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/cli.js +730 -1686
- package/dist/hooks/session-start.js +10 -15
- package/docs/AUTHORING-ADAPTERS.md +41 -0
- package/docs/SECURITY.md +39 -0
- package/package.json +3 -3
- package/src/db.ts +24 -1
- package/src/security/registry-pubkey.generated.ts +1 -1
- package/src/server.ts +126 -25
- package/src/tool-db-needs.ts +226 -0
- package/src/tools.ts +110 -24
package/dist/cli.js
CHANGED
|
@@ -11159,1239 +11159,43 @@ var init_python_flask = __esm({
|
|
|
11159
11159
|
}
|
|
11160
11160
|
});
|
|
11161
11161
|
|
|
11162
|
-
//
|
|
11163
|
-
import {
|
|
11164
|
-
|
|
11165
|
-
|
|
11166
|
-
|
|
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
|
-
};
|
|
12038
|
-
}
|
|
12039
|
-
});
|
|
12040
|
-
|
|
12041
|
-
// src/detect/adapters/phoenix.ts
|
|
12042
|
-
var init_phoenix = __esm({
|
|
12043
|
-
"src/detect/adapters/phoenix.ts"() {
|
|
12044
|
-
"use strict";
|
|
12045
|
-
init_dist3();
|
|
12046
|
-
}
|
|
12047
|
-
});
|
|
12048
|
-
|
|
12049
|
-
// ../adapter-aspnet/dist/index.js
|
|
12050
|
-
import { Parser as Parser11 } from "web-tree-sitter";
|
|
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"() {
|
|
12061
|
-
"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
|
-
};
|
|
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";
|
|
12210
11167
|
}
|
|
12211
11168
|
});
|
|
12212
11169
|
|
|
12213
|
-
// src/detect/adapters/
|
|
12214
|
-
|
|
12215
|
-
|
|
11170
|
+
// src/detect/adapters/rails.ts
|
|
11171
|
+
import { railsAdapter } from "@massu/adapter-rails";
|
|
11172
|
+
var init_rails = __esm({
|
|
11173
|
+
"src/detect/adapters/rails.ts"() {
|
|
12216
11174
|
"use strict";
|
|
12217
|
-
init_dist4();
|
|
12218
11175
|
}
|
|
12219
11176
|
});
|
|
12220
11177
|
|
|
12221
|
-
//
|
|
12222
|
-
import {
|
|
12223
|
-
|
|
12224
|
-
|
|
12225
|
-
|
|
12226
|
-
|
|
12227
|
-
|
|
12228
|
-
|
|
12229
|
-
|
|
12230
|
-
|
|
12231
|
-
var
|
|
12232
|
-
"
|
|
11178
|
+
// src/detect/adapters/phoenix.ts
|
|
11179
|
+
import { phoenixAdapter } from "@massu/adapter-phoenix";
|
|
11180
|
+
var init_phoenix = __esm({
|
|
11181
|
+
"src/detect/adapters/phoenix.ts"() {
|
|
11182
|
+
"use strict";
|
|
11183
|
+
}
|
|
11184
|
+
});
|
|
11185
|
+
|
|
11186
|
+
// src/detect/adapters/aspnet.ts
|
|
11187
|
+
import { aspnetAdapter } from "@massu/adapter-aspnet";
|
|
11188
|
+
var init_aspnet = __esm({
|
|
11189
|
+
"src/detect/adapters/aspnet.ts"() {
|
|
12233
11190
|
"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
|
|
12406
|
-
import { join as
|
|
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) =>
|
|
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 =
|
|
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 =
|
|
11249
|
+
const fullPath = join9(dir, entry);
|
|
12446
11250
|
let st;
|
|
12447
11251
|
try {
|
|
12448
|
-
st =
|
|
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 =
|
|
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
|
|
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
|
|
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
|
|
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
|
|
12307
|
+
var init_dist2 = __esm({
|
|
13504
12308
|
"../../node_modules/@clack/prompts/dist/index.mjs"() {
|
|
13505
|
-
|
|
13506
|
-
|
|
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
|
|
13895
|
-
import { resolve as resolve6, basename as basename4, dirname as
|
|
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
|
|
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(
|
|
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 =
|
|
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 =
|
|
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
|
-
|
|
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(
|
|
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
|
-
|
|
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
|
-
|
|
13101
|
+
renameSync3(tmpPath, configPath);
|
|
14298
13102
|
if (existingMode !== void 0) {
|
|
14299
13103
|
try {
|
|
14300
|
-
|
|
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 =
|
|
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 =
|
|
13223
|
+
let content = readFileSync10(srcPath, "utf-8");
|
|
14420
13224
|
content = content.replace(/\{\{PROJECT_NAME\}\}/g, projectName);
|
|
14421
|
-
|
|
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(
|
|
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
|
-
|
|
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
|
-
|
|
13356
|
+
mkdirSync4(claudeDir, { recursive: true });
|
|
14553
13357
|
}
|
|
14554
13358
|
let settings = {};
|
|
14555
13359
|
if (existsSync10(settingsPath)) {
|
|
14556
13360
|
try {
|
|
14557
|
-
settings = JSON.parse(
|
|
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
|
-
|
|
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(
|
|
13380
|
+
const memoryDir = resolve6(homedir3(), `.claude/projects/${encodedRoot}/memory`);
|
|
14577
13381
|
let created = false;
|
|
14578
13382
|
if (!existsSync10(memoryDir)) {
|
|
14579
|
-
|
|
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
|
-
|
|
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
|
-
|
|
14853
|
-
|
|
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(
|
|
14873
|
-
const memFiles = existsSync10(memoryDir) ?
|
|
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(() => (
|
|
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(() => (
|
|
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 =
|
|
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
|
|
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 =
|
|
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 =
|
|
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
|
|
15250
|
-
import { resolve as resolve7, dirname as
|
|
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 =
|
|
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(
|
|
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(
|
|
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(
|
|
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 =
|
|
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 =
|
|
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 =
|
|
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 =
|
|
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
|
|
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(
|
|
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
|
|
15752
|
-
import { dirname as
|
|
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 =
|
|
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
|
-
|
|
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
|
-
|
|
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
|
|
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 =
|
|
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(() => (
|
|
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
|
|
16419
|
-
import { dirname as
|
|
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 =
|
|
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
|
-
|
|
16472
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
|
16773
|
-
import { appendFileSync, existsSync as existsSync16, mkdirSync as
|
|
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
|
-
|
|
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 =
|
|
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
|
|
15904
|
+
chmodSync as chmodSync3,
|
|
17101
15905
|
closeSync as closeSync4,
|
|
17102
15906
|
existsSync as existsSync17,
|
|
17103
15907
|
fsyncSync as fsyncSync4,
|
|
17104
|
-
mkdirSync as
|
|
15908
|
+
mkdirSync as mkdirSync8,
|
|
17105
15909
|
openSync as openSync4,
|
|
17106
|
-
renameSync as
|
|
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
|
|
15915
|
+
import { dirname as dirname10 } from "node:path";
|
|
17112
15916
|
function atomicWrite(path, content, opts = {}) {
|
|
17113
15917
|
const tmpPath = `${path}.tmp`;
|
|
17114
|
-
const parentDir =
|
|
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
|
-
|
|
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
|
-
|
|
15937
|
+
chmodSync3(tmpPath, opts.mode);
|
|
17134
15938
|
}
|
|
17135
|
-
|
|
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
|
|
16022
|
+
import { createHash as createHash5 } from "node:crypto";
|
|
17219
16023
|
import nacl from "tweetnacl";
|
|
17220
16024
|
function sha256Hex(bytes) {
|
|
17221
|
-
return
|
|
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
|
|
17482
|
-
import { homedir as
|
|
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(
|
|
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 =
|
|
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
|
|
17688
|
-
import { homedir as
|
|
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
|
|
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 =
|
|
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 =
|
|
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
|
|
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(
|
|
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(
|
|
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
|
|
17784
|
-
import { join as
|
|
17785
|
-
import { homedir as
|
|
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
|
|
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 =
|
|
16607
|
+
entries = readdirSync12(currentDir);
|
|
17804
16608
|
} catch {
|
|
17805
16609
|
return;
|
|
17806
16610
|
}
|
|
17807
16611
|
for (const entry of entries.sort()) {
|
|
17808
|
-
const absPath =
|
|
16612
|
+
const absPath = join10(currentDir, entry);
|
|
17809
16613
|
let lst;
|
|
17810
16614
|
try {
|
|
17811
|
-
lst =
|
|
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 =
|
|
16639
|
+
const top = createHash7("sha256");
|
|
17836
16640
|
for (const f2 of files) {
|
|
17837
|
-
const fileHash =
|
|
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(
|
|
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(
|
|
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
|
|
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 =
|
|
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 =
|
|
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 =
|
|
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 =
|
|
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(
|
|
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
|
|
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 =
|
|
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(
|
|
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,12 +17607,12 @@ var init_adapters2 = __esm({
|
|
|
18803
17607
|
|
|
18804
17608
|
// src/db.ts
|
|
18805
17609
|
import Database2 from "better-sqlite3";
|
|
18806
|
-
import { dirname as
|
|
18807
|
-
import { existsSync as existsSync23, mkdirSync as
|
|
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)) {
|
|
18811
|
-
throw new
|
|
17615
|
+
throw new CodegraphDbNotInitializedError(dbPath);
|
|
18812
17616
|
}
|
|
18813
17617
|
const db = new Database2(dbPath, { readonly: true });
|
|
18814
17618
|
db.pragma("journal_mode = WAL");
|
|
@@ -18816,9 +17620,9 @@ function getCodeGraphDb() {
|
|
|
18816
17620
|
}
|
|
18817
17621
|
function getDataDb() {
|
|
18818
17622
|
const dbPath = getResolvedPaths().dataDbPath;
|
|
18819
|
-
const dir =
|
|
17623
|
+
const dir = dirname11(dbPath);
|
|
18820
17624
|
if (!existsSync23(dir)) {
|
|
18821
|
-
|
|
17625
|
+
mkdirSync9(dir, { recursive: true });
|
|
18822
17626
|
}
|
|
18823
17627
|
const db = new Database2(dbPath);
|
|
18824
17628
|
db.pragma("journal_mode = WAL");
|
|
@@ -19072,25 +17876,25 @@ function initDataSchema(db) {
|
|
|
19072
17876
|
END;
|
|
19073
17877
|
`);
|
|
19074
17878
|
}
|
|
19075
|
-
function isDataStale(
|
|
19076
|
-
const lastBuild =
|
|
17879
|
+
function isDataStale(dataDb, codegraphDb) {
|
|
17880
|
+
const lastBuild = dataDb.prepare("SELECT value FROM massu_meta WHERE key = 'last_build_time'").get();
|
|
19077
17881
|
if (!lastBuild) return true;
|
|
19078
|
-
const latestIndexed =
|
|
17882
|
+
const latestIndexed = codegraphDb.prepare("SELECT MAX(indexed_at) as latest FROM files").get();
|
|
19079
17883
|
if (!latestIndexed?.latest) return true;
|
|
19080
17884
|
return latestIndexed.latest * 1e3 > new Date(lastBuild.value).getTime();
|
|
19081
17885
|
}
|
|
19082
|
-
function updateBuildTimestamp(
|
|
19083
|
-
|
|
17886
|
+
function updateBuildTimestamp(dataDb) {
|
|
17887
|
+
dataDb.prepare("INSERT OR REPLACE INTO massu_meta (key, value) VALUES ('last_build_time', ?)").run((/* @__PURE__ */ new Date()).toISOString());
|
|
19084
17888
|
}
|
|
19085
|
-
function isPythonDataStale(
|
|
19086
|
-
const lastBuild =
|
|
17889
|
+
function isPythonDataStale(dataDb, pythonRoot) {
|
|
17890
|
+
const lastBuild = dataDb.prepare("SELECT value FROM massu_py_meta WHERE key = 'last_build_time'").get();
|
|
19087
17891
|
if (!lastBuild) return true;
|
|
19088
17892
|
const lastBuildTime = new Date(lastBuild.value).getTime();
|
|
19089
17893
|
function checkDir(dir) {
|
|
19090
17894
|
try {
|
|
19091
|
-
const entries =
|
|
17895
|
+
const entries = readdirSync14(dir, { withFileTypes: true });
|
|
19092
17896
|
for (const entry of entries) {
|
|
19093
|
-
const fullPath =
|
|
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;
|
|
@@ -19104,13 +17908,22 @@ function isPythonDataStale(dataDb2, pythonRoot) {
|
|
|
19104
17908
|
}
|
|
19105
17909
|
return checkDir(pythonRoot);
|
|
19106
17910
|
}
|
|
19107
|
-
function updatePythonBuildTimestamp(
|
|
19108
|
-
|
|
17911
|
+
function updatePythonBuildTimestamp(dataDb) {
|
|
17912
|
+
dataDb.prepare("INSERT OR REPLACE INTO massu_py_meta (key, value) VALUES ('last_build_time', ?)").run((/* @__PURE__ */ new Date()).toISOString());
|
|
19109
17913
|
}
|
|
17914
|
+
var CodegraphDbNotInitializedError;
|
|
19110
17915
|
var init_db = __esm({
|
|
19111
17916
|
"src/db.ts"() {
|
|
19112
17917
|
"use strict";
|
|
19113
17918
|
init_config();
|
|
17919
|
+
CodegraphDbNotInitializedError = class extends Error {
|
|
17920
|
+
dbPath;
|
|
17921
|
+
constructor(dbPath) {
|
|
17922
|
+
super(`CodeGraph database not found at ${dbPath}`);
|
|
17923
|
+
this.name = "CodegraphDbNotInitializedError";
|
|
17924
|
+
this.dbPath = dbPath;
|
|
17925
|
+
}
|
|
17926
|
+
};
|
|
19114
17927
|
}
|
|
19115
17928
|
});
|
|
19116
17929
|
|
|
@@ -19191,8 +18004,8 @@ var init_rules = __esm({
|
|
|
19191
18004
|
});
|
|
19192
18005
|
|
|
19193
18006
|
// src/import-resolver.ts
|
|
19194
|
-
import { readFileSync as
|
|
19195
|
-
import { resolve as resolve20, dirname as
|
|
18007
|
+
import { readFileSync as readFileSync22, existsSync as existsSync24, statSync as statSync12 } from "fs";
|
|
18008
|
+
import { resolve as resolve20, dirname as dirname12, join as join12 } from "path";
|
|
19196
18009
|
function parseImports(source) {
|
|
19197
18010
|
const imports = [];
|
|
19198
18011
|
const lines = source.split("\n");
|
|
@@ -19250,7 +18063,7 @@ function resolveImportPath(specifier, fromFile) {
|
|
|
19250
18063
|
const paths = getResolvedPaths();
|
|
19251
18064
|
basePath = resolve20(paths.pathAlias["@"] ?? paths.srcDir, specifier.slice(2));
|
|
19252
18065
|
} else {
|
|
19253
|
-
basePath = resolve20(
|
|
18066
|
+
basePath = resolve20(dirname12(fromFile), specifier);
|
|
19254
18067
|
}
|
|
19255
18068
|
if (existsSync24(basePath) && !isDirectory(basePath)) {
|
|
19256
18069
|
return toRelative(basePath);
|
|
@@ -19263,7 +18076,7 @@ function resolveImportPath(specifier, fromFile) {
|
|
|
19263
18076
|
}
|
|
19264
18077
|
}
|
|
19265
18078
|
for (const indexFile of resolvedPaths.indexFiles) {
|
|
19266
|
-
const indexPath =
|
|
18079
|
+
const indexPath = join12(basePath, indexFile);
|
|
19267
18080
|
if (existsSync24(indexPath)) {
|
|
19268
18081
|
return toRelative(indexPath);
|
|
19269
18082
|
}
|
|
@@ -19284,15 +18097,15 @@ function toRelative(absPath) {
|
|
|
19284
18097
|
}
|
|
19285
18098
|
return absPath;
|
|
19286
18099
|
}
|
|
19287
|
-
function buildImportIndex(
|
|
19288
|
-
const files =
|
|
19289
|
-
|
|
19290
|
-
const insertStmt =
|
|
18100
|
+
function buildImportIndex(dataDb, codegraphDb) {
|
|
18101
|
+
const files = codegraphDb.prepare("SELECT path FROM files WHERE path LIKE 'src/%'").all();
|
|
18102
|
+
dataDb.exec("DELETE FROM massu_imports");
|
|
18103
|
+
const insertStmt = dataDb.prepare(
|
|
19291
18104
|
"INSERT INTO massu_imports (source_file, target_file, import_type, imported_names, line) VALUES (?, ?, ?, ?, ?)"
|
|
19292
18105
|
);
|
|
19293
18106
|
let edgeCount = 0;
|
|
19294
18107
|
const projectRoot = getProjectRoot();
|
|
19295
|
-
const insertMany =
|
|
18108
|
+
const insertMany = dataDb.transaction((edges) => {
|
|
19296
18109
|
for (const edge of edges) {
|
|
19297
18110
|
insertStmt.run(edge.source_file, edge.target_file, edge.import_type, edge.imported_names, edge.line);
|
|
19298
18111
|
}
|
|
@@ -19304,7 +18117,7 @@ function buildImportIndex(dataDb2, codegraphDb2) {
|
|
|
19304
18117
|
if (!existsSync24(absPath)) continue;
|
|
19305
18118
|
let source;
|
|
19306
18119
|
try {
|
|
19307
|
-
source =
|
|
18120
|
+
source = readFileSync22(absPath, "utf-8");
|
|
19308
18121
|
} catch {
|
|
19309
18122
|
continue;
|
|
19310
18123
|
}
|
|
@@ -19340,15 +18153,15 @@ var init_import_resolver = __esm({
|
|
|
19340
18153
|
});
|
|
19341
18154
|
|
|
19342
18155
|
// src/trpc-index.ts
|
|
19343
|
-
import { readFileSync as
|
|
19344
|
-
import { resolve as resolve21, join as
|
|
18156
|
+
import { readFileSync as readFileSync23, existsSync as existsSync25, readdirSync as readdirSync15 } from "fs";
|
|
18157
|
+
import { resolve as resolve21, join as join13 } from "path";
|
|
19345
18158
|
function parseRootRouter() {
|
|
19346
18159
|
const paths = getResolvedPaths();
|
|
19347
18160
|
const rootPath = paths.rootRouterPath;
|
|
19348
18161
|
if (!existsSync25(rootPath)) {
|
|
19349
18162
|
throw new Error(`Root router not found at ${rootPath}`);
|
|
19350
18163
|
}
|
|
19351
|
-
const source =
|
|
18164
|
+
const source = readFileSync23(rootPath, "utf-8");
|
|
19352
18165
|
const mappings = [];
|
|
19353
18166
|
const importMap = /* @__PURE__ */ new Map();
|
|
19354
18167
|
const importRegex = /import\s+\{[^}]*?(\w+Router)[^}]*\}\s+from\s+['"]\.\/routers\/([^'"]+)['"]/g;
|
|
@@ -19364,7 +18177,7 @@ function parseRootRouter() {
|
|
|
19364
18177
|
filePath = routersRelPath + "/" + filePath + ext;
|
|
19365
18178
|
break;
|
|
19366
18179
|
}
|
|
19367
|
-
const indexCandidate =
|
|
18180
|
+
const indexCandidate = join13(fullPath, "index.ts");
|
|
19368
18181
|
if (existsSync25(indexCandidate)) {
|
|
19369
18182
|
filePath = routersRelPath + "/" + filePath + "/index.ts";
|
|
19370
18183
|
break;
|
|
@@ -19386,7 +18199,7 @@ function parseRootRouter() {
|
|
|
19386
18199
|
function extractProcedures(routerFilePath) {
|
|
19387
18200
|
const absPath = resolve21(getProjectRoot(), routerFilePath);
|
|
19388
18201
|
if (!existsSync25(absPath)) return [];
|
|
19389
|
-
const source =
|
|
18202
|
+
const source = readFileSync23(absPath, "utf-8");
|
|
19390
18203
|
const procedures = [];
|
|
19391
18204
|
const seen = /* @__PURE__ */ new Set();
|
|
19392
18205
|
const procRegex = /(\w+)\s*:\s*(protected|public)Procedure/g;
|
|
@@ -19421,15 +18234,15 @@ function findUICallSites(routerKey, procedureName) {
|
|
|
19421
18234
|
return callSites;
|
|
19422
18235
|
}
|
|
19423
18236
|
function searchDirectory(dir, pattern, results) {
|
|
19424
|
-
const entries =
|
|
18237
|
+
const entries = readdirSync15(dir, { withFileTypes: true });
|
|
19425
18238
|
for (const entry of entries) {
|
|
19426
|
-
const fullPath =
|
|
18239
|
+
const fullPath = join13(dir, entry.name);
|
|
19427
18240
|
if (entry.isDirectory()) {
|
|
19428
18241
|
if (entry.name === "node_modules" || entry.name === ".next") continue;
|
|
19429
18242
|
searchDirectory(fullPath, pattern, results);
|
|
19430
18243
|
} else if (entry.name.endsWith(".ts") || entry.name.endsWith(".tsx")) {
|
|
19431
18244
|
try {
|
|
19432
|
-
const source =
|
|
18245
|
+
const source = readFileSync23(fullPath, "utf-8");
|
|
19433
18246
|
const lines = source.split("\n");
|
|
19434
18247
|
for (let i = 0; i < lines.length; i++) {
|
|
19435
18248
|
if (lines[i].includes(pattern)) {
|
|
@@ -19451,20 +18264,20 @@ function searchDirectory(dir, pattern, results) {
|
|
|
19451
18264
|
function escapeRegex2(str) {
|
|
19452
18265
|
return str.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
|
|
19453
18266
|
}
|
|
19454
|
-
function buildTrpcIndex(
|
|
19455
|
-
|
|
19456
|
-
|
|
18267
|
+
function buildTrpcIndex(dataDb) {
|
|
18268
|
+
dataDb.exec("DELETE FROM massu_trpc_call_sites");
|
|
18269
|
+
dataDb.exec("DELETE FROM massu_trpc_procedures");
|
|
19457
18270
|
const routerMappings = parseRootRouter();
|
|
19458
|
-
const insertProc =
|
|
18271
|
+
const insertProc = dataDb.prepare(
|
|
19459
18272
|
"INSERT INTO massu_trpc_procedures (router_file, router_name, procedure_name, procedure_type, has_ui_caller) VALUES (?, ?, ?, ?, ?)"
|
|
19460
18273
|
);
|
|
19461
|
-
const insertCallSite =
|
|
18274
|
+
const insertCallSite = dataDb.prepare(
|
|
19462
18275
|
"INSERT INTO massu_trpc_call_sites (procedure_id, file, line, call_pattern) VALUES (?, ?, ?, ?)"
|
|
19463
18276
|
);
|
|
19464
18277
|
let totalProcedures = 0;
|
|
19465
18278
|
let withCallers = 0;
|
|
19466
18279
|
let withoutCallers = 0;
|
|
19467
|
-
const insertAll =
|
|
18280
|
+
const insertAll = dataDb.transaction(() => {
|
|
19468
18281
|
for (const router of routerMappings) {
|
|
19469
18282
|
const procedures = extractProcedures(router.file);
|
|
19470
18283
|
for (const proc of procedures) {
|
|
@@ -19492,7 +18305,7 @@ var init_trpc_index = __esm({
|
|
|
19492
18305
|
});
|
|
19493
18306
|
|
|
19494
18307
|
// src/page-deps.ts
|
|
19495
|
-
import { readFileSync as
|
|
18308
|
+
import { readFileSync as readFileSync24, existsSync as existsSync26 } from "fs";
|
|
19496
18309
|
import { resolve as resolve22 } from "path";
|
|
19497
18310
|
function deriveRoute(pageFile) {
|
|
19498
18311
|
let route = pageFile.replace(/^src\/app/, "").replace(/\/page\.tsx?$/, "").replace(/\/page\.jsx?$/, "");
|
|
@@ -19508,10 +18321,10 @@ function derivePortal(route) {
|
|
|
19508
18321
|
const parts = route.split("/").filter(Boolean);
|
|
19509
18322
|
return parts[0] ?? "default";
|
|
19510
18323
|
}
|
|
19511
|
-
function traceImports(startFile,
|
|
18324
|
+
function traceImports(startFile, dataDb, visited, components, hooks, maxDepth = 5) {
|
|
19512
18325
|
if (maxDepth <= 0 || visited.has(startFile)) return;
|
|
19513
18326
|
visited.add(startFile);
|
|
19514
|
-
const imports =
|
|
18327
|
+
const imports = dataDb.prepare(
|
|
19515
18328
|
"SELECT target_file, imported_names FROM massu_imports WHERE source_file = ?"
|
|
19516
18329
|
).all(startFile);
|
|
19517
18330
|
for (const imp of imports) {
|
|
@@ -19523,7 +18336,7 @@ function traceImports(startFile, dataDb2, visited, components, hooks, maxDepth =
|
|
|
19523
18336
|
hooks.add(target);
|
|
19524
18337
|
}
|
|
19525
18338
|
if (target.startsWith("src/")) {
|
|
19526
|
-
traceImports(target,
|
|
18339
|
+
traceImports(target, dataDb, visited, components, hooks, maxDepth - 1);
|
|
19527
18340
|
}
|
|
19528
18341
|
}
|
|
19529
18342
|
}
|
|
@@ -19534,7 +18347,7 @@ function findRouterCalls(files) {
|
|
|
19534
18347
|
const absPath = ensureWithinRoot(resolve22(projectRoot, file), projectRoot);
|
|
19535
18348
|
if (!existsSync26(absPath)) continue;
|
|
19536
18349
|
try {
|
|
19537
|
-
const source =
|
|
18350
|
+
const source = readFileSync24(absPath, "utf-8");
|
|
19538
18351
|
const apiCallRegex = /api\.(\w+)\.\w+/g;
|
|
19539
18352
|
let match;
|
|
19540
18353
|
while ((match = apiCallRegex.exec(source)) !== null) {
|
|
@@ -19545,17 +18358,17 @@ function findRouterCalls(files) {
|
|
|
19545
18358
|
}
|
|
19546
18359
|
return [...routers];
|
|
19547
18360
|
}
|
|
19548
|
-
function findTablesFromRouters(routerNames,
|
|
18361
|
+
function findTablesFromRouters(routerNames, dataDb) {
|
|
19549
18362
|
const tables = /* @__PURE__ */ new Set();
|
|
19550
18363
|
for (const routerName of routerNames) {
|
|
19551
|
-
const procs =
|
|
18364
|
+
const procs = dataDb.prepare(
|
|
19552
18365
|
"SELECT DISTINCT router_file FROM massu_trpc_procedures WHERE router_name = ?"
|
|
19553
18366
|
).all(routerName);
|
|
19554
18367
|
for (const proc of procs) {
|
|
19555
18368
|
const absPath = ensureWithinRoot(resolve22(getProjectRoot(), proc.router_file), getProjectRoot());
|
|
19556
18369
|
if (!existsSync26(absPath)) continue;
|
|
19557
18370
|
try {
|
|
19558
|
-
const source =
|
|
18371
|
+
const source = readFileSync24(absPath, "utf-8");
|
|
19559
18372
|
const dbPattern = getConfig().dbAccessPattern ?? "ctx.db.{table}";
|
|
19560
18373
|
const regexStr = dbPattern.replace(/[.*+?^${}()|[\]\\]/g, "\\$&").replace("\\{table\\}", "(\\w+)");
|
|
19561
18374
|
const tableRegex = new RegExp(regexStr + "\\.", "g");
|
|
@@ -19569,26 +18382,26 @@ function findTablesFromRouters(routerNames, dataDb2) {
|
|
|
19569
18382
|
}
|
|
19570
18383
|
return [...tables];
|
|
19571
18384
|
}
|
|
19572
|
-
function buildPageDeps(
|
|
19573
|
-
|
|
19574
|
-
const pages =
|
|
18385
|
+
function buildPageDeps(dataDb, codegraphDb) {
|
|
18386
|
+
dataDb.exec("DELETE FROM massu_page_deps");
|
|
18387
|
+
const pages = codegraphDb.prepare(
|
|
19575
18388
|
"SELECT path FROM files WHERE path LIKE 'src/app/%/page.tsx' OR path = 'src/app/page.tsx'"
|
|
19576
18389
|
).all();
|
|
19577
|
-
const insertStmt =
|
|
18390
|
+
const insertStmt = dataDb.prepare(
|
|
19578
18391
|
"INSERT INTO massu_page_deps (page_file, route, portal, components, hooks, routers, tables_touched) VALUES (?, ?, ?, ?, ?, ?, ?)"
|
|
19579
18392
|
);
|
|
19580
18393
|
let count = 0;
|
|
19581
|
-
const insertAll =
|
|
18394
|
+
const insertAll = dataDb.transaction(() => {
|
|
19582
18395
|
for (const page of pages) {
|
|
19583
18396
|
const route = deriveRoute(page.path);
|
|
19584
18397
|
const portal = derivePortal(route);
|
|
19585
18398
|
const visited = /* @__PURE__ */ new Set();
|
|
19586
18399
|
const components = /* @__PURE__ */ new Set();
|
|
19587
18400
|
const hooks = /* @__PURE__ */ new Set();
|
|
19588
|
-
traceImports(page.path,
|
|
18401
|
+
traceImports(page.path, dataDb, visited, components, hooks);
|
|
19589
18402
|
const allFiles = [...visited];
|
|
19590
18403
|
const routers = findRouterCalls(allFiles);
|
|
19591
|
-
const tables = findTablesFromRouters(routers,
|
|
18404
|
+
const tables = findTablesFromRouters(routers, dataDb);
|
|
19592
18405
|
insertStmt.run(
|
|
19593
18406
|
page.path,
|
|
19594
18407
|
route,
|
|
@@ -19604,8 +18417,8 @@ function buildPageDeps(dataDb2, codegraphDb2) {
|
|
|
19604
18417
|
insertAll();
|
|
19605
18418
|
return count;
|
|
19606
18419
|
}
|
|
19607
|
-
function getPageChain(
|
|
19608
|
-
const row =
|
|
18420
|
+
function getPageChain(dataDb, pageFile) {
|
|
18421
|
+
const row = dataDb.prepare("SELECT * FROM massu_page_deps WHERE page_file = ?").get(pageFile);
|
|
19609
18422
|
if (!row) return null;
|
|
19610
18423
|
return {
|
|
19611
18424
|
page: row.page_file,
|
|
@@ -19617,10 +18430,10 @@ function getPageChain(dataDb2, pageFile) {
|
|
|
19617
18430
|
tables: JSON.parse(row.tables_touched)
|
|
19618
18431
|
};
|
|
19619
18432
|
}
|
|
19620
|
-
function findAffectedPages(
|
|
19621
|
-
const directPage = getPageChain(
|
|
18433
|
+
function findAffectedPages(dataDb, file) {
|
|
18434
|
+
const directPage = getPageChain(dataDb, file);
|
|
19622
18435
|
if (directPage) return [directPage];
|
|
19623
|
-
const importers =
|
|
18436
|
+
const importers = dataDb.prepare(
|
|
19624
18437
|
"SELECT source_file FROM massu_imports WHERE target_file = ?"
|
|
19625
18438
|
).all(file);
|
|
19626
18439
|
const affectedFiles = /* @__PURE__ */ new Set([file, ...importers.map((i) => i.source_file)]);
|
|
@@ -19631,7 +18444,7 @@ function findAffectedPages(dataDb2, file) {
|
|
|
19631
18444
|
while (frontier.length > 0 && depth < maxDepth) {
|
|
19632
18445
|
const next = [];
|
|
19633
18446
|
for (const f2 of frontier) {
|
|
19634
|
-
const upstreamImporters =
|
|
18447
|
+
const upstreamImporters = dataDb.prepare(
|
|
19635
18448
|
"SELECT source_file FROM massu_imports WHERE target_file = ?"
|
|
19636
18449
|
).all(f2);
|
|
19637
18450
|
for (const imp of upstreamImporters) {
|
|
@@ -19645,7 +18458,7 @@ function findAffectedPages(dataDb2, file) {
|
|
|
19645
18458
|
frontier = next;
|
|
19646
18459
|
depth++;
|
|
19647
18460
|
}
|
|
19648
|
-
const allPages =
|
|
18461
|
+
const allPages = dataDb.prepare("SELECT * FROM massu_page_deps").all();
|
|
19649
18462
|
const results = [];
|
|
19650
18463
|
for (const row of allPages) {
|
|
19651
18464
|
if (affectedFiles.has(row.page_file)) {
|
|
@@ -19671,8 +18484,8 @@ var init_page_deps = __esm({
|
|
|
19671
18484
|
});
|
|
19672
18485
|
|
|
19673
18486
|
// src/middleware-tree.ts
|
|
19674
|
-
function buildMiddlewareTree(
|
|
19675
|
-
|
|
18487
|
+
function buildMiddlewareTree(dataDb) {
|
|
18488
|
+
dataDb.exec("DELETE FROM massu_middleware_tree");
|
|
19676
18489
|
const config = getConfig();
|
|
19677
18490
|
const middlewareFile = config.paths.middleware ?? "src/middleware.ts";
|
|
19678
18491
|
if (!middlewareFile) return 0;
|
|
@@ -19681,7 +18494,7 @@ function buildMiddlewareTree(dataDb2) {
|
|
|
19681
18494
|
visited.add(middlewareFile);
|
|
19682
18495
|
while (queue.length > 0) {
|
|
19683
18496
|
const current = queue.shift();
|
|
19684
|
-
const imports =
|
|
18497
|
+
const imports = dataDb.prepare(
|
|
19685
18498
|
"SELECT target_file FROM massu_imports WHERE source_file = ?"
|
|
19686
18499
|
).all(current);
|
|
19687
18500
|
for (const imp of imports) {
|
|
@@ -19691,8 +18504,8 @@ function buildMiddlewareTree(dataDb2) {
|
|
|
19691
18504
|
}
|
|
19692
18505
|
}
|
|
19693
18506
|
}
|
|
19694
|
-
const insertStmt =
|
|
19695
|
-
const insertAll =
|
|
18507
|
+
const insertStmt = dataDb.prepare("INSERT INTO massu_middleware_tree (file) VALUES (?)");
|
|
18508
|
+
const insertAll = dataDb.transaction(() => {
|
|
19696
18509
|
for (const file of visited) {
|
|
19697
18510
|
insertStmt.run(file);
|
|
19698
18511
|
}
|
|
@@ -19700,8 +18513,8 @@ function buildMiddlewareTree(dataDb2) {
|
|
|
19700
18513
|
insertAll();
|
|
19701
18514
|
return visited.size;
|
|
19702
18515
|
}
|
|
19703
|
-
function isInMiddlewareTree(
|
|
19704
|
-
const result =
|
|
18516
|
+
function isInMiddlewareTree(dataDb, file) {
|
|
18517
|
+
const result = dataDb.prepare("SELECT 1 FROM massu_middleware_tree WHERE file = ?").get(file);
|
|
19705
18518
|
return result !== void 0;
|
|
19706
18519
|
}
|
|
19707
18520
|
var init_middleware_tree = __esm({
|
|
@@ -19763,12 +18576,12 @@ function globMatchSimple(name, pattern) {
|
|
|
19763
18576
|
const regexStr = pattern.replace(/\./g, "\\.").replace(/\*/g, ".*").replace(/\?/g, ".");
|
|
19764
18577
|
return new RegExp(`^${regexStr}$`).test(name);
|
|
19765
18578
|
}
|
|
19766
|
-
function findCrossDomainImports(
|
|
18579
|
+
function findCrossDomainImports(dataDb) {
|
|
19767
18580
|
const domains = getDomains();
|
|
19768
18581
|
const config = getConfig();
|
|
19769
18582
|
const srcPrefix = config.paths.source;
|
|
19770
18583
|
const srcPattern = srcPrefix + "/%";
|
|
19771
|
-
const imports =
|
|
18584
|
+
const imports = dataDb.prepare(
|
|
19772
18585
|
"SELECT source_file, target_file FROM massu_imports WHERE source_file LIKE ? AND target_file LIKE ?"
|
|
19773
18586
|
).all(srcPattern, srcPattern);
|
|
19774
18587
|
const crossings = [];
|
|
@@ -19790,7 +18603,7 @@ function findCrossDomainImports(dataDb2) {
|
|
|
19790
18603
|
}
|
|
19791
18604
|
return crossings;
|
|
19792
18605
|
}
|
|
19793
|
-
function getFilesInDomain(
|
|
18606
|
+
function getFilesInDomain(dataDb, codegraphDb, domainName) {
|
|
19794
18607
|
const domains = getDomains();
|
|
19795
18608
|
const config = getConfig();
|
|
19796
18609
|
const domain = domains.find((d2) => d2.name === domainName);
|
|
@@ -19798,7 +18611,7 @@ function getFilesInDomain(dataDb2, codegraphDb2, domainName) {
|
|
|
19798
18611
|
const srcPrefix = config.paths.source;
|
|
19799
18612
|
const routersPath = config.paths.routers ?? "src/server/api/routers";
|
|
19800
18613
|
const srcPattern = srcPrefix + "/%";
|
|
19801
|
-
const allFiles =
|
|
18614
|
+
const allFiles = codegraphDb.prepare("SELECT path FROM files WHERE path LIKE ?").all(srcPattern);
|
|
19802
18615
|
const routers = [];
|
|
19803
18616
|
const pages = [];
|
|
19804
18617
|
const components = [];
|
|
@@ -19824,14 +18637,14 @@ var init_domains = __esm({
|
|
|
19824
18637
|
});
|
|
19825
18638
|
|
|
19826
18639
|
// src/schema-mapper.ts
|
|
19827
|
-
import { readFileSync as
|
|
19828
|
-
import { join as
|
|
18640
|
+
import { readFileSync as readFileSync25, existsSync as existsSync27, readdirSync as readdirSync16 } from "fs";
|
|
18641
|
+
import { join as join14 } from "path";
|
|
19829
18642
|
function parsePrismaSchema() {
|
|
19830
18643
|
const schemaPath = getResolvedPaths().prismaSchemaPath;
|
|
19831
18644
|
if (!existsSync27(schemaPath)) {
|
|
19832
18645
|
throw new Error(`Prisma schema not found at ${schemaPath}`);
|
|
19833
18646
|
}
|
|
19834
|
-
const source =
|
|
18647
|
+
const source = readFileSync25(schemaPath, "utf-8");
|
|
19835
18648
|
const models = [];
|
|
19836
18649
|
const sourceLines = source.split("\n");
|
|
19837
18650
|
let i = 0;
|
|
@@ -19894,9 +18707,9 @@ function findColumnUsageInRouters(tableName) {
|
|
|
19894
18707
|
return usage;
|
|
19895
18708
|
}
|
|
19896
18709
|
function scanDirectory(dir, tableName, usage) {
|
|
19897
|
-
const entries =
|
|
18710
|
+
const entries = readdirSync16(dir, { withFileTypes: true });
|
|
19898
18711
|
for (const entry of entries) {
|
|
19899
|
-
const fullPath =
|
|
18712
|
+
const fullPath = join14(dir, entry.name);
|
|
19900
18713
|
if (entry.isDirectory()) {
|
|
19901
18714
|
scanDirectory(fullPath, tableName, usage);
|
|
19902
18715
|
} else if (entry.name.endsWith(".ts")) {
|
|
@@ -19906,7 +18719,7 @@ function scanDirectory(dir, tableName, usage) {
|
|
|
19906
18719
|
}
|
|
19907
18720
|
function scanFile(absPath, tableName, usage) {
|
|
19908
18721
|
try {
|
|
19909
|
-
const source =
|
|
18722
|
+
const source = readFileSync25(absPath, "utf-8");
|
|
19910
18723
|
if (!source.includes(tableName)) return;
|
|
19911
18724
|
const relPath = absPath.slice(getProjectRoot().length + 1);
|
|
19912
18725
|
const lines = source.split("\n");
|
|
@@ -19952,14 +18765,14 @@ function detectMismatches(models) {
|
|
|
19952
18765
|
function findFilesUsingColumn(dir, column, tableName) {
|
|
19953
18766
|
const result = [];
|
|
19954
18767
|
if (!existsSync27(dir)) return result;
|
|
19955
|
-
const entries =
|
|
18768
|
+
const entries = readdirSync16(dir, { withFileTypes: true });
|
|
19956
18769
|
for (const entry of entries) {
|
|
19957
|
-
const fullPath =
|
|
18770
|
+
const fullPath = join14(dir, entry.name);
|
|
19958
18771
|
if (entry.isDirectory()) {
|
|
19959
18772
|
result.push(...findFilesUsingColumn(fullPath, column, tableName));
|
|
19960
18773
|
} else if (entry.name.endsWith(".ts")) {
|
|
19961
18774
|
try {
|
|
19962
|
-
const source =
|
|
18775
|
+
const source = readFileSync25(fullPath, "utf-8");
|
|
19963
18776
|
if (source.includes(tableName) && source.includes(column)) {
|
|
19964
18777
|
result.push(fullPath.slice(getProjectRoot().length + 1));
|
|
19965
18778
|
}
|
|
@@ -20104,32 +18917,32 @@ var init_import_parser = __esm({
|
|
|
20104
18917
|
});
|
|
20105
18918
|
|
|
20106
18919
|
// src/python/import-resolver.ts
|
|
20107
|
-
import { readFileSync as
|
|
20108
|
-
import { resolve as resolve24, join as
|
|
18920
|
+
import { readFileSync as readFileSync26, existsSync as existsSync28, readdirSync as readdirSync17 } from "fs";
|
|
18921
|
+
import { resolve as resolve24, join as join15, relative as relative6, dirname as dirname13 } from "path";
|
|
20109
18922
|
function resolvePythonModulePath(module, fromFile, pythonRoot, level) {
|
|
20110
18923
|
const projectRoot = getProjectRoot();
|
|
20111
18924
|
if (level > 0) {
|
|
20112
|
-
let baseDir =
|
|
18925
|
+
let baseDir = dirname13(resolve24(projectRoot, fromFile));
|
|
20113
18926
|
for (let i = 1; i < level; i++) {
|
|
20114
|
-
baseDir =
|
|
18927
|
+
baseDir = dirname13(baseDir);
|
|
20115
18928
|
}
|
|
20116
18929
|
const modulePart = module.replace(/^\.+/, "");
|
|
20117
18930
|
if (modulePart) {
|
|
20118
18931
|
const parts2 = modulePart.split(".");
|
|
20119
|
-
return tryResolvePythonPath(
|
|
18932
|
+
return tryResolvePythonPath(join15(baseDir, ...parts2), projectRoot);
|
|
20120
18933
|
}
|
|
20121
18934
|
return tryResolvePythonPath(baseDir, projectRoot);
|
|
20122
18935
|
}
|
|
20123
18936
|
const parts = module.split(".");
|
|
20124
|
-
const candidate =
|
|
18937
|
+
const candidate = join15(resolve24(projectRoot, pythonRoot), ...parts);
|
|
20125
18938
|
return tryResolvePythonPath(candidate, projectRoot);
|
|
20126
18939
|
}
|
|
20127
18940
|
function tryResolvePythonPath(basePath, projectRoot) {
|
|
20128
18941
|
if (existsSync28(basePath + ".py")) {
|
|
20129
18942
|
return relative6(projectRoot, basePath + ".py");
|
|
20130
18943
|
}
|
|
20131
|
-
if (existsSync28(
|
|
20132
|
-
return relative6(projectRoot,
|
|
18944
|
+
if (existsSync28(join15(basePath, "__init__.py"))) {
|
|
18945
|
+
return relative6(projectRoot, join15(basePath, "__init__.py"));
|
|
20133
18946
|
}
|
|
20134
18947
|
if (basePath.endsWith(".py") && existsSync28(basePath)) {
|
|
20135
18948
|
return relative6(projectRoot, basePath);
|
|
@@ -20139,29 +18952,29 @@ function tryResolvePythonPath(basePath, projectRoot) {
|
|
|
20139
18952
|
function walkPythonFiles(dir, excludeDirs) {
|
|
20140
18953
|
const files = [];
|
|
20141
18954
|
try {
|
|
20142
|
-
const entries =
|
|
18955
|
+
const entries = readdirSync17(dir, { withFileTypes: true });
|
|
20143
18956
|
for (const entry of entries) {
|
|
20144
18957
|
if (entry.isDirectory()) {
|
|
20145
18958
|
if (excludeDirs.includes(entry.name)) continue;
|
|
20146
|
-
files.push(...walkPythonFiles(
|
|
18959
|
+
files.push(...walkPythonFiles(join15(dir, entry.name), excludeDirs));
|
|
20147
18960
|
} else if (entry.name.endsWith(".py")) {
|
|
20148
|
-
files.push(
|
|
18961
|
+
files.push(join15(dir, entry.name));
|
|
20149
18962
|
}
|
|
20150
18963
|
}
|
|
20151
18964
|
} catch {
|
|
20152
18965
|
}
|
|
20153
18966
|
return files;
|
|
20154
18967
|
}
|
|
20155
|
-
function buildPythonImportIndex(
|
|
18968
|
+
function buildPythonImportIndex(dataDb, pythonRoot, excludeDirs = ["__pycache__", ".venv", "venv", ".mypy_cache", ".pytest_cache"]) {
|
|
20156
18969
|
const projectRoot = getProjectRoot();
|
|
20157
18970
|
const absRoot = resolve24(projectRoot, pythonRoot);
|
|
20158
|
-
|
|
20159
|
-
const insertStmt =
|
|
18971
|
+
dataDb.exec("DELETE FROM massu_py_imports");
|
|
18972
|
+
const insertStmt = dataDb.prepare(
|
|
20160
18973
|
"INSERT INTO massu_py_imports (source_file, target_file, import_type, imported_names, line) VALUES (?, ?, ?, ?, ?)"
|
|
20161
18974
|
);
|
|
20162
18975
|
const files = walkPythonFiles(absRoot, excludeDirs);
|
|
20163
18976
|
let edgeCount = 0;
|
|
20164
|
-
const insertMany =
|
|
18977
|
+
const insertMany = dataDb.transaction((edges) => {
|
|
20165
18978
|
for (const edge of edges) {
|
|
20166
18979
|
insertStmt.run(edge.source, edge.target, edge.type, edge.names, edge.line);
|
|
20167
18980
|
}
|
|
@@ -20171,7 +18984,7 @@ function buildPythonImportIndex(dataDb2, pythonRoot, excludeDirs = ["__pycache__
|
|
|
20171
18984
|
const relFile = relative6(projectRoot, absFile);
|
|
20172
18985
|
let source;
|
|
20173
18986
|
try {
|
|
20174
|
-
source =
|
|
18987
|
+
source = readFileSync26(absFile, "utf-8");
|
|
20175
18988
|
} catch {
|
|
20176
18989
|
continue;
|
|
20177
18990
|
}
|
|
@@ -20437,40 +19250,40 @@ var init_route_parser = __esm({
|
|
|
20437
19250
|
});
|
|
20438
19251
|
|
|
20439
19252
|
// src/python/route-indexer.ts
|
|
20440
|
-
import { readFileSync as
|
|
20441
|
-
import { join as
|
|
19253
|
+
import { readFileSync as readFileSync27, readdirSync as readdirSync18 } from "fs";
|
|
19254
|
+
import { join as join16, relative as relative7 } from "path";
|
|
20442
19255
|
function walkPyFiles(dir, excludeDirs) {
|
|
20443
19256
|
const files = [];
|
|
20444
19257
|
try {
|
|
20445
|
-
const entries =
|
|
19258
|
+
const entries = readdirSync18(dir, { withFileTypes: true });
|
|
20446
19259
|
for (const entry of entries) {
|
|
20447
19260
|
if (entry.isDirectory()) {
|
|
20448
19261
|
if (excludeDirs.includes(entry.name)) continue;
|
|
20449
|
-
files.push(...walkPyFiles(
|
|
19262
|
+
files.push(...walkPyFiles(join16(dir, entry.name), excludeDirs));
|
|
20450
19263
|
} else if (entry.name.endsWith(".py")) {
|
|
20451
|
-
files.push(
|
|
19264
|
+
files.push(join16(dir, entry.name));
|
|
20452
19265
|
}
|
|
20453
19266
|
}
|
|
20454
19267
|
} catch {
|
|
20455
19268
|
}
|
|
20456
19269
|
return files;
|
|
20457
19270
|
}
|
|
20458
|
-
function buildPythonRouteIndex(
|
|
19271
|
+
function buildPythonRouteIndex(dataDb, pythonRoot, excludeDirs = ["__pycache__", ".venv", "venv", ".mypy_cache", ".pytest_cache"]) {
|
|
20459
19272
|
const projectRoot = getProjectRoot();
|
|
20460
|
-
const absRoot =
|
|
20461
|
-
|
|
20462
|
-
|
|
20463
|
-
const insertStmt =
|
|
19273
|
+
const absRoot = join16(projectRoot, pythonRoot);
|
|
19274
|
+
dataDb.exec("DELETE FROM massu_py_routes");
|
|
19275
|
+
dataDb.exec("DELETE FROM massu_py_route_callers");
|
|
19276
|
+
const insertStmt = dataDb.prepare(
|
|
20464
19277
|
"INSERT INTO massu_py_routes (file, method, path, function_name, dependencies, request_model, response_model, is_authenticated, line) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?)"
|
|
20465
19278
|
);
|
|
20466
19279
|
const files = walkPyFiles(absRoot, excludeDirs);
|
|
20467
19280
|
let count = 0;
|
|
20468
|
-
|
|
19281
|
+
dataDb.transaction(() => {
|
|
20469
19282
|
for (const absFile of files) {
|
|
20470
19283
|
const relFile = relative7(projectRoot, absFile);
|
|
20471
19284
|
let source;
|
|
20472
19285
|
try {
|
|
20473
|
-
source =
|
|
19286
|
+
source = readFileSync27(absFile, "utf-8");
|
|
20474
19287
|
} catch {
|
|
20475
19288
|
continue;
|
|
20476
19289
|
}
|
|
@@ -20681,43 +19494,43 @@ var init_model_parser = __esm({
|
|
|
20681
19494
|
});
|
|
20682
19495
|
|
|
20683
19496
|
// src/python/model-indexer.ts
|
|
20684
|
-
import { readFileSync as
|
|
20685
|
-
import { join as
|
|
19497
|
+
import { readFileSync as readFileSync28, readdirSync as readdirSync19 } from "fs";
|
|
19498
|
+
import { join as join17, relative as relative8 } from "path";
|
|
20686
19499
|
function walkPyFiles2(dir, excludeDirs) {
|
|
20687
19500
|
const files = [];
|
|
20688
19501
|
try {
|
|
20689
|
-
const entries =
|
|
19502
|
+
const entries = readdirSync19(dir, { withFileTypes: true });
|
|
20690
19503
|
for (const entry of entries) {
|
|
20691
19504
|
if (entry.isDirectory()) {
|
|
20692
19505
|
if (excludeDirs.includes(entry.name)) continue;
|
|
20693
|
-
files.push(...walkPyFiles2(
|
|
19506
|
+
files.push(...walkPyFiles2(join17(dir, entry.name), excludeDirs));
|
|
20694
19507
|
} else if (entry.name.endsWith(".py")) {
|
|
20695
|
-
files.push(
|
|
19508
|
+
files.push(join17(dir, entry.name));
|
|
20696
19509
|
}
|
|
20697
19510
|
}
|
|
20698
19511
|
} catch {
|
|
20699
19512
|
}
|
|
20700
19513
|
return files;
|
|
20701
19514
|
}
|
|
20702
|
-
function buildPythonModelIndex(
|
|
19515
|
+
function buildPythonModelIndex(dataDb, pythonRoot, excludeDirs = ["__pycache__", ".venv", "venv", ".mypy_cache", ".pytest_cache"]) {
|
|
20703
19516
|
const projectRoot = getProjectRoot();
|
|
20704
|
-
const absRoot =
|
|
20705
|
-
|
|
20706
|
-
|
|
20707
|
-
const insertModel =
|
|
19517
|
+
const absRoot = join17(projectRoot, pythonRoot);
|
|
19518
|
+
dataDb.exec("DELETE FROM massu_py_models");
|
|
19519
|
+
dataDb.exec("DELETE FROM massu_py_fk_edges");
|
|
19520
|
+
const insertModel = dataDb.prepare(
|
|
20708
19521
|
"INSERT INTO massu_py_models (class_name, table_name, file, line, columns, relationships, foreign_keys) VALUES (?, ?, ?, ?, ?, ?, ?)"
|
|
20709
19522
|
);
|
|
20710
|
-
const insertFk =
|
|
19523
|
+
const insertFk = dataDb.prepare(
|
|
20711
19524
|
"INSERT INTO massu_py_fk_edges (source_table, source_column, target_table, target_column) VALUES (?, ?, ?, ?)"
|
|
20712
19525
|
);
|
|
20713
19526
|
const files = walkPyFiles2(absRoot, excludeDirs);
|
|
20714
19527
|
let count = 0;
|
|
20715
|
-
|
|
19528
|
+
dataDb.transaction(() => {
|
|
20716
19529
|
for (const absFile of files) {
|
|
20717
19530
|
const relFile = relative8(projectRoot, absFile);
|
|
20718
19531
|
let source;
|
|
20719
19532
|
try {
|
|
20720
|
-
source =
|
|
19533
|
+
source = readFileSync28(absFile, "utf-8");
|
|
20721
19534
|
} catch {
|
|
20722
19535
|
continue;
|
|
20723
19536
|
}
|
|
@@ -20977,23 +19790,23 @@ var init_migration_parser = __esm({
|
|
|
20977
19790
|
});
|
|
20978
19791
|
|
|
20979
19792
|
// src/python/migration-indexer.ts
|
|
20980
|
-
import { readFileSync as
|
|
20981
|
-
import { join as
|
|
20982
|
-
function buildPythonMigrationIndex(
|
|
19793
|
+
import { readFileSync as readFileSync29, readdirSync as readdirSync20 } from "fs";
|
|
19794
|
+
import { join as join18, relative as relative9 } from "path";
|
|
19795
|
+
function buildPythonMigrationIndex(dataDb, alembicDir) {
|
|
20983
19796
|
const projectRoot = getProjectRoot();
|
|
20984
|
-
const absDir =
|
|
20985
|
-
|
|
20986
|
-
const versionsDir =
|
|
19797
|
+
const absDir = join18(projectRoot, alembicDir);
|
|
19798
|
+
dataDb.exec("DELETE FROM massu_py_migrations");
|
|
19799
|
+
const versionsDir = join18(absDir, "versions");
|
|
20987
19800
|
let files = [];
|
|
20988
19801
|
try {
|
|
20989
|
-
files =
|
|
19802
|
+
files = readdirSync20(versionsDir).filter((f2) => f2.endsWith(".py")).map((f2) => join18(versionsDir, f2));
|
|
20990
19803
|
} catch {
|
|
20991
19804
|
try {
|
|
20992
|
-
files =
|
|
19805
|
+
files = readdirSync20(absDir).filter((f2) => f2.endsWith(".py") && f2 !== "env.py").map((f2) => join18(absDir, f2));
|
|
20993
19806
|
} catch {
|
|
20994
19807
|
}
|
|
20995
19808
|
}
|
|
20996
|
-
const insertStmt =
|
|
19809
|
+
const insertStmt = dataDb.prepare(
|
|
20997
19810
|
"INSERT INTO massu_py_migrations (revision, down_revision, file, description, operations, is_head) VALUES (?, ?, ?, ?, ?, ?)"
|
|
20998
19811
|
);
|
|
20999
19812
|
let count = 0;
|
|
@@ -21003,7 +19816,7 @@ function buildPythonMigrationIndex(dataDb2, alembicDir) {
|
|
|
21003
19816
|
for (const absFile of files) {
|
|
21004
19817
|
let source;
|
|
21005
19818
|
try {
|
|
21006
|
-
source =
|
|
19819
|
+
source = readFileSync29(absFile, "utf-8");
|
|
21007
19820
|
} catch {
|
|
21008
19821
|
continue;
|
|
21009
19822
|
}
|
|
@@ -21019,7 +19832,7 @@ function buildPythonMigrationIndex(dataDb2, alembicDir) {
|
|
|
21019
19832
|
operations: JSON.stringify(parsed.operations)
|
|
21020
19833
|
});
|
|
21021
19834
|
}
|
|
21022
|
-
|
|
19835
|
+
dataDb.transaction(() => {
|
|
21023
19836
|
for (const row of rows) {
|
|
21024
19837
|
const isHead = !hasDownRef.has(row.revision) ? 1 : 0;
|
|
21025
19838
|
insertStmt.run(row.revision, row.downRevision, row.file, row.description, row.operations, isHead);
|
|
@@ -21037,17 +19850,17 @@ var init_migration_indexer = __esm({
|
|
|
21037
19850
|
});
|
|
21038
19851
|
|
|
21039
19852
|
// src/python/coupling-detector.ts
|
|
21040
|
-
import { readFileSync as
|
|
21041
|
-
import { join as
|
|
21042
|
-
function buildPythonCouplingIndex(
|
|
19853
|
+
import { readFileSync as readFileSync30, readdirSync as readdirSync21 } from "fs";
|
|
19854
|
+
import { join as join19, relative as relative10 } from "path";
|
|
19855
|
+
function buildPythonCouplingIndex(dataDb) {
|
|
21043
19856
|
const projectRoot = getProjectRoot();
|
|
21044
19857
|
const config = getConfig();
|
|
21045
|
-
const srcDir =
|
|
21046
|
-
const routes =
|
|
19858
|
+
const srcDir = join19(projectRoot, config.paths.source);
|
|
19859
|
+
const routes = dataDb.prepare("SELECT id, method, path FROM massu_py_routes").all();
|
|
21047
19860
|
if (routes.length === 0) return 0;
|
|
21048
|
-
|
|
19861
|
+
dataDb.exec("DELETE FROM massu_py_route_callers");
|
|
21049
19862
|
const frontendFiles = walkFrontendFiles(srcDir);
|
|
21050
|
-
const insertStmt =
|
|
19863
|
+
const insertStmt = dataDb.prepare(
|
|
21051
19864
|
"INSERT INTO massu_py_route_callers (route_id, frontend_file, line, call_pattern) VALUES (?, ?, ?, ?)"
|
|
21052
19865
|
);
|
|
21053
19866
|
let count = 0;
|
|
@@ -21069,12 +19882,12 @@ function buildPythonCouplingIndex(dataDb2) {
|
|
|
21069
19882
|
/\.patch\s*\(\s*[`'"](\/api\/[^`'"]*)[`'"]/g
|
|
21070
19883
|
// client.patch('/api/...')
|
|
21071
19884
|
];
|
|
21072
|
-
|
|
19885
|
+
dataDb.transaction(() => {
|
|
21073
19886
|
for (const absFile of frontendFiles) {
|
|
21074
19887
|
const relFile = relative10(projectRoot, absFile);
|
|
21075
19888
|
let source;
|
|
21076
19889
|
try {
|
|
21077
|
-
source =
|
|
19890
|
+
source = readFileSync30(absFile, "utf-8");
|
|
21078
19891
|
} catch {
|
|
21079
19892
|
continue;
|
|
21080
19893
|
}
|
|
@@ -21102,13 +19915,13 @@ function walkFrontendFiles(dir) {
|
|
|
21102
19915
|
const files = [];
|
|
21103
19916
|
const exclude = ["node_modules", ".next", "dist", ".git", "__pycache__", ".venv", "venv"];
|
|
21104
19917
|
try {
|
|
21105
|
-
const entries =
|
|
19918
|
+
const entries = readdirSync21(dir, { withFileTypes: true });
|
|
21106
19919
|
for (const entry of entries) {
|
|
21107
19920
|
if (entry.isDirectory()) {
|
|
21108
19921
|
if (exclude.includes(entry.name)) continue;
|
|
21109
|
-
files.push(...walkFrontendFiles(
|
|
19922
|
+
files.push(...walkFrontendFiles(join19(dir, entry.name)));
|
|
21110
19923
|
} else if (/\.(tsx?|jsx?)$/.test(entry.name)) {
|
|
21111
|
-
files.push(
|
|
19924
|
+
files.push(join19(dir, entry.name));
|
|
21112
19925
|
}
|
|
21113
19926
|
}
|
|
21114
19927
|
} catch {
|
|
@@ -21479,7 +20292,7 @@ var init_memory_tools = __esm({
|
|
|
21479
20292
|
});
|
|
21480
20293
|
|
|
21481
20294
|
// src/docs-tools.ts
|
|
21482
|
-
import { readFileSync as
|
|
20295
|
+
import { readFileSync as readFileSync31, existsSync as existsSync29 } from "fs";
|
|
21483
20296
|
import { resolve as resolve25, basename as basename6 } from "path";
|
|
21484
20297
|
function p3(baseName) {
|
|
21485
20298
|
return `${getConfig().toolPrefix}_${baseName}`;
|
|
@@ -21538,7 +20351,7 @@ function loadDocsMap() {
|
|
|
21538
20351
|
if (!existsSync29(mapPath)) {
|
|
21539
20352
|
throw new Error(`docs-map.json not found at ${mapPath}`);
|
|
21540
20353
|
}
|
|
21541
|
-
return JSON.parse(
|
|
20354
|
+
return JSON.parse(readFileSync31(mapPath, "utf-8"));
|
|
21542
20355
|
}
|
|
21543
20356
|
function matchesPattern(filePath, pattern) {
|
|
21544
20357
|
const regexStr = pattern.replace(/\./g, "\\.").replace(/\*\*/g, "{{GLOBSTAR}}").replace(/\*/g, "[^/]*").replace(/\{\{GLOBSTAR\}\}/g, ".*");
|
|
@@ -21612,9 +20425,9 @@ function extractProcedureNames(routerPath) {
|
|
|
21612
20425
|
if (!existsSync29(absPath)) {
|
|
21613
20426
|
const altPath = ensureWithinRoot(resolve25(getResolvedPaths().srcDir, "../server/api/routers", basename6(routerPath)), root);
|
|
21614
20427
|
if (!existsSync29(altPath)) return [];
|
|
21615
|
-
return extractProcedureNamesFromContent(
|
|
20428
|
+
return extractProcedureNamesFromContent(readFileSync31(altPath, "utf-8"));
|
|
21616
20429
|
}
|
|
21617
|
-
return extractProcedureNamesFromContent(
|
|
20430
|
+
return extractProcedureNamesFromContent(readFileSync31(absPath, "utf-8"));
|
|
21618
20431
|
}
|
|
21619
20432
|
function extractProcedureNamesFromContent(content) {
|
|
21620
20433
|
const procRegex = /\.(?:query|mutation)\s*\(/g;
|
|
@@ -21667,7 +20480,7 @@ function handleDocsAudit(args2) {
|
|
|
21667
20480
|
});
|
|
21668
20481
|
continue;
|
|
21669
20482
|
}
|
|
21670
|
-
const content =
|
|
20483
|
+
const content = readFileSync31(helpPagePath, "utf-8");
|
|
21671
20484
|
const sections = extractSections(content);
|
|
21672
20485
|
const frontmatter = extractFrontmatter(content);
|
|
21673
20486
|
const staleReasons = [];
|
|
@@ -21709,7 +20522,7 @@ function handleDocsAudit(args2) {
|
|
|
21709
20522
|
if (parentId === mappingId) {
|
|
21710
20523
|
const guidePath = ensureWithinRoot(resolve25(getResolvedPaths().helpSitePath, `pages/user-guides/${guideName}/index.mdx`), getProjectRoot());
|
|
21711
20524
|
if (existsSync29(guidePath)) {
|
|
21712
|
-
const guideContent =
|
|
20525
|
+
const guideContent = readFileSync31(guidePath, "utf-8");
|
|
21713
20526
|
const guideFrontmatter = extractFrontmatter(guideContent);
|
|
21714
20527
|
if (!guideFrontmatter?.lastVerified || status === "STALE") {
|
|
21715
20528
|
results.push({
|
|
@@ -21749,7 +20562,7 @@ function handleDocsCoverage(args2) {
|
|
|
21749
20562
|
let lastVerified = null;
|
|
21750
20563
|
let status = null;
|
|
21751
20564
|
if (exists) {
|
|
21752
|
-
const content =
|
|
20565
|
+
const content = readFileSync31(helpPagePath, "utf-8");
|
|
21753
20566
|
lineCount = content.split("\n").length;
|
|
21754
20567
|
hasContent = lineCount > 10;
|
|
21755
20568
|
const frontmatter = extractFrontmatter(content);
|
|
@@ -22585,22 +21398,22 @@ function getSentinelToolDefinitions() {
|
|
|
22585
21398
|
}
|
|
22586
21399
|
];
|
|
22587
21400
|
}
|
|
22588
|
-
function handleSentinelToolCall(name, args2,
|
|
21401
|
+
function handleSentinelToolCall(name, args2, dataDb) {
|
|
22589
21402
|
const prefix3 = getConfig().toolPrefix + "_";
|
|
22590
21403
|
const baseName = name.startsWith(prefix3) ? name.slice(prefix3.length) : name;
|
|
22591
21404
|
switch (baseName) {
|
|
22592
21405
|
case "sentinel_search":
|
|
22593
|
-
return handleSearch2(args2,
|
|
21406
|
+
return handleSearch2(args2, dataDb);
|
|
22594
21407
|
case "sentinel_detail":
|
|
22595
|
-
return handleDetail2(args2,
|
|
21408
|
+
return handleDetail2(args2, dataDb);
|
|
22596
21409
|
case "sentinel_impact":
|
|
22597
|
-
return handleImpact(args2,
|
|
21410
|
+
return handleImpact(args2, dataDb);
|
|
22598
21411
|
case "sentinel_validate":
|
|
22599
|
-
return handleValidate(args2,
|
|
21412
|
+
return handleValidate(args2, dataDb);
|
|
22600
21413
|
case "sentinel_register":
|
|
22601
|
-
return handleRegister(args2,
|
|
21414
|
+
return handleRegister(args2, dataDb);
|
|
22602
21415
|
case "sentinel_parity":
|
|
22603
|
-
return handleParityCheck(args2,
|
|
21416
|
+
return handleParityCheck(args2, dataDb);
|
|
22604
21417
|
default:
|
|
22605
21418
|
return text4(`Unknown sentinel tool: ${name}`);
|
|
22606
21419
|
}
|
|
@@ -22867,8 +21680,8 @@ var init_sentinel_tools = __esm({
|
|
|
22867
21680
|
});
|
|
22868
21681
|
|
|
22869
21682
|
// src/sentinel-scanner.ts
|
|
22870
|
-
import { readFileSync as
|
|
22871
|
-
import { resolve as resolve27, join as
|
|
21683
|
+
import { readFileSync as readFileSync32, existsSync as existsSync31, readdirSync as readdirSync22, statSync as statSync13 } from "fs";
|
|
21684
|
+
import { resolve as resolve27, join as join20, basename as basename7, dirname as dirname14, relative as relative11 } from "path";
|
|
22872
21685
|
function inferDomain(filePath) {
|
|
22873
21686
|
const domains = getConfig().domains;
|
|
22874
21687
|
const path = filePath.toLowerCase();
|
|
@@ -22914,10 +21727,10 @@ function parseFeatureAnnotations(source) {
|
|
|
22914
21727
|
}
|
|
22915
21728
|
return annotations;
|
|
22916
21729
|
}
|
|
22917
|
-
function scanTrpcProcedures(
|
|
21730
|
+
function scanTrpcProcedures(dataDb) {
|
|
22918
21731
|
const features = [];
|
|
22919
21732
|
const featureMap = /* @__PURE__ */ new Map();
|
|
22920
|
-
const procedures =
|
|
21733
|
+
const procedures = dataDb.prepare(`
|
|
22921
21734
|
SELECT router_name, procedure_name, procedure_type, router_file
|
|
22922
21735
|
FROM massu_trpc_procedures
|
|
22923
21736
|
ORDER BY router_name, procedure_name
|
|
@@ -22957,9 +21770,9 @@ function scanTrpcProcedures(dataDb2) {
|
|
|
22957
21770
|
}
|
|
22958
21771
|
return Array.from(featureMap.values());
|
|
22959
21772
|
}
|
|
22960
|
-
function scanPageRoutes(
|
|
21773
|
+
function scanPageRoutes(dataDb) {
|
|
22961
21774
|
const features = [];
|
|
22962
|
-
const pages =
|
|
21775
|
+
const pages = dataDb.prepare(`
|
|
22963
21776
|
SELECT page_file, route, portal, components, hooks, routers
|
|
22964
21777
|
FROM massu_page_deps
|
|
22965
21778
|
ORDER BY route
|
|
@@ -22991,7 +21804,7 @@ function scanPageRoutes(dataDb2) {
|
|
|
22991
21804
|
}
|
|
22992
21805
|
return features;
|
|
22993
21806
|
}
|
|
22994
|
-
function scanComponentExports(
|
|
21807
|
+
function scanComponentExports(dataDb) {
|
|
22995
21808
|
const features = [];
|
|
22996
21809
|
const config = getConfig();
|
|
22997
21810
|
const projectRoot = getProjectRoot();
|
|
@@ -23000,7 +21813,7 @@ function scanComponentExports(dataDb2) {
|
|
|
23000
21813
|
const basePath = resolve27(projectRoot, componentsBase);
|
|
23001
21814
|
if (existsSync31(basePath)) {
|
|
23002
21815
|
try {
|
|
23003
|
-
const entries =
|
|
21816
|
+
const entries = readdirSync22(basePath, { withFileTypes: true });
|
|
23004
21817
|
for (const entry of entries) {
|
|
23005
21818
|
if (entry.isDirectory()) {
|
|
23006
21819
|
componentDirs.push(componentsBase + "/" + entry.name);
|
|
@@ -23015,7 +21828,7 @@ function scanComponentExports(dataDb2) {
|
|
|
23015
21828
|
const files = walkDir2(absDir).filter((f2) => f2.endsWith(".tsx") || f2.endsWith(".ts"));
|
|
23016
21829
|
for (const file of files) {
|
|
23017
21830
|
const relPath = relative11(projectRoot, file);
|
|
23018
|
-
const source =
|
|
21831
|
+
const source = readFileSync32(file, "utf-8");
|
|
23019
21832
|
const annotations = parseFeatureAnnotations(source);
|
|
23020
21833
|
if (annotations.length > 0) {
|
|
23021
21834
|
for (const ann of annotations) {
|
|
@@ -23041,7 +21854,7 @@ function scanComponentExports(dataDb2) {
|
|
|
23041
21854
|
if (hasHandlers && exportMatch) {
|
|
23042
21855
|
const componentName = exportMatch[1];
|
|
23043
21856
|
const domain = inferDomain(relPath);
|
|
23044
|
-
const subdomain = basename7(
|
|
21857
|
+
const subdomain = basename7(dirname14(relPath));
|
|
23045
21858
|
const featureKey = `component.${subdomain}.${componentName.replace(/([A-Z])/g, "-$1").toLowerCase().replace(/^-/, "")}`;
|
|
23046
21859
|
if (!annotations.some((a2) => a2.featureKey === featureKey)) {
|
|
23047
21860
|
features.push({
|
|
@@ -23064,9 +21877,9 @@ function scanComponentExports(dataDb2) {
|
|
|
23064
21877
|
function walkDir2(dir) {
|
|
23065
21878
|
const results = [];
|
|
23066
21879
|
try {
|
|
23067
|
-
const entries =
|
|
21880
|
+
const entries = readdirSync22(dir);
|
|
23068
21881
|
for (const entry of entries) {
|
|
23069
|
-
const fullPath =
|
|
21882
|
+
const fullPath = join20(dir, entry);
|
|
23070
21883
|
try {
|
|
23071
21884
|
const stat = statSync13(fullPath);
|
|
23072
21885
|
if (stat.isDirectory()) {
|
|
@@ -23081,10 +21894,10 @@ function walkDir2(dir) {
|
|
|
23081
21894
|
}
|
|
23082
21895
|
return results;
|
|
23083
21896
|
}
|
|
23084
|
-
function runFeatureScan(
|
|
23085
|
-
const procedureFeatures = scanTrpcProcedures(
|
|
23086
|
-
const pageFeatures = scanPageRoutes(
|
|
23087
|
-
const componentFeatures = scanComponentExports(
|
|
21897
|
+
function runFeatureScan(dataDb) {
|
|
21898
|
+
const procedureFeatures = scanTrpcProcedures(dataDb);
|
|
21899
|
+
const pageFeatures = scanPageRoutes(dataDb);
|
|
21900
|
+
const componentFeatures = scanComponentExports(dataDb);
|
|
23088
21901
|
const allFeatures = /* @__PURE__ */ new Map();
|
|
23089
21902
|
for (const f2 of procedureFeatures) {
|
|
23090
21903
|
allFeatures.set(f2.feature_key, f2);
|
|
@@ -23097,7 +21910,7 @@ function runFeatureScan(dataDb2) {
|
|
|
23097
21910
|
}
|
|
23098
21911
|
let registered = 0;
|
|
23099
21912
|
for (const feature of allFeatures.values()) {
|
|
23100
|
-
const featureId = upsertFeature(
|
|
21913
|
+
const featureId = upsertFeature(dataDb, {
|
|
23101
21914
|
feature_key: feature.feature_key,
|
|
23102
21915
|
domain: feature.domain,
|
|
23103
21916
|
subdomain: feature.subdomain,
|
|
@@ -23108,15 +21921,15 @@ function runFeatureScan(dataDb2) {
|
|
|
23108
21921
|
portal_scope: feature.portal_scope
|
|
23109
21922
|
});
|
|
23110
21923
|
for (const comp of feature.components) {
|
|
23111
|
-
linkComponent(
|
|
21924
|
+
linkComponent(dataDb, featureId, comp.file, comp.name, comp.role, comp.isPrimary);
|
|
23112
21925
|
}
|
|
23113
21926
|
for (const proc of feature.procedures) {
|
|
23114
|
-
linkProcedure(
|
|
21927
|
+
linkProcedure(dataDb, featureId, proc.router, proc.procedure, proc.type);
|
|
23115
21928
|
}
|
|
23116
21929
|
for (const page of feature.pages) {
|
|
23117
|
-
linkPage(
|
|
21930
|
+
linkPage(dataDb, featureId, page.route, page.portal ?? void 0);
|
|
23118
21931
|
}
|
|
23119
|
-
logChange(
|
|
21932
|
+
logChange(dataDb, featureId, "created", "Auto-discovered by sentinel scanner", void 0, "scanner");
|
|
23120
21933
|
registered++;
|
|
23121
21934
|
}
|
|
23122
21935
|
return {
|
|
@@ -24054,7 +22867,7 @@ var init_audit_trail = __esm({
|
|
|
24054
22867
|
});
|
|
24055
22868
|
|
|
24056
22869
|
// src/validation-engine.ts
|
|
24057
|
-
import { existsSync as existsSync32, readFileSync as
|
|
22870
|
+
import { existsSync as existsSync32, readFileSync as readFileSync33 } from "fs";
|
|
24058
22871
|
function p10(baseName) {
|
|
24059
22872
|
return `${getConfig().toolPrefix}_${baseName}`;
|
|
24060
22873
|
}
|
|
@@ -24094,7 +22907,7 @@ function validateFile(filePath, projectRoot) {
|
|
|
24094
22907
|
});
|
|
24095
22908
|
return checks;
|
|
24096
22909
|
}
|
|
24097
|
-
const source =
|
|
22910
|
+
const source = readFileSync33(absPath, "utf-8");
|
|
24098
22911
|
const lines = source.split("\n");
|
|
24099
22912
|
if (activeChecks.rule_compliance !== false) {
|
|
24100
22913
|
for (const ruleSet of config.rules) {
|
|
@@ -24539,7 +23352,7 @@ var init_adr_generator = __esm({
|
|
|
24539
23352
|
});
|
|
24540
23353
|
|
|
24541
23354
|
// src/security-scorer.ts
|
|
24542
|
-
import { existsSync as existsSync33, readFileSync as
|
|
23355
|
+
import { existsSync as existsSync33, readFileSync as readFileSync34 } from "fs";
|
|
24543
23356
|
function p12(baseName) {
|
|
24544
23357
|
return `${getConfig().toolPrefix}_${baseName}`;
|
|
24545
23358
|
}
|
|
@@ -24568,7 +23381,7 @@ function scoreFileSecurity(filePath, projectRoot) {
|
|
|
24568
23381
|
}
|
|
24569
23382
|
let source;
|
|
24570
23383
|
try {
|
|
24571
|
-
source =
|
|
23384
|
+
source = readFileSync34(absPath, "utf-8");
|
|
24572
23385
|
} catch {
|
|
24573
23386
|
return { riskScore: 0, findings: [] };
|
|
24574
23387
|
}
|
|
@@ -24857,7 +23670,7 @@ var init_security_scorer = __esm({
|
|
|
24857
23670
|
});
|
|
24858
23671
|
|
|
24859
23672
|
// src/dependency-scorer.ts
|
|
24860
|
-
import { existsSync as existsSync34, readFileSync as
|
|
23673
|
+
import { existsSync as existsSync34, readFileSync as readFileSync35 } from "fs";
|
|
24861
23674
|
import { resolve as resolve28 } from "path";
|
|
24862
23675
|
function p13(baseName) {
|
|
24863
23676
|
return `${getConfig().toolPrefix}_${baseName}`;
|
|
@@ -24893,7 +23706,7 @@ function getInstalledPackages(projectRoot) {
|
|
|
24893
23706
|
const pkgPath = resolve28(projectRoot, "package.json");
|
|
24894
23707
|
if (!existsSync34(pkgPath)) return /* @__PURE__ */ new Map();
|
|
24895
23708
|
try {
|
|
24896
|
-
const pkg = JSON.parse(
|
|
23709
|
+
const pkg = JSON.parse(readFileSync35(pkgPath, "utf-8"));
|
|
24897
23710
|
const packages = /* @__PURE__ */ new Map();
|
|
24898
23711
|
for (const [name, version] of Object.entries(pkg.dependencies ?? {})) {
|
|
24899
23712
|
packages.set(name, version);
|
|
@@ -25495,8 +24308,8 @@ var init_regression_detector = __esm({
|
|
|
25495
24308
|
});
|
|
25496
24309
|
|
|
25497
24310
|
// src/knowledge-indexer.ts
|
|
25498
|
-
import { createHash as
|
|
25499
|
-
import { readFileSync as
|
|
24311
|
+
import { createHash as createHash8 } from "crypto";
|
|
24312
|
+
import { readFileSync as readFileSync36, readdirSync as readdirSync23, statSync as statSync14, existsSync as existsSync35 } from "fs";
|
|
25500
24313
|
import { resolve as resolve29, relative as relative12, basename as basename8, extname as extname2 } from "path";
|
|
25501
24314
|
function getKnowledgePaths() {
|
|
25502
24315
|
const resolved = getResolvedPaths();
|
|
@@ -25523,7 +24336,7 @@ function discoverMarkdownFiles(baseDir) {
|
|
|
25523
24336
|
const files = [];
|
|
25524
24337
|
function walk(dir) {
|
|
25525
24338
|
try {
|
|
25526
|
-
const entries =
|
|
24339
|
+
const entries = readdirSync23(dir, { withFileTypes: true });
|
|
25527
24340
|
for (const entry of entries) {
|
|
25528
24341
|
const fullPath = resolve29(dir, entry.name);
|
|
25529
24342
|
if (entry.isDirectory()) {
|
|
@@ -25583,7 +24396,7 @@ function categorizeFile(filePath) {
|
|
|
25583
24396
|
return "root";
|
|
25584
24397
|
}
|
|
25585
24398
|
function hashContent2(content) {
|
|
25586
|
-
return
|
|
24399
|
+
return createHash8("sha256").update(content).digest("hex");
|
|
25587
24400
|
}
|
|
25588
24401
|
function parseCRTable(content) {
|
|
25589
24402
|
const rules = [];
|
|
@@ -25851,7 +24664,7 @@ function indexAllKnowledge(db) {
|
|
|
25851
24664
|
}
|
|
25852
24665
|
for (const filePath of files) {
|
|
25853
24666
|
if (!existsSync35(filePath)) continue;
|
|
25854
|
-
const content =
|
|
24667
|
+
const content = readFileSync36(filePath, "utf-8");
|
|
25855
24668
|
const hash = hashContent2(content);
|
|
25856
24669
|
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
24670
|
const category = categorizeFile(filePath);
|
|
@@ -26003,7 +24816,7 @@ var init_knowledge_indexer = __esm({
|
|
|
26003
24816
|
});
|
|
26004
24817
|
|
|
26005
24818
|
// src/knowledge-tools.ts
|
|
26006
|
-
import { readFileSync as
|
|
24819
|
+
import { readFileSync as readFileSync37, writeFileSync as writeFileSync5, appendFileSync as appendFileSync2, readdirSync as readdirSync24 } from "fs";
|
|
26007
24820
|
import { resolve as resolve30, basename as basename9 } from "path";
|
|
26008
24821
|
function p16(baseName) {
|
|
26009
24822
|
return `${getConfig().toolPrefix}_${baseName}`;
|
|
@@ -26754,14 +25567,14 @@ ${crRule ? `- **CR**: ${crRule}
|
|
|
26754
25567
|
`;
|
|
26755
25568
|
let existing = "";
|
|
26756
25569
|
try {
|
|
26757
|
-
existing =
|
|
25570
|
+
existing = readFileSync37(correctionsPath, "utf-8");
|
|
26758
25571
|
} catch {
|
|
26759
25572
|
}
|
|
26760
25573
|
const archiveIdx = existing.indexOf("## Archived");
|
|
26761
25574
|
if (archiveIdx > 0) {
|
|
26762
25575
|
const before = existing.slice(0, archiveIdx);
|
|
26763
25576
|
const after = existing.slice(archiveIdx);
|
|
26764
|
-
|
|
25577
|
+
writeFileSync5(correctionsPath, before + entry + after);
|
|
26765
25578
|
} else {
|
|
26766
25579
|
appendFileSync2(correctionsPath, entry);
|
|
26767
25580
|
}
|
|
@@ -26892,9 +25705,9 @@ function handleGaps(db, args2) {
|
|
|
26892
25705
|
lines.push(`## Knowledge Gap Analysis (${checkType})`);
|
|
26893
25706
|
lines.push("");
|
|
26894
25707
|
if (checkType === "features") {
|
|
26895
|
-
let
|
|
25708
|
+
let dataDb = null;
|
|
26896
25709
|
try {
|
|
26897
|
-
|
|
25710
|
+
dataDb = getDataDb();
|
|
26898
25711
|
let sql = "SELECT feature_key, title, domain, status FROM massu_sentinel WHERE status = 'active'";
|
|
26899
25712
|
const params = [];
|
|
26900
25713
|
if (domain) {
|
|
@@ -26902,7 +25715,7 @@ function handleGaps(db, args2) {
|
|
|
26902
25715
|
params.push(`%${domain}%`);
|
|
26903
25716
|
}
|
|
26904
25717
|
sql += " ORDER BY domain, feature_key";
|
|
26905
|
-
const features =
|
|
25718
|
+
const features = dataDb.prepare(sql).all(...params);
|
|
26906
25719
|
lines.push(`| Feature | Domain | Knowledge Hits | Status |`);
|
|
26907
25720
|
lines.push(`|---------|--------|----------------|--------|`);
|
|
26908
25721
|
let gapCount = 0;
|
|
@@ -26931,12 +25744,12 @@ function handleGaps(db, args2) {
|
|
|
26931
25744
|
} catch (error) {
|
|
26932
25745
|
lines.push(`Error querying sentinel: ${error instanceof Error ? error.message : String(error)}`);
|
|
26933
25746
|
} finally {
|
|
26934
|
-
|
|
25747
|
+
dataDb?.close();
|
|
26935
25748
|
}
|
|
26936
25749
|
} else if (checkType === "routers") {
|
|
26937
25750
|
try {
|
|
26938
25751
|
const routersDir = getResolvedPaths().routersDir;
|
|
26939
|
-
const routerFiles =
|
|
25752
|
+
const routerFiles = readdirSync24(routersDir).filter((f2) => f2.endsWith(".ts") && !f2.startsWith("_"));
|
|
26940
25753
|
lines.push(`| Router | Knowledge Hits | Status |`);
|
|
26941
25754
|
lines.push(`|--------|----------------|--------|`);
|
|
26942
25755
|
for (const file of routerFiles) {
|
|
@@ -26958,10 +25771,10 @@ function handleGaps(db, args2) {
|
|
|
26958
25771
|
lines.push("### Pattern Coverage");
|
|
26959
25772
|
lines.push(`Documented domains: ${[...documentedDomains].join(", ")}`);
|
|
26960
25773
|
lines.push("");
|
|
26961
|
-
let
|
|
25774
|
+
let dataDb = null;
|
|
26962
25775
|
try {
|
|
26963
|
-
|
|
26964
|
-
const domains =
|
|
25776
|
+
dataDb = getDataDb();
|
|
25777
|
+
const domains = dataDb.prepare(
|
|
26965
25778
|
"SELECT DISTINCT domain FROM massu_sentinel WHERE status = 'active' ORDER BY domain"
|
|
26966
25779
|
).all();
|
|
26967
25780
|
for (const d2 of domains) {
|
|
@@ -26970,7 +25783,7 @@ function handleGaps(db, args2) {
|
|
|
26970
25783
|
}
|
|
26971
25784
|
} catch {
|
|
26972
25785
|
} finally {
|
|
26973
|
-
|
|
25786
|
+
dataDb?.close();
|
|
26974
25787
|
}
|
|
26975
25788
|
} else if (checkType === "incidents") {
|
|
26976
25789
|
const incidents = db.prepare(
|
|
@@ -27092,13 +25905,13 @@ var init_knowledge_tools = __esm({
|
|
|
27092
25905
|
|
|
27093
25906
|
// src/knowledge-db.ts
|
|
27094
25907
|
import Database3 from "better-sqlite3";
|
|
27095
|
-
import { dirname as
|
|
27096
|
-
import { existsSync as existsSync37, mkdirSync as
|
|
25908
|
+
import { dirname as dirname15 } from "path";
|
|
25909
|
+
import { existsSync as existsSync37, mkdirSync as mkdirSync10 } from "fs";
|
|
27097
25910
|
function getKnowledgeDb() {
|
|
27098
25911
|
const dbPath = getResolvedPaths().knowledgeDbPath;
|
|
27099
|
-
const dir =
|
|
25912
|
+
const dir = dirname15(dbPath);
|
|
27100
25913
|
if (!existsSync37(dir)) {
|
|
27101
|
-
|
|
25914
|
+
mkdirSync10(dir, { recursive: true });
|
|
27102
25915
|
}
|
|
27103
25916
|
const db = new Database3(dbPath);
|
|
27104
25917
|
db.pragma("journal_mode = WAL");
|
|
@@ -27413,30 +26226,30 @@ function isPythonTool(name) {
|
|
|
27413
26226
|
const base = stripPrefix2(name);
|
|
27414
26227
|
return base.startsWith("py_");
|
|
27415
26228
|
}
|
|
27416
|
-
function handlePythonToolCall(name, args2,
|
|
26229
|
+
function handlePythonToolCall(name, args2, dataDb) {
|
|
27417
26230
|
const baseName = stripPrefix2(name);
|
|
27418
26231
|
switch (baseName) {
|
|
27419
26232
|
case "py_imports":
|
|
27420
|
-
return handlePyImports(args2,
|
|
26233
|
+
return handlePyImports(args2, dataDb);
|
|
27421
26234
|
case "py_routes":
|
|
27422
|
-
return handlePyRoutes(args2,
|
|
26235
|
+
return handlePyRoutes(args2, dataDb);
|
|
27423
26236
|
case "py_coupling":
|
|
27424
|
-
return handlePyCoupling(args2,
|
|
26237
|
+
return handlePyCoupling(args2, dataDb);
|
|
27425
26238
|
case "py_models":
|
|
27426
|
-
return handlePyModels(args2,
|
|
26239
|
+
return handlePyModels(args2, dataDb);
|
|
27427
26240
|
case "py_migrations":
|
|
27428
|
-
return handlePyMigrations(args2,
|
|
26241
|
+
return handlePyMigrations(args2, dataDb);
|
|
27429
26242
|
case "py_domains":
|
|
27430
|
-
return handlePyDomains(args2,
|
|
26243
|
+
return handlePyDomains(args2, dataDb);
|
|
27431
26244
|
case "py_impact":
|
|
27432
|
-
return handlePyImpact(args2,
|
|
26245
|
+
return handlePyImpact(args2, dataDb);
|
|
27433
26246
|
case "py_context":
|
|
27434
|
-
return handlePyContext(args2,
|
|
26247
|
+
return handlePyContext(args2, dataDb);
|
|
27435
26248
|
default:
|
|
27436
26249
|
return text16(`Unknown Python tool: ${name}`);
|
|
27437
26250
|
}
|
|
27438
26251
|
}
|
|
27439
|
-
function handlePyImports(args2,
|
|
26252
|
+
function handlePyImports(args2, dataDb) {
|
|
27440
26253
|
const lines = [];
|
|
27441
26254
|
const file = args2.file;
|
|
27442
26255
|
const importedBy = args2.imported_by;
|
|
@@ -27447,7 +26260,7 @@ function handlePyImports(args2, dataDb2) {
|
|
|
27447
26260
|
let traverse2 = function(f2, depth) {
|
|
27448
26261
|
if (depth > maxDepth || visited.has(f2)) return;
|
|
27449
26262
|
visited.add(f2);
|
|
27450
|
-
const imports =
|
|
26263
|
+
const imports = dataDb.prepare(
|
|
27451
26264
|
"SELECT target_file, imported_names FROM massu_py_imports WHERE source_file = ?"
|
|
27452
26265
|
).all(f2);
|
|
27453
26266
|
for (const imp of imports) {
|
|
@@ -27462,7 +26275,7 @@ function handlePyImports(args2, dataDb2) {
|
|
|
27462
26275
|
const visited = /* @__PURE__ */ new Set();
|
|
27463
26276
|
traverse2(file, 0);
|
|
27464
26277
|
} else {
|
|
27465
|
-
const imports =
|
|
26278
|
+
const imports = dataDb.prepare(
|
|
27466
26279
|
"SELECT target_file, import_type, imported_names, line FROM massu_py_imports WHERE source_file = ? ORDER BY line"
|
|
27467
26280
|
).all(file);
|
|
27468
26281
|
lines.push(`## Imports from ${file} (${imports.length} edges)`);
|
|
@@ -27472,7 +26285,7 @@ function handlePyImports(args2, dataDb2) {
|
|
|
27472
26285
|
}
|
|
27473
26286
|
}
|
|
27474
26287
|
} else if (importedBy) {
|
|
27475
|
-
const importers =
|
|
26288
|
+
const importers = dataDb.prepare(
|
|
27476
26289
|
"SELECT source_file, imported_names, line FROM massu_py_imports WHERE target_file = ? ORDER BY source_file"
|
|
27477
26290
|
).all(importedBy);
|
|
27478
26291
|
lines.push(`## Files importing ${importedBy} (${importers.length} edges)`);
|
|
@@ -27481,8 +26294,8 @@ function handlePyImports(args2, dataDb2) {
|
|
|
27481
26294
|
lines.push(`- ${imp.source_file}:${imp.line}${names.length > 0 ? " (" + names.join(", ") + ")" : ""}`);
|
|
27482
26295
|
}
|
|
27483
26296
|
} else {
|
|
27484
|
-
const total =
|
|
27485
|
-
const files =
|
|
26297
|
+
const total = dataDb.prepare("SELECT COUNT(*) as cnt FROM massu_py_imports").get().cnt;
|
|
26298
|
+
const files = dataDb.prepare("SELECT COUNT(DISTINCT source_file) as cnt FROM massu_py_imports").get().cnt;
|
|
27486
26299
|
lines.push("## Python Import Index Summary");
|
|
27487
26300
|
lines.push(`- Total import edges: ${total}`);
|
|
27488
26301
|
lines.push(`- Files with imports: ${files}`);
|
|
@@ -27492,7 +26305,7 @@ function handlePyImports(args2, dataDb2) {
|
|
|
27492
26305
|
}
|
|
27493
26306
|
return text16(lines.join("\n") || "No Python import data available. Run sync first.");
|
|
27494
26307
|
}
|
|
27495
|
-
function handlePyRoutes(args2,
|
|
26308
|
+
function handlePyRoutes(args2, dataDb) {
|
|
27496
26309
|
const lines = [];
|
|
27497
26310
|
const limit = Math.min(Math.max(args2.limit || 500, 1), 5e3);
|
|
27498
26311
|
let query = "SELECT * FROM massu_py_routes WHERE 1=1";
|
|
@@ -27513,9 +26326,9 @@ function handlePyRoutes(args2, dataDb2) {
|
|
|
27513
26326
|
query += " AND is_authenticated = 0";
|
|
27514
26327
|
}
|
|
27515
26328
|
query += ` ORDER BY file, line LIMIT ${limit}`;
|
|
27516
|
-
const routes =
|
|
26329
|
+
const routes = dataDb.prepare(query).all(...params);
|
|
27517
26330
|
if (args2.uncoupled) {
|
|
27518
|
-
const callerCountStmt =
|
|
26331
|
+
const callerCountStmt = dataDb.prepare("SELECT COUNT(*) as cnt FROM massu_py_route_callers WHERE route_id = ?");
|
|
27519
26332
|
const uncoupledRoutes = routes.filter((r2) => {
|
|
27520
26333
|
const callers = callerCountStmt.get(r2.id).cnt;
|
|
27521
26334
|
return callers === 0;
|
|
@@ -27536,7 +26349,7 @@ function handlePyRoutes(args2, dataDb2) {
|
|
|
27536
26349
|
}
|
|
27537
26350
|
return text16(lines.join("\n") || "No Python routes found.");
|
|
27538
26351
|
}
|
|
27539
|
-
function handlePyCoupling(args2,
|
|
26352
|
+
function handlePyCoupling(args2, dataDb) {
|
|
27540
26353
|
const lines = [];
|
|
27541
26354
|
let query = `
|
|
27542
26355
|
SELECT rc.frontend_file, rc.call_pattern, rc.line as caller_line,
|
|
@@ -27555,7 +26368,7 @@ function handlePyCoupling(args2, dataDb2) {
|
|
|
27555
26368
|
params.push(`%${args2.backend_path}%`);
|
|
27556
26369
|
}
|
|
27557
26370
|
query += " ORDER BY rc.frontend_file, rc.line";
|
|
27558
|
-
const couplings =
|
|
26371
|
+
const couplings = dataDb.prepare(query).all(...params);
|
|
27559
26372
|
lines.push(`## Frontend \u2194 Backend Coupling (${couplings.length} connections)`);
|
|
27560
26373
|
let currentFrontend = "";
|
|
27561
26374
|
for (const c2 of couplings) {
|
|
@@ -27568,17 +26381,17 @@ function handlePyCoupling(args2, dataDb2) {
|
|
|
27568
26381
|
}
|
|
27569
26382
|
return text16(lines.join("\n") || "No coupling data found.");
|
|
27570
26383
|
}
|
|
27571
|
-
function handlePyModels(args2,
|
|
26384
|
+
function handlePyModels(args2, dataDb) {
|
|
27572
26385
|
const lines = [];
|
|
27573
26386
|
if (args2.fk_graph) {
|
|
27574
|
-
const edges =
|
|
26387
|
+
const edges = dataDb.prepare("SELECT * FROM massu_py_fk_edges ORDER BY source_table").all();
|
|
27575
26388
|
lines.push(`## Foreign Key Graph (${edges.length} edges)`);
|
|
27576
26389
|
for (const e2 of edges) {
|
|
27577
26390
|
lines.push(`- ${e2.source_table}.${e2.source_column} \u2192 ${e2.target_table}.${e2.target_column}`);
|
|
27578
26391
|
}
|
|
27579
26392
|
} else if (args2.model || args2.table) {
|
|
27580
26393
|
const search = args2.model || args2.table;
|
|
27581
|
-
const model =
|
|
26394
|
+
const model = dataDb.prepare(
|
|
27582
26395
|
"SELECT * FROM massu_py_models WHERE class_name = ? OR table_name = ?"
|
|
27583
26396
|
).get(search, search);
|
|
27584
26397
|
if (!model) return text16(`Model "${search}" not found.`);
|
|
@@ -27607,7 +26420,7 @@ function handlePyModels(args2, dataDb2) {
|
|
|
27607
26420
|
}
|
|
27608
26421
|
} else {
|
|
27609
26422
|
const limit = Math.min(Math.max(args2.limit || 500, 1), 5e3);
|
|
27610
|
-
const models =
|
|
26423
|
+
const models = dataDb.prepare(`SELECT class_name, table_name, file, line FROM massu_py_models ORDER BY class_name LIMIT ${limit}`).all();
|
|
27611
26424
|
lines.push(`## Python Models (${models.length})`);
|
|
27612
26425
|
for (const m3 of models) {
|
|
27613
26426
|
lines.push(`- ${m3.class_name} (${m3.table_name || "no table"}) \u2014 ${m3.file}:${m3.line}`);
|
|
@@ -27615,11 +26428,11 @@ function handlePyModels(args2, dataDb2) {
|
|
|
27615
26428
|
}
|
|
27616
26429
|
return text16(lines.join("\n") || "No Python models found.");
|
|
27617
26430
|
}
|
|
27618
|
-
function handlePyMigrations(args2,
|
|
26431
|
+
function handlePyMigrations(args2, dataDb) {
|
|
27619
26432
|
const lines = [];
|
|
27620
26433
|
if (args2.drift) {
|
|
27621
|
-
const models =
|
|
27622
|
-
const migrations =
|
|
26434
|
+
const models = dataDb.prepare("SELECT class_name, table_name, columns FROM massu_py_models").all();
|
|
26435
|
+
const migrations = dataDb.prepare("SELECT revision, operations FROM massu_py_migrations").all();
|
|
27623
26436
|
const migratedTables = /* @__PURE__ */ new Set();
|
|
27624
26437
|
for (const m3 of migrations) {
|
|
27625
26438
|
const ops = safeParseArray(m3.operations);
|
|
@@ -27640,14 +26453,14 @@ function handlePyMigrations(args2, dataDb2) {
|
|
|
27640
26453
|
}
|
|
27641
26454
|
} else if (args2.chain) {
|
|
27642
26455
|
const limit = Math.min(Math.max(args2.limit || 500, 1), 5e3);
|
|
27643
|
-
const migrations =
|
|
26456
|
+
const migrations = dataDb.prepare(`SELECT * FROM massu_py_migrations ORDER BY id LIMIT ${limit}`).all();
|
|
27644
26457
|
lines.push(`## Migration Chain (${migrations.length} revisions)`);
|
|
27645
26458
|
for (const m3 of migrations) {
|
|
27646
26459
|
const head = m3.is_head ? " [HEAD]" : "";
|
|
27647
26460
|
lines.push(`- ${m3.revision}${head} \u2190 ${m3.down_revision || "BASE"}: ${m3.description || "(no description)"} (${m3.file})`);
|
|
27648
26461
|
}
|
|
27649
26462
|
} else if (args2.revision) {
|
|
27650
|
-
const m3 =
|
|
26463
|
+
const m3 = dataDb.prepare("SELECT * FROM massu_py_migrations WHERE revision = ?").get(args2.revision);
|
|
27651
26464
|
if (!m3) return text16(`Revision "${args2.revision}" not found.`);
|
|
27652
26465
|
lines.push(`## Revision: ${m3.revision}`);
|
|
27653
26466
|
lines.push(`Down: ${m3.down_revision || "BASE"}`);
|
|
@@ -27661,15 +26474,15 @@ function handlePyMigrations(args2, dataDb2) {
|
|
|
27661
26474
|
}
|
|
27662
26475
|
}
|
|
27663
26476
|
} else {
|
|
27664
|
-
const total =
|
|
27665
|
-
const head =
|
|
26477
|
+
const total = dataDb.prepare("SELECT COUNT(*) as cnt FROM massu_py_migrations").get().cnt;
|
|
26478
|
+
const head = dataDb.prepare("SELECT revision FROM massu_py_migrations WHERE is_head = 1").get();
|
|
27666
26479
|
lines.push("## Migration Summary");
|
|
27667
26480
|
lines.push(`- Total revisions: ${total}`);
|
|
27668
26481
|
lines.push(`- Current head: ${head?.revision || "N/A"}`);
|
|
27669
26482
|
}
|
|
27670
26483
|
return text16(lines.join("\n") || "No Python migration data found.");
|
|
27671
26484
|
}
|
|
27672
|
-
function handlePyDomains(args2,
|
|
26485
|
+
function handlePyDomains(args2, dataDb) {
|
|
27673
26486
|
const lines = [];
|
|
27674
26487
|
const config = getConfig();
|
|
27675
26488
|
const domains = config.python?.domains || [];
|
|
@@ -27683,7 +26496,7 @@ function handlePyDomains(args2, dataDb2) {
|
|
|
27683
26496
|
lines.push(`Allowed imports from: ${domainConfig.allowed_imports_from.join(", ") || "any"}`);
|
|
27684
26497
|
}
|
|
27685
26498
|
} else if (args2.crossings) {
|
|
27686
|
-
const imports =
|
|
26499
|
+
const imports = dataDb.prepare("SELECT source_file, target_file FROM massu_py_imports").all();
|
|
27687
26500
|
const violations = [];
|
|
27688
26501
|
for (const imp of imports) {
|
|
27689
26502
|
const srcDomain = classifyPythonFileDomain(imp.source_file);
|
|
@@ -27702,7 +26515,7 @@ function handlePyDomains(args2, dataDb2) {
|
|
|
27702
26515
|
if (violations.length > 50) lines.push(`... and ${violations.length - 50} more`);
|
|
27703
26516
|
} else if (args2.domain) {
|
|
27704
26517
|
const domainName = args2.domain;
|
|
27705
|
-
const allFiles =
|
|
26518
|
+
const allFiles = dataDb.prepare("SELECT DISTINCT source_file FROM massu_py_imports UNION SELECT DISTINCT target_file FROM massu_py_imports").all();
|
|
27706
26519
|
const filesInDomain = allFiles.filter((f2) => classifyPythonFileDomain(f2.source_file) === domainName);
|
|
27707
26520
|
lines.push(`## Domain: ${domainName} (${filesInDomain.length} files)`);
|
|
27708
26521
|
for (const f2 of filesInDomain) {
|
|
@@ -27716,17 +26529,17 @@ function handlePyDomains(args2, dataDb2) {
|
|
|
27716
26529
|
}
|
|
27717
26530
|
return text16(lines.join("\n") || "No Python domains configured.");
|
|
27718
26531
|
}
|
|
27719
|
-
function handlePyImpact(args2,
|
|
26532
|
+
function handlePyImpact(args2, dataDb) {
|
|
27720
26533
|
const file = args2.file;
|
|
27721
26534
|
const lines = [`## Impact Analysis: ${file}`, ""];
|
|
27722
|
-
const importedBy =
|
|
26535
|
+
const importedBy = dataDb.prepare(
|
|
27723
26536
|
"SELECT source_file FROM massu_py_imports WHERE target_file = ?"
|
|
27724
26537
|
).all(file);
|
|
27725
26538
|
lines.push(`### Imported By (${importedBy.length} files)`);
|
|
27726
26539
|
for (const imp of importedBy.slice(0, 20)) {
|
|
27727
26540
|
lines.push(`- ${imp.source_file}`);
|
|
27728
26541
|
}
|
|
27729
|
-
const routes =
|
|
26542
|
+
const routes = dataDb.prepare(
|
|
27730
26543
|
"SELECT method, path, function_name FROM massu_py_routes WHERE file = ?"
|
|
27731
26544
|
).all(file);
|
|
27732
26545
|
if (routes.length > 0) {
|
|
@@ -27736,7 +26549,7 @@ function handlePyImpact(args2, dataDb2) {
|
|
|
27736
26549
|
lines.push(`- ${r2.method} ${r2.path} \u2192 ${r2.function_name}`);
|
|
27737
26550
|
}
|
|
27738
26551
|
}
|
|
27739
|
-
const models =
|
|
26552
|
+
const models = dataDb.prepare(
|
|
27740
26553
|
"SELECT class_name, table_name FROM massu_py_models WHERE file = ?"
|
|
27741
26554
|
).all(file);
|
|
27742
26555
|
if (models.length > 0) {
|
|
@@ -27746,10 +26559,10 @@ function handlePyImpact(args2, dataDb2) {
|
|
|
27746
26559
|
lines.push(`- ${m3.class_name} (${m3.table_name || "no table"})`);
|
|
27747
26560
|
}
|
|
27748
26561
|
}
|
|
27749
|
-
const routeIds =
|
|
26562
|
+
const routeIds = dataDb.prepare("SELECT id FROM massu_py_routes WHERE file = ?").all(file);
|
|
27750
26563
|
if (routeIds.length > 0) {
|
|
27751
26564
|
const placeholders = routeIds.map(() => "?").join(",");
|
|
27752
|
-
const callers =
|
|
26565
|
+
const callers = dataDb.prepare(
|
|
27753
26566
|
`SELECT DISTINCT frontend_file FROM massu_py_route_callers WHERE route_id IN (${placeholders})`
|
|
27754
26567
|
).all(...routeIds.map((r2) => r2.id));
|
|
27755
26568
|
if (callers.length > 0) {
|
|
@@ -27766,13 +26579,13 @@ function handlePyImpact(args2, dataDb2) {
|
|
|
27766
26579
|
### Domain: ${domain}`);
|
|
27767
26580
|
return text16(lines.join("\n"));
|
|
27768
26581
|
}
|
|
27769
|
-
function handlePyContext(args2,
|
|
26582
|
+
function handlePyContext(args2, dataDb) {
|
|
27770
26583
|
const file = args2.file;
|
|
27771
26584
|
const lines = [`## Python Context: ${file}`, ""];
|
|
27772
26585
|
const config = getConfig();
|
|
27773
26586
|
const domain = classifyPythonFileDomain(file);
|
|
27774
26587
|
lines.push(`**Domain**: ${domain}`);
|
|
27775
|
-
const imports =
|
|
26588
|
+
const imports = dataDb.prepare(
|
|
27776
26589
|
"SELECT target_file, imported_names FROM massu_py_imports WHERE source_file = ? LIMIT 20"
|
|
27777
26590
|
).all(file);
|
|
27778
26591
|
if (imports.length > 0) {
|
|
@@ -27782,7 +26595,7 @@ function handlePyContext(args2, dataDb2) {
|
|
|
27782
26595
|
lines.push(`- ${imp.target_file}${names.length > 0 ? ": " + names.join(", ") : ""}`);
|
|
27783
26596
|
}
|
|
27784
26597
|
}
|
|
27785
|
-
const importedBy =
|
|
26598
|
+
const importedBy = dataDb.prepare(
|
|
27786
26599
|
"SELECT source_file FROM massu_py_imports WHERE target_file = ? LIMIT 10"
|
|
27787
26600
|
).all(file);
|
|
27788
26601
|
if (importedBy.length > 0) {
|
|
@@ -27791,14 +26604,14 @@ function handlePyContext(args2, dataDb2) {
|
|
|
27791
26604
|
lines.push(`- ${imp.source_file}`);
|
|
27792
26605
|
}
|
|
27793
26606
|
}
|
|
27794
|
-
const routes =
|
|
26607
|
+
const routes = dataDb.prepare("SELECT method, path, function_name, line FROM massu_py_routes WHERE file = ?").all(file);
|
|
27795
26608
|
if (routes.length > 0) {
|
|
27796
26609
|
lines.push("\n### Routes");
|
|
27797
26610
|
for (const r2 of routes) {
|
|
27798
26611
|
lines.push(`- ${r2.method} ${r2.path} \u2192 ${r2.function_name} (L${r2.line})`);
|
|
27799
26612
|
}
|
|
27800
26613
|
}
|
|
27801
|
-
const models =
|
|
26614
|
+
const models = dataDb.prepare("SELECT class_name, table_name, line FROM massu_py_models WHERE file = ?").all(file);
|
|
27802
26615
|
if (models.length > 0) {
|
|
27803
26616
|
lines.push("\n### Models");
|
|
27804
26617
|
for (const m3 of models) {
|
|
@@ -27831,7 +26644,7 @@ var init_python_tools = __esm({
|
|
|
27831
26644
|
});
|
|
27832
26645
|
|
|
27833
26646
|
// src/tools.ts
|
|
27834
|
-
import { readFileSync as
|
|
26647
|
+
import { readFileSync as readFileSync38, existsSync as existsSync38 } from "fs";
|
|
27835
26648
|
import { resolve as resolve31, basename as basename10 } from "path";
|
|
27836
26649
|
function prefix2() {
|
|
27837
26650
|
return getConfig().toolPrefix;
|
|
@@ -27846,41 +26659,41 @@ function stripPrefix3(name) {
|
|
|
27846
26659
|
}
|
|
27847
26660
|
return name;
|
|
27848
26661
|
}
|
|
27849
|
-
function ensureIndexes(
|
|
26662
|
+
function ensureIndexes(dataDb, codegraphDb, force = false) {
|
|
27850
26663
|
const results = [];
|
|
27851
26664
|
const config = getConfig();
|
|
27852
|
-
if (force || isDataStale(
|
|
27853
|
-
const importCount = buildImportIndex(
|
|
26665
|
+
if (codegraphDb !== void 0 && (force || isDataStale(dataDb, codegraphDb))) {
|
|
26666
|
+
const importCount = buildImportIndex(dataDb, codegraphDb);
|
|
27854
26667
|
results.push(`Import edges: ${importCount}`);
|
|
27855
26668
|
if (config.framework.router === "trpc") {
|
|
27856
|
-
const trpcStats = buildTrpcIndex(
|
|
26669
|
+
const trpcStats = buildTrpcIndex(dataDb);
|
|
27857
26670
|
results.push(`tRPC procedures: ${trpcStats.totalProcedures} (${trpcStats.withCallers} with UI, ${trpcStats.withoutCallers} without)`);
|
|
27858
26671
|
}
|
|
27859
|
-
const pageCount = buildPageDeps(
|
|
26672
|
+
const pageCount = buildPageDeps(dataDb, codegraphDb);
|
|
27860
26673
|
results.push(`Page deps: ${pageCount} pages`);
|
|
27861
26674
|
if (config.paths.middleware) {
|
|
27862
|
-
const middlewareCount = buildMiddlewareTree(
|
|
26675
|
+
const middlewareCount = buildMiddlewareTree(dataDb);
|
|
27863
26676
|
results.push(`Middleware tree: ${middlewareCount} files`);
|
|
27864
26677
|
}
|
|
27865
|
-
updateBuildTimestamp(
|
|
26678
|
+
updateBuildTimestamp(dataDb);
|
|
27866
26679
|
}
|
|
27867
26680
|
if (config.python?.root) {
|
|
27868
26681
|
const pythonRoot = config.python.root;
|
|
27869
26682
|
const excludeDirs = config.python.exclude_dirs || ["__pycache__", ".venv", "venv", ".mypy_cache", ".pytest_cache"];
|
|
27870
|
-
if (force || isPythonDataStale(
|
|
27871
|
-
const pyImports = buildPythonImportIndex(
|
|
26683
|
+
if (force || isPythonDataStale(dataDb, resolve31(getProjectRoot(), pythonRoot))) {
|
|
26684
|
+
const pyImports = buildPythonImportIndex(dataDb, pythonRoot, excludeDirs);
|
|
27872
26685
|
results.push(`Python imports: ${pyImports}`);
|
|
27873
|
-
const pyRoutes = buildPythonRouteIndex(
|
|
26686
|
+
const pyRoutes = buildPythonRouteIndex(dataDb, pythonRoot, excludeDirs);
|
|
27874
26687
|
results.push(`Python routes: ${pyRoutes}`);
|
|
27875
|
-
const pyModels = buildPythonModelIndex(
|
|
26688
|
+
const pyModels = buildPythonModelIndex(dataDb, pythonRoot, excludeDirs);
|
|
27876
26689
|
results.push(`Python models: ${pyModels}`);
|
|
27877
26690
|
if (config.python.alembic_dir) {
|
|
27878
|
-
const pyMigrations = buildPythonMigrationIndex(
|
|
26691
|
+
const pyMigrations = buildPythonMigrationIndex(dataDb, config.python.alembic_dir);
|
|
27879
26692
|
results.push(`Python migrations: ${pyMigrations}`);
|
|
27880
26693
|
}
|
|
27881
|
-
const pyCoupling = buildPythonCouplingIndex(
|
|
26694
|
+
const pyCoupling = buildPythonCouplingIndex(dataDb);
|
|
27882
26695
|
results.push(`Python coupling: ${pyCoupling}`);
|
|
27883
|
-
updatePythonBuildTimestamp(
|
|
26696
|
+
updatePythonBuildTimestamp(dataDb);
|
|
27884
26697
|
}
|
|
27885
26698
|
}
|
|
27886
26699
|
if (results.length === 0) return "Indexes are up-to-date.";
|
|
@@ -28008,13 +26821,24 @@ function getToolDefinitions() {
|
|
|
28008
26821
|
}] : []
|
|
28009
26822
|
]);
|
|
28010
26823
|
}
|
|
28011
|
-
|
|
26824
|
+
function assertDataDb(dataDb, toolName) {
|
|
26825
|
+
if (!dataDb) {
|
|
26826
|
+
throw new Error(`Internal: tool "${toolName}" routed to a Data-DB branch but dispatcher did not resolve Data DB. Check TOOL_DB_NEEDS manifest entry includes 'data'.`);
|
|
26827
|
+
}
|
|
26828
|
+
return dataDb;
|
|
26829
|
+
}
|
|
26830
|
+
function assertCodegraphDb(codegraphDb, toolName) {
|
|
26831
|
+
if (!codegraphDb) {
|
|
26832
|
+
throw new Error(`Internal: tool "${toolName}" routed to a CodeGraph branch but dispatcher did not resolve CodeGraph DB. Check TOOL_DB_NEEDS manifest entry includes 'codegraph'.`);
|
|
26833
|
+
}
|
|
26834
|
+
return codegraphDb;
|
|
26835
|
+
}
|
|
26836
|
+
async function handleToolCall(name, args2, dataDb, codegraphDb) {
|
|
28012
26837
|
const userTier = await getCurrentTier();
|
|
28013
26838
|
const requiredTier = getToolTier(name);
|
|
28014
26839
|
if (!isToolAllowed(name, userTier)) {
|
|
28015
26840
|
return text17(`This tool requires ${requiredTier} tier. Current tier: ${userTier}. Upgrade at https://massu.ai/pricing`);
|
|
28016
26841
|
}
|
|
28017
|
-
const syncMessage = ensureIndexes(dataDb2, codegraphDb2);
|
|
28018
26842
|
const pfx = prefix2();
|
|
28019
26843
|
try {
|
|
28020
26844
|
if (name.startsWith(pfx + "_memory_")) {
|
|
@@ -28037,7 +26861,7 @@ async function handleToolCall(name, args2, dataDb2, codegraphDb2) {
|
|
|
28037
26861
|
return handleDocsToolCall(name, args2);
|
|
28038
26862
|
}
|
|
28039
26863
|
if (name.startsWith(pfx + "_sentinel_")) {
|
|
28040
|
-
return handleSentinelToolCall(name, args2,
|
|
26864
|
+
return handleSentinelToolCall(name, args2, assertDataDb(dataDb, name));
|
|
28041
26865
|
}
|
|
28042
26866
|
if (isAnalyticsTool(name)) {
|
|
28043
26867
|
const memDb = getMemoryDb();
|
|
@@ -28128,7 +26952,9 @@ async function handleToolCall(name, args2, dataDb2, codegraphDb2) {
|
|
|
28128
26952
|
}
|
|
28129
26953
|
}
|
|
28130
26954
|
if (isPythonTool(name)) {
|
|
28131
|
-
|
|
26955
|
+
const pyDataDb = assertDataDb(dataDb, name);
|
|
26956
|
+
ensureIndexes(pyDataDb);
|
|
26957
|
+
return handlePythonToolCall(name, args2, pyDataDb);
|
|
28132
26958
|
}
|
|
28133
26959
|
if (isLicenseTool(name)) {
|
|
28134
26960
|
const memDb = getMemoryDb();
|
|
@@ -28140,18 +26966,40 @@ async function handleToolCall(name, args2, dataDb2, codegraphDb2) {
|
|
|
28140
26966
|
}
|
|
28141
26967
|
const baseName = stripPrefix3(name);
|
|
28142
26968
|
switch (baseName) {
|
|
28143
|
-
case "sync":
|
|
28144
|
-
|
|
28145
|
-
|
|
28146
|
-
return
|
|
28147
|
-
|
|
28148
|
-
|
|
28149
|
-
|
|
28150
|
-
|
|
28151
|
-
|
|
28152
|
-
return
|
|
28153
|
-
|
|
28154
|
-
|
|
26969
|
+
case "sync": {
|
|
26970
|
+
const d2 = assertDataDb(dataDb, name);
|
|
26971
|
+
const c2 = assertCodegraphDb(codegraphDb, name);
|
|
26972
|
+
return handleSync(d2, c2);
|
|
26973
|
+
}
|
|
26974
|
+
case "context": {
|
|
26975
|
+
const d2 = assertDataDb(dataDb, name);
|
|
26976
|
+
const c2 = assertCodegraphDb(codegraphDb, name);
|
|
26977
|
+
ensureIndexes(d2, c2);
|
|
26978
|
+
return handleContext(args2.file, d2, c2);
|
|
26979
|
+
}
|
|
26980
|
+
case "trpc_map": {
|
|
26981
|
+
const d2 = assertDataDb(dataDb, name);
|
|
26982
|
+
ensureIndexes(d2, codegraphDb);
|
|
26983
|
+
return handleTrpcMap(args2, d2);
|
|
26984
|
+
}
|
|
26985
|
+
case "coupling_check": {
|
|
26986
|
+
const d2 = assertDataDb(dataDb, name);
|
|
26987
|
+
const c2 = assertCodegraphDb(codegraphDb, name);
|
|
26988
|
+
ensureIndexes(d2, c2);
|
|
26989
|
+
return handleCouplingCheck(args2, d2, c2);
|
|
26990
|
+
}
|
|
26991
|
+
case "impact": {
|
|
26992
|
+
const d2 = assertDataDb(dataDb, name);
|
|
26993
|
+
const c2 = assertCodegraphDb(codegraphDb, name);
|
|
26994
|
+
ensureIndexes(d2, c2);
|
|
26995
|
+
return handleImpact2(args2.file, d2, c2);
|
|
26996
|
+
}
|
|
26997
|
+
case "domains": {
|
|
26998
|
+
const d2 = assertDataDb(dataDb, name);
|
|
26999
|
+
const c2 = assertCodegraphDb(codegraphDb, name);
|
|
27000
|
+
ensureIndexes(d2, c2);
|
|
27001
|
+
return handleDomains(args2, d2, c2);
|
|
27002
|
+
}
|
|
28155
27003
|
case "schema":
|
|
28156
27004
|
return handleSchema(args2);
|
|
28157
27005
|
default:
|
|
@@ -28166,10 +27014,10 @@ async function handleToolCall(name, args2, dataDb2, codegraphDb2) {
|
|
|
28166
27014
|
function text17(content) {
|
|
28167
27015
|
return { content: [{ type: "text", text: content }] };
|
|
28168
27016
|
}
|
|
28169
|
-
function handleSync(
|
|
28170
|
-
const result = ensureIndexes(
|
|
27017
|
+
function handleSync(dataDb, codegraphDb) {
|
|
27018
|
+
const result = ensureIndexes(dataDb, codegraphDb, true);
|
|
28171
27019
|
try {
|
|
28172
|
-
const scanResult = runFeatureScan(
|
|
27020
|
+
const scanResult = runFeatureScan(dataDb);
|
|
28173
27021
|
return text17(`${result}
|
|
28174
27022
|
|
|
28175
27023
|
Feature scan: ${scanResult.registered} features registered (${scanResult.fromProcedures} from procedures, ${scanResult.fromPages} from pages, ${scanResult.fromComponents} from components)`);
|
|
@@ -28179,9 +27027,9 @@ Feature scan: ${scanResult.registered} features registered (${scanResult.fromPro
|
|
|
28179
27027
|
Feature scan failed: ${error instanceof Error ? error.message : String(error)}`);
|
|
28180
27028
|
}
|
|
28181
27029
|
}
|
|
28182
|
-
function handleContext(file,
|
|
27030
|
+
function handleContext(file, dataDb, codegraphDb) {
|
|
28183
27031
|
const lines = [];
|
|
28184
|
-
const nodes =
|
|
27032
|
+
const nodes = codegraphDb.prepare(
|
|
28185
27033
|
"SELECT name, kind, start_line, end_line FROM nodes WHERE file_path = ? ORDER BY start_line"
|
|
28186
27034
|
).all(file);
|
|
28187
27035
|
if (nodes.length > 0) {
|
|
@@ -28208,7 +27056,7 @@ function handleContext(file, dataDb2, codegraphDb2) {
|
|
|
28208
27056
|
}
|
|
28209
27057
|
lines.push("");
|
|
28210
27058
|
}
|
|
28211
|
-
if (isInMiddlewareTree(
|
|
27059
|
+
if (isInMiddlewareTree(dataDb, file)) {
|
|
28212
27060
|
lines.push("## WARNING: Middleware Import Tree");
|
|
28213
27061
|
lines.push("This file is imported (directly or transitively) by the middleware entry point.");
|
|
28214
27062
|
lines.push("NO Node.js dependencies allowed (pino, winston, fs, crypto, path, child_process).");
|
|
@@ -28217,7 +27065,7 @@ function handleContext(file, dataDb2, codegraphDb2) {
|
|
|
28217
27065
|
const domain = classifyFile(file);
|
|
28218
27066
|
lines.push(`## Domain: ${domain}`);
|
|
28219
27067
|
lines.push("");
|
|
28220
|
-
const imports =
|
|
27068
|
+
const imports = dataDb.prepare(
|
|
28221
27069
|
"SELECT target_file, imported_names FROM massu_imports WHERE source_file = ? LIMIT 20"
|
|
28222
27070
|
).all(file);
|
|
28223
27071
|
if (imports.length > 0) {
|
|
@@ -28228,7 +27076,7 @@ function handleContext(file, dataDb2, codegraphDb2) {
|
|
|
28228
27076
|
}
|
|
28229
27077
|
lines.push("");
|
|
28230
27078
|
}
|
|
28231
|
-
const importedBy =
|
|
27079
|
+
const importedBy = dataDb.prepare(
|
|
28232
27080
|
"SELECT source_file FROM massu_imports WHERE target_file = ? LIMIT 20"
|
|
28233
27081
|
).all(file);
|
|
28234
27082
|
if (importedBy.length > 0) {
|
|
@@ -28268,7 +27116,7 @@ function handleContext(file, dataDb2, codegraphDb2) {
|
|
|
28268
27116
|
const root = getProjectRoot();
|
|
28269
27117
|
const absFilePath = ensureWithinRoot(resolve31(resolvedPaths.srcDir, "..", file), root);
|
|
28270
27118
|
if (existsSync38(absFilePath)) {
|
|
28271
|
-
const fileContent =
|
|
27119
|
+
const fileContent = readFileSync38(absFilePath, "utf-8").slice(0, 3e3);
|
|
28272
27120
|
const keywords = [];
|
|
28273
27121
|
if (fileContent.includes("ctx.db")) keywords.push("database", "schema");
|
|
28274
27122
|
if (fileContent.includes("BigInt") || fileContent.includes("Decimal")) keywords.push("BigInt", "serialization");
|
|
@@ -28392,10 +27240,10 @@ function handleContext(file, dataDb2, codegraphDb2) {
|
|
|
28392
27240
|
}
|
|
28393
27241
|
return text17(lines.join("\n") || "No context available for this file.");
|
|
28394
27242
|
}
|
|
28395
|
-
function handleTrpcMap(args2,
|
|
27243
|
+
function handleTrpcMap(args2, dataDb) {
|
|
28396
27244
|
const lines = [];
|
|
28397
27245
|
if (args2.uncoupled) {
|
|
28398
|
-
const uncoupled =
|
|
27246
|
+
const uncoupled = dataDb.prepare(
|
|
28399
27247
|
"SELECT router_name, procedure_name, procedure_type, router_file FROM massu_trpc_procedures WHERE has_ui_caller = 0 ORDER BY router_name, procedure_name"
|
|
28400
27248
|
).all();
|
|
28401
27249
|
lines.push(`## Uncoupled Procedures (${uncoupled.length} total)`);
|
|
@@ -28410,7 +27258,7 @@ function handleTrpcMap(args2, dataDb2) {
|
|
|
28410
27258
|
lines.push(`- ${proc.procedure_name} (${proc.procedure_type})`);
|
|
28411
27259
|
}
|
|
28412
27260
|
} else if (args2.router) {
|
|
28413
|
-
const procs =
|
|
27261
|
+
const procs = dataDb.prepare(
|
|
28414
27262
|
"SELECT id, procedure_name, procedure_type, has_ui_caller FROM massu_trpc_procedures WHERE router_name = ? ORDER BY procedure_name"
|
|
28415
27263
|
).all(args2.router);
|
|
28416
27264
|
lines.push(`## Router: ${args2.router} (${procs.length} procedures)`);
|
|
@@ -28418,7 +27266,7 @@ function handleTrpcMap(args2, dataDb2) {
|
|
|
28418
27266
|
for (const proc of procs) {
|
|
28419
27267
|
const status = proc.has_ui_caller ? "" : " [NO UI CALLERS]";
|
|
28420
27268
|
lines.push(`### ${args2.router}.${proc.procedure_name} (${proc.procedure_type})${status}`);
|
|
28421
|
-
const callSites =
|
|
27269
|
+
const callSites = dataDb.prepare(
|
|
28422
27270
|
"SELECT file, line, call_pattern FROM massu_trpc_call_sites WHERE procedure_id = ?"
|
|
28423
27271
|
).all(proc.id);
|
|
28424
27272
|
if (callSites.length > 0) {
|
|
@@ -28432,7 +27280,7 @@ function handleTrpcMap(args2, dataDb2) {
|
|
|
28432
27280
|
lines.push("");
|
|
28433
27281
|
}
|
|
28434
27282
|
} else if (args2.procedure) {
|
|
28435
|
-
const procs =
|
|
27283
|
+
const procs = dataDb.prepare(
|
|
28436
27284
|
"SELECT id, router_name, router_file, procedure_type, has_ui_caller FROM massu_trpc_procedures WHERE procedure_name = ? ORDER BY router_name"
|
|
28437
27285
|
).all(args2.procedure);
|
|
28438
27286
|
lines.push(`## Procedure "${args2.procedure}" found in ${procs.length} routers`);
|
|
@@ -28440,7 +27288,7 @@ function handleTrpcMap(args2, dataDb2) {
|
|
|
28440
27288
|
for (const proc of procs) {
|
|
28441
27289
|
lines.push(`### ${proc.router_name}.${args2.procedure} (${proc.procedure_type})`);
|
|
28442
27290
|
lines.push(`File: ${proc.router_file}`);
|
|
28443
|
-
const callSites =
|
|
27291
|
+
const callSites = dataDb.prepare(
|
|
28444
27292
|
"SELECT file, line, call_pattern FROM massu_trpc_call_sites WHERE procedure_id = ?"
|
|
28445
27293
|
).all(proc.id);
|
|
28446
27294
|
if (callSites.length > 0) {
|
|
@@ -28454,8 +27302,8 @@ function handleTrpcMap(args2, dataDb2) {
|
|
|
28454
27302
|
lines.push("");
|
|
28455
27303
|
}
|
|
28456
27304
|
} else {
|
|
28457
|
-
const total =
|
|
28458
|
-
const coupled =
|
|
27305
|
+
const total = dataDb.prepare("SELECT COUNT(*) as count FROM massu_trpc_procedures").get();
|
|
27306
|
+
const coupled = dataDb.prepare("SELECT COUNT(*) as count FROM massu_trpc_procedures WHERE has_ui_caller = 1").get();
|
|
28459
27307
|
const uncoupled = total.count - coupled.count;
|
|
28460
27308
|
lines.push("## tRPC Procedure Summary");
|
|
28461
27309
|
lines.push(`- Total procedures: ${total.count}`);
|
|
@@ -28467,16 +27315,16 @@ function handleTrpcMap(args2, dataDb2) {
|
|
|
28467
27315
|
}
|
|
28468
27316
|
return text17(lines.join("\n"));
|
|
28469
27317
|
}
|
|
28470
|
-
function handleCouplingCheck(args2,
|
|
27318
|
+
function handleCouplingCheck(args2, dataDb, codegraphDb) {
|
|
28471
27319
|
const lines = [];
|
|
28472
27320
|
const stagedFiles = args2.staged_files;
|
|
28473
27321
|
let uncoupledProcs;
|
|
28474
27322
|
if (stagedFiles) {
|
|
28475
|
-
uncoupledProcs =
|
|
27323
|
+
uncoupledProcs = dataDb.prepare(
|
|
28476
27324
|
`SELECT router_name, procedure_name, procedure_type, router_file FROM massu_trpc_procedures WHERE has_ui_caller = 0 AND router_file IN (${stagedFiles.map(() => "?").join(",")})`
|
|
28477
27325
|
).all(...stagedFiles);
|
|
28478
27326
|
} else {
|
|
28479
|
-
uncoupledProcs =
|
|
27327
|
+
uncoupledProcs = dataDb.prepare(
|
|
28480
27328
|
"SELECT router_name, procedure_name, procedure_type, router_file FROM massu_trpc_procedures WHERE has_ui_caller = 0"
|
|
28481
27329
|
).all();
|
|
28482
27330
|
}
|
|
@@ -28492,12 +27340,12 @@ function handleCouplingCheck(args2, dataDb2, codegraphDb2) {
|
|
|
28492
27340
|
lines.push("### Uncoupled Procedures: 0 (PASS)");
|
|
28493
27341
|
lines.push("");
|
|
28494
27342
|
}
|
|
28495
|
-
const allPages =
|
|
27343
|
+
const allPages = codegraphDb.prepare(
|
|
28496
27344
|
"SELECT path FROM files WHERE path LIKE 'src/app/%/page.tsx' OR path = 'src/app/page.tsx'"
|
|
28497
27345
|
).all();
|
|
28498
27346
|
const pageImports = /* @__PURE__ */ new Set();
|
|
28499
27347
|
for (const page of allPages) {
|
|
28500
|
-
const imports =
|
|
27348
|
+
const imports = dataDb.prepare(
|
|
28501
27349
|
"SELECT target_file FROM massu_imports WHERE source_file = ?"
|
|
28502
27350
|
).all(page.path);
|
|
28503
27351
|
for (const imp of imports) {
|
|
@@ -28507,7 +27355,7 @@ function handleCouplingCheck(args2, dataDb2, codegraphDb2) {
|
|
|
28507
27355
|
let componentFiles;
|
|
28508
27356
|
if (stagedFiles) {
|
|
28509
27357
|
const placeholders = stagedFiles.map(() => "?").join(",");
|
|
28510
|
-
componentFiles =
|
|
27358
|
+
componentFiles = codegraphDb.prepare(
|
|
28511
27359
|
`SELECT path FROM files WHERE path LIKE 'src/components/%' AND path IN (${placeholders})`
|
|
28512
27360
|
).all(...stagedFiles);
|
|
28513
27361
|
} else {
|
|
@@ -28525,11 +27373,11 @@ function handleCouplingCheck(args2, dataDb2, codegraphDb2) {
|
|
|
28525
27373
|
lines.push(`### RESULT: ${totalIssues === 0 ? "PASS" : `FAIL (${totalIssues} issues)`}`);
|
|
28526
27374
|
return text17(lines.join("\n"));
|
|
28527
27375
|
}
|
|
28528
|
-
function handleImpact2(file,
|
|
27376
|
+
function handleImpact2(file, dataDb, codegraphDb) {
|
|
28529
27377
|
const lines = [];
|
|
28530
27378
|
lines.push(`## Impact Analysis: ${file}`);
|
|
28531
27379
|
lines.push("");
|
|
28532
|
-
const affectedPages = findAffectedPages(
|
|
27380
|
+
const affectedPages = findAffectedPages(dataDb, file);
|
|
28533
27381
|
if (affectedPages.length > 0) {
|
|
28534
27382
|
const portals = [...new Set(affectedPages.map((p19) => p19.portal))];
|
|
28535
27383
|
const allTables = [...new Set(affectedPages.flatMap((p19) => p19.tables))];
|
|
@@ -28559,7 +27407,7 @@ function handleImpact2(file, dataDb2, codegraphDb2) {
|
|
|
28559
27407
|
lines.push("No pages affected (file may not be in any page dependency chain).");
|
|
28560
27408
|
lines.push("");
|
|
28561
27409
|
}
|
|
28562
|
-
const inMiddleware = isInMiddlewareTree(
|
|
27410
|
+
const inMiddleware = isInMiddlewareTree(dataDb, file);
|
|
28563
27411
|
if (inMiddleware) {
|
|
28564
27412
|
lines.push("### WARNING: In Middleware Import Tree");
|
|
28565
27413
|
lines.push("Changes to this file affect Edge Runtime. No Node.js deps allowed.");
|
|
@@ -28569,7 +27417,7 @@ function handleImpact2(file, dataDb2, codegraphDb2) {
|
|
|
28569
27417
|
lines.push("");
|
|
28570
27418
|
const fileDomain = classifyFile(file);
|
|
28571
27419
|
lines.push(`### Domain: ${fileDomain}`);
|
|
28572
|
-
const imports =
|
|
27420
|
+
const imports = dataDb.prepare(
|
|
28573
27421
|
"SELECT target_file FROM massu_imports WHERE source_file = ?"
|
|
28574
27422
|
).all(file);
|
|
28575
27423
|
const crossings = [];
|
|
@@ -28587,7 +27435,7 @@ function handleImpact2(file, dataDb2, codegraphDb2) {
|
|
|
28587
27435
|
}
|
|
28588
27436
|
return text17(lines.join("\n"));
|
|
28589
27437
|
}
|
|
28590
|
-
function handleDomains(args2,
|
|
27438
|
+
function handleDomains(args2, dataDb, codegraphDb) {
|
|
28591
27439
|
const lines = [];
|
|
28592
27440
|
const domains = getConfig().domains;
|
|
28593
27441
|
if (args2.file) {
|
|
@@ -28600,7 +27448,7 @@ function handleDomains(args2, dataDb2, codegraphDb2) {
|
|
|
28600
27448
|
lines.push(`Allowed imports from: ${domainConfig.allowedImportsFrom.join(", ") || "any domain (system)"}`);
|
|
28601
27449
|
}
|
|
28602
27450
|
} else if (args2.crossings) {
|
|
28603
|
-
const crossings = findCrossDomainImports(
|
|
27451
|
+
const crossings = findCrossDomainImports(dataDb);
|
|
28604
27452
|
const violations = crossings.filter((c2) => !c2.allowed);
|
|
28605
27453
|
const allowed = crossings.filter((c2) => c2.allowed);
|
|
28606
27454
|
lines.push(`## Cross-Domain Import Analysis`);
|
|
@@ -28619,7 +27467,7 @@ function handleDomains(args2, dataDb2, codegraphDb2) {
|
|
|
28619
27467
|
}
|
|
28620
27468
|
} else if (args2.domain) {
|
|
28621
27469
|
const domainName = args2.domain;
|
|
28622
|
-
const files = getFilesInDomain(
|
|
27470
|
+
const files = getFilesInDomain(dataDb, codegraphDb, domainName);
|
|
28623
27471
|
const config = domains.find((d2) => d2.name === domainName);
|
|
28624
27472
|
lines.push(`## Domain: ${domainName}`);
|
|
28625
27473
|
if (config) {
|
|
@@ -28696,7 +27544,7 @@ function handleSchema(args2) {
|
|
|
28696
27544
|
if (!existsSync38(absPath)) {
|
|
28697
27545
|
return text17(`File not found: ${file}`);
|
|
28698
27546
|
}
|
|
28699
|
-
const source =
|
|
27547
|
+
const source = readFileSync38(absPath, "utf-8");
|
|
28700
27548
|
const config = getConfig();
|
|
28701
27549
|
const dbPattern = config.dbAccessPattern ?? "ctx.db.{table}";
|
|
28702
27550
|
const regexStr = dbPattern.replace(/[.*+?^${}()|[\]\\]/g, "\\$&").replace("\\{table\\}", "(\\w+)");
|
|
@@ -28772,15 +27620,163 @@ var init_tools = __esm({
|
|
|
28772
27620
|
}
|
|
28773
27621
|
});
|
|
28774
27622
|
|
|
27623
|
+
// src/tool-db-needs.ts
|
|
27624
|
+
function stripConfiguredPrefix(toolName, prefix3) {
|
|
27625
|
+
const pfx = `${prefix3}_`;
|
|
27626
|
+
return toolName.startsWith(pfx) ? toolName.slice(pfx.length) : toolName;
|
|
27627
|
+
}
|
|
27628
|
+
function getToolDbNeeds(toolName, prefix3) {
|
|
27629
|
+
const shortName = stripConfiguredPrefix(toolName, prefix3);
|
|
27630
|
+
const needs = TOOL_DB_NEEDS[shortName];
|
|
27631
|
+
if (needs === void 0) {
|
|
27632
|
+
throw new UnknownToolError(toolName);
|
|
27633
|
+
}
|
|
27634
|
+
return needs;
|
|
27635
|
+
}
|
|
27636
|
+
var UnknownToolError, TOOL_DB_NEEDS;
|
|
27637
|
+
var init_tool_db_needs = __esm({
|
|
27638
|
+
"src/tool-db-needs.ts"() {
|
|
27639
|
+
"use strict";
|
|
27640
|
+
UnknownToolError = class extends Error {
|
|
27641
|
+
toolName;
|
|
27642
|
+
constructor(toolName) {
|
|
27643
|
+
super(`Tool not registered in TOOL_DB_NEEDS manifest: ${toolName}. Add an entry to packages/core/src/tool-db-needs.ts.`);
|
|
27644
|
+
this.name = "UnknownToolError";
|
|
27645
|
+
this.toolName = toolName;
|
|
27646
|
+
}
|
|
27647
|
+
};
|
|
27648
|
+
TOOL_DB_NEEDS = {
|
|
27649
|
+
// === Core code-intel tools (tools.ts:393-406) ===
|
|
27650
|
+
// Use CodeGraph DB (read-only AST) + Data DB (Massu's import/trpc/sentinel
|
|
27651
|
+
// tables). All call `ensureIndexes` directly or via shared infrastructure.
|
|
27652
|
+
sync: ["codegraph", "data"],
|
|
27653
|
+
context: ["codegraph", "data"],
|
|
27654
|
+
coupling_check: ["codegraph", "data"],
|
|
27655
|
+
impact: ["codegraph", "data"],
|
|
27656
|
+
domains: ["codegraph", "data"],
|
|
27657
|
+
// `trpc_map` reads only Data DB (tRPC index lives there); no CodeGraph access.
|
|
27658
|
+
trpc_map: ["data"],
|
|
27659
|
+
// `schema` reads filesystem (Prisma schema files); no DB access at all.
|
|
27660
|
+
schema: [],
|
|
27661
|
+
// === Memory tools (memory-tools.ts) ===
|
|
27662
|
+
// Routed via `name.startsWith(pfx + '_memory_')` at tools.ts:284-290.
|
|
27663
|
+
// Handler opens memory DB per-call (with try/finally close).
|
|
27664
|
+
memory_search: ["memory"],
|
|
27665
|
+
memory_timeline: ["memory"],
|
|
27666
|
+
memory_detail: ["memory"],
|
|
27667
|
+
memory_sessions: ["memory"],
|
|
27668
|
+
memory_failures: ["memory"],
|
|
27669
|
+
memory_ingest: ["memory"],
|
|
27670
|
+
memory_backfill: ["memory"],
|
|
27671
|
+
// === Observability tools (observability-tools.ts) ===
|
|
27672
|
+
// Routed via `isObservabilityTool(name)` at tools.ts:294-300. Memory DB only.
|
|
27673
|
+
session_replay: ["memory"],
|
|
27674
|
+
session_stats: ["memory"],
|
|
27675
|
+
tool_patterns: ["memory"],
|
|
27676
|
+
prompt_analysis: ["memory"],
|
|
27677
|
+
// === Docs tools (docs-tools.ts) ===
|
|
27678
|
+
// Routed via `name.startsWith(pfx + '_docs_')` at tools.ts:303-306.
|
|
27679
|
+
// No DB access — pure filesystem traversal.
|
|
27680
|
+
docs_audit: [],
|
|
27681
|
+
docs_coverage: [],
|
|
27682
|
+
// === Sentinel registry tools (sentinel-tools.ts:180-184) ===
|
|
27683
|
+
// Routed via `name.startsWith(pfx + '_sentinel_')` at tools.ts:308.
|
|
27684
|
+
// Handler signature: `(name, args, dataDb)` — Data DB only.
|
|
27685
|
+
sentinel_register: ["data"],
|
|
27686
|
+
sentinel_validate: ["data"],
|
|
27687
|
+
sentinel_search: ["data"],
|
|
27688
|
+
sentinel_detail: ["data"],
|
|
27689
|
+
sentinel_impact: ["data"],
|
|
27690
|
+
sentinel_parity: ["data"],
|
|
27691
|
+
// === Knowledge layer tools (knowledge-tools.ts) ===
|
|
27692
|
+
// Routed via `isKnowledgeTool(name)` at tools.ts:372-376. Primary DB is
|
|
27693
|
+
// `knowledgeDb` (separate SQLite file). Handlers ALSO call `getDataDb()`
|
|
27694
|
+
// (knowledge-tools.ts:1187,1275) and `getMemoryDb()` (knowledge-tools.ts:1332)
|
|
27695
|
+
// for cross-DB joins — declare all three so the AST completeness test
|
|
27696
|
+
// (P-B-002) verifies the full access pattern.
|
|
27697
|
+
knowledge_search: ["knowledge", "data", "memory"],
|
|
27698
|
+
knowledge_pattern: ["knowledge", "data", "memory"],
|
|
27699
|
+
knowledge_rule: ["knowledge", "data", "memory"],
|
|
27700
|
+
knowledge_correct: ["knowledge", "data", "memory"],
|
|
27701
|
+
knowledge_incident: ["knowledge", "data", "memory"],
|
|
27702
|
+
knowledge_plan: ["knowledge", "data", "memory"],
|
|
27703
|
+
knowledge_command: ["knowledge", "data", "memory"],
|
|
27704
|
+
knowledge_gaps: ["knowledge", "data", "memory"],
|
|
27705
|
+
knowledge_verification: ["knowledge", "data", "memory"],
|
|
27706
|
+
knowledge_effectiveness: ["knowledge", "data", "memory"],
|
|
27707
|
+
knowledge_graph: ["knowledge", "data", "memory"],
|
|
27708
|
+
knowledge_schema_check: ["knowledge", "data", "memory"],
|
|
27709
|
+
// === Analytics / quality (analytics.ts) ===
|
|
27710
|
+
// Routed via `isAnalyticsTool(name)`. Memory DB only.
|
|
27711
|
+
quality_score: ["memory"],
|
|
27712
|
+
quality_report: ["memory"],
|
|
27713
|
+
quality_trend: ["memory"],
|
|
27714
|
+
// === Cost tracker (cost-tracker.ts) ===
|
|
27715
|
+
cost_session: ["memory"],
|
|
27716
|
+
cost_feature: ["memory"],
|
|
27717
|
+
cost_trend: ["memory"],
|
|
27718
|
+
// === Prompt analyzer (prompt-analyzer.ts) ===
|
|
27719
|
+
prompt_effectiveness: ["memory"],
|
|
27720
|
+
prompt_suggestions: ["memory"],
|
|
27721
|
+
// === Audit trail (audit-trail.ts) ===
|
|
27722
|
+
audit_chain: ["memory"],
|
|
27723
|
+
audit_log: ["memory"],
|
|
27724
|
+
audit_report: ["memory"],
|
|
27725
|
+
// === Validation engine (validation-engine.ts) ===
|
|
27726
|
+
validation_check: ["memory"],
|
|
27727
|
+
validation_report: ["memory"],
|
|
27728
|
+
// === ADR generator (adr-generator.ts) ===
|
|
27729
|
+
adr_create: ["memory"],
|
|
27730
|
+
adr_list: ["memory"],
|
|
27731
|
+
adr_detail: ["memory"],
|
|
27732
|
+
// === Security scorer (security-scorer.ts) ===
|
|
27733
|
+
security_score: ["memory"],
|
|
27734
|
+
security_heatmap: ["memory"],
|
|
27735
|
+
security_trend: ["memory"],
|
|
27736
|
+
// === Dependency scorer (dependency-scorer.ts) ===
|
|
27737
|
+
dep_score: ["memory"],
|
|
27738
|
+
dep_alternatives: ["memory"],
|
|
27739
|
+
// === Team knowledge (team-knowledge.ts) ===
|
|
27740
|
+
team_expertise: ["memory"],
|
|
27741
|
+
team_conflicts: ["memory"],
|
|
27742
|
+
team_search: ["memory"],
|
|
27743
|
+
// === Regression detector (regression-detector.ts) ===
|
|
27744
|
+
regression_risk: ["memory"],
|
|
27745
|
+
feature_health: ["memory"],
|
|
27746
|
+
// === Python code-intel tools (python-tools.ts) ===
|
|
27747
|
+
// Routed via `isPythonTool(name)` at tools.ts:379-381. Data DB only.
|
|
27748
|
+
py_imports: ["data"],
|
|
27749
|
+
py_routes: ["data"],
|
|
27750
|
+
py_models: ["data"],
|
|
27751
|
+
py_migrations: ["data"],
|
|
27752
|
+
py_coupling: ["data"],
|
|
27753
|
+
py_context: ["data"],
|
|
27754
|
+
py_impact: ["data"],
|
|
27755
|
+
py_domains: ["data"],
|
|
27756
|
+
// === License tool (license.ts) ===
|
|
27757
|
+
license_status: ["memory"]
|
|
27758
|
+
};
|
|
27759
|
+
}
|
|
27760
|
+
});
|
|
27761
|
+
|
|
28775
27762
|
// src/server.ts
|
|
28776
27763
|
var server_exports = {};
|
|
28777
|
-
import { readFileSync as
|
|
28778
|
-
import { resolve as resolve32, dirname as
|
|
27764
|
+
import { readFileSync as readFileSync39 } from "fs";
|
|
27765
|
+
import { resolve as resolve32, dirname as dirname16 } from "path";
|
|
28779
27766
|
import { fileURLToPath as fileURLToPath4 } from "url";
|
|
28780
|
-
function
|
|
28781
|
-
|
|
28782
|
-
|
|
28783
|
-
|
|
27767
|
+
function resolveDbsForTool(toolName) {
|
|
27768
|
+
const needs = getToolDbNeeds(toolName, getConfig().toolPrefix);
|
|
27769
|
+
let dataDbResolved;
|
|
27770
|
+
let codegraphDbResolved;
|
|
27771
|
+
if (needs.includes("data")) {
|
|
27772
|
+
if (!dataDbCache) dataDbCache = getDataDb();
|
|
27773
|
+
dataDbResolved = dataDbCache;
|
|
27774
|
+
}
|
|
27775
|
+
if (needs.includes("codegraph")) {
|
|
27776
|
+
if (!codegraphDbCache) codegraphDbCache = getCodeGraphDb();
|
|
27777
|
+
codegraphDbResolved = codegraphDbCache;
|
|
27778
|
+
}
|
|
27779
|
+
return { needs, dataDb: dataDbResolved, codegraphDb: codegraphDbResolved };
|
|
28784
27780
|
}
|
|
28785
27781
|
async function handleRequest(request) {
|
|
28786
27782
|
const { method, params, id } = request;
|
|
@@ -28815,13 +27811,46 @@ async function handleRequest(request) {
|
|
|
28815
27811
|
case "tools/call": {
|
|
28816
27812
|
const toolName = params?.name;
|
|
28817
27813
|
const toolArgs = params?.arguments ?? {};
|
|
28818
|
-
|
|
28819
|
-
|
|
28820
|
-
|
|
28821
|
-
|
|
28822
|
-
|
|
28823
|
-
|
|
28824
|
-
|
|
27814
|
+
try {
|
|
27815
|
+
const { dataDb: lDb, codegraphDb: cgDb } = resolveDbsForTool(toolName);
|
|
27816
|
+
const result = await handleToolCall(toolName, toolArgs, lDb, cgDb);
|
|
27817
|
+
return {
|
|
27818
|
+
jsonrpc: "2.0",
|
|
27819
|
+
id: id ?? null,
|
|
27820
|
+
result
|
|
27821
|
+
};
|
|
27822
|
+
} catch (err) {
|
|
27823
|
+
if (err instanceof CodegraphDbNotInitializedError) {
|
|
27824
|
+
return {
|
|
27825
|
+
jsonrpc: "2.0",
|
|
27826
|
+
id: id ?? null,
|
|
27827
|
+
error: {
|
|
27828
|
+
code: -32001,
|
|
27829
|
+
message: `Tool requires CodeGraph database which is not initialized for this repo`,
|
|
27830
|
+
data: {
|
|
27831
|
+
remedy: "npx @colbymchenry/codegraph@0.7.4 init . && npx @colbymchenry/codegraph@0.7.4 index .",
|
|
27832
|
+
codegraphDbPath: err.dbPath,
|
|
27833
|
+
tool: toolName
|
|
27834
|
+
}
|
|
27835
|
+
}
|
|
27836
|
+
};
|
|
27837
|
+
}
|
|
27838
|
+
if (err instanceof UnknownToolError) {
|
|
27839
|
+
return {
|
|
27840
|
+
jsonrpc: "2.0",
|
|
27841
|
+
id: id ?? null,
|
|
27842
|
+
error: {
|
|
27843
|
+
code: -32602,
|
|
27844
|
+
message: `Unknown tool: ${err.toolName}`,
|
|
27845
|
+
data: {
|
|
27846
|
+
remedy: "Tool not registered in TOOL_DB_NEEDS manifest. See packages/core/src/tool-db-needs.ts.",
|
|
27847
|
+
tool: toolName
|
|
27848
|
+
}
|
|
27849
|
+
}
|
|
27850
|
+
};
|
|
27851
|
+
}
|
|
27852
|
+
throw err;
|
|
27853
|
+
}
|
|
28825
27854
|
}
|
|
28826
27855
|
case "ping": {
|
|
28827
27856
|
return { jsonrpc: "2.0", id: id ?? null, result: {} };
|
|
@@ -28858,7 +27887,7 @@ function pruneMemoryOnStartup() {
|
|
|
28858
27887
|
);
|
|
28859
27888
|
}
|
|
28860
27889
|
}
|
|
28861
|
-
var __dirname4, PKG_VERSION,
|
|
27890
|
+
var __dirname4, PKG_VERSION, codegraphDbCache, dataDbCache, buffer;
|
|
28862
27891
|
var init_server = __esm({
|
|
28863
27892
|
"src/server.ts"() {
|
|
28864
27893
|
"use strict";
|
|
@@ -28867,17 +27896,18 @@ var init_server = __esm({
|
|
|
28867
27896
|
init_tools();
|
|
28868
27897
|
init_memory_db();
|
|
28869
27898
|
init_license();
|
|
28870
|
-
|
|
27899
|
+
init_tool_db_needs();
|
|
27900
|
+
__dirname4 = dirname16(fileURLToPath4(import.meta.url));
|
|
28871
27901
|
PKG_VERSION = (() => {
|
|
28872
27902
|
try {
|
|
28873
|
-
const pkg = JSON.parse(
|
|
27903
|
+
const pkg = JSON.parse(readFileSync39(resolve32(__dirname4, "..", "package.json"), "utf-8"));
|
|
28874
27904
|
return pkg.version ?? "0.0.0";
|
|
28875
27905
|
} catch {
|
|
28876
27906
|
return "0.0.0";
|
|
28877
27907
|
}
|
|
28878
27908
|
})();
|
|
28879
|
-
|
|
28880
|
-
|
|
27909
|
+
codegraphDbCache = null;
|
|
27910
|
+
dataDbCache = null;
|
|
28881
27911
|
pruneMemoryOnStartup();
|
|
28882
27912
|
getCurrentTier().then((tier) => {
|
|
28883
27913
|
process.stderr.write(`massu: License tier: ${tier}
|
|
@@ -28897,8 +27927,22 @@ var init_server = __esm({
|
|
|
28897
27927
|
const line = buffer.slice(0, newlineIndex).trim();
|
|
28898
27928
|
buffer = buffer.slice(newlineIndex + 1);
|
|
28899
27929
|
if (!line) continue;
|
|
27930
|
+
let request = null;
|
|
27931
|
+
try {
|
|
27932
|
+
request = JSON.parse(line);
|
|
27933
|
+
} catch (parseError) {
|
|
27934
|
+
const errorResponse = {
|
|
27935
|
+
jsonrpc: "2.0",
|
|
27936
|
+
id: null,
|
|
27937
|
+
error: {
|
|
27938
|
+
code: -32700,
|
|
27939
|
+
message: `Parse error: ${parseError instanceof Error ? parseError.message : String(parseError)}`
|
|
27940
|
+
}
|
|
27941
|
+
};
|
|
27942
|
+
process.stdout.write(JSON.stringify(errorResponse) + "\n");
|
|
27943
|
+
continue;
|
|
27944
|
+
}
|
|
28900
27945
|
try {
|
|
28901
|
-
const request = JSON.parse(line);
|
|
28902
27946
|
const response = await handleRequest(request);
|
|
28903
27947
|
if (request.id !== void 0) {
|
|
28904
27948
|
const responseStr = JSON.stringify(response);
|
|
@@ -28907,10 +27951,10 @@ var init_server = __esm({
|
|
|
28907
27951
|
} catch (error) {
|
|
28908
27952
|
const errorResponse = {
|
|
28909
27953
|
jsonrpc: "2.0",
|
|
28910
|
-
id: null,
|
|
27954
|
+
id: request.id ?? null,
|
|
28911
27955
|
error: {
|
|
28912
|
-
code: -
|
|
28913
|
-
message: `
|
|
27956
|
+
code: -32603,
|
|
27957
|
+
message: `Internal error: ${error instanceof Error ? error.message : String(error)}`
|
|
28914
27958
|
}
|
|
28915
27959
|
};
|
|
28916
27960
|
process.stdout.write(JSON.stringify(errorResponse) + "\n");
|
|
@@ -28918,8 +27962,8 @@ var init_server = __esm({
|
|
|
28918
27962
|
}
|
|
28919
27963
|
});
|
|
28920
27964
|
process.stdin.on("end", () => {
|
|
28921
|
-
if (
|
|
28922
|
-
if (
|
|
27965
|
+
if (codegraphDbCache) codegraphDbCache.close();
|
|
27966
|
+
if (dataDbCache) dataDbCache.close();
|
|
28923
27967
|
process.exit(0);
|
|
28924
27968
|
});
|
|
28925
27969
|
process.on("uncaughtException", (error) => {
|
|
@@ -29173,7 +28217,7 @@ var config_upgrade_exports = {};
|
|
|
29173
28217
|
__export(config_upgrade_exports, {
|
|
29174
28218
|
runConfigUpgrade: () => runConfigUpgrade
|
|
29175
28219
|
});
|
|
29176
|
-
import { existsSync as existsSync39, readFileSync as
|
|
28220
|
+
import { existsSync as existsSync39, readFileSync as readFileSync40, writeFileSync as writeFileSync6, copyFileSync, unlinkSync as unlinkSync2 } from "fs";
|
|
29177
28221
|
import { resolve as resolve33 } from "path";
|
|
29178
28222
|
import { parse as parseYaml6 } from "yaml";
|
|
29179
28223
|
async function runConfigUpgrade(opts = {}) {
|
|
@@ -29192,7 +28236,7 @@ async function runConfigUpgrade(opts = {}) {
|
|
|
29192
28236
|
}
|
|
29193
28237
|
try {
|
|
29194
28238
|
copyFileSync(bakPath, configPath);
|
|
29195
|
-
|
|
28239
|
+
unlinkSync2(bakPath);
|
|
29196
28240
|
log("Config restored from backup.\n");
|
|
29197
28241
|
return { exitCode: 0, action: "rolled-back" };
|
|
29198
28242
|
} catch (e2) {
|
|
@@ -29208,7 +28252,7 @@ async function runConfigUpgrade(opts = {}) {
|
|
|
29208
28252
|
}
|
|
29209
28253
|
let existing;
|
|
29210
28254
|
try {
|
|
29211
|
-
const content =
|
|
28255
|
+
const content = readFileSync40(configPath, "utf-8");
|
|
29212
28256
|
const parsed = parseYaml6(content);
|
|
29213
28257
|
if (!parsed || typeof parsed !== "object") {
|
|
29214
28258
|
throw new Error("config is not a YAML object");
|
|
@@ -29231,8 +28275,8 @@ async function runConfigUpgrade(opts = {}) {
|
|
|
29231
28275
|
fingerprint: computeFingerprint(detection)
|
|
29232
28276
|
};
|
|
29233
28277
|
try {
|
|
29234
|
-
const original =
|
|
29235
|
-
|
|
28278
|
+
const original = readFileSync40(configPath, "utf-8");
|
|
28279
|
+
writeFileSync6(bakPath, original, "utf-8");
|
|
29236
28280
|
} catch (e2) {
|
|
29237
28281
|
const message = `Failed to write backup: ${e2 instanceof Error ? e2.message : String(e2)}`;
|
|
29238
28282
|
err(message + "\n");
|
|
@@ -29265,7 +28309,7 @@ var config_check_drift_exports = {};
|
|
|
29265
28309
|
__export(config_check_drift_exports, {
|
|
29266
28310
|
runConfigCheckDrift: () => runConfigCheckDrift
|
|
29267
28311
|
});
|
|
29268
|
-
import { existsSync as existsSync40, readFileSync as
|
|
28312
|
+
import { existsSync as existsSync40, readFileSync as readFileSync41 } from "fs";
|
|
29269
28313
|
import { resolve as resolve34 } from "path";
|
|
29270
28314
|
import { parse as parseYaml7 } from "yaml";
|
|
29271
28315
|
function renderChanges(changes) {
|
|
@@ -29293,7 +28337,7 @@ async function runConfigCheckDrift(opts = {}) {
|
|
|
29293
28337
|
}
|
|
29294
28338
|
let config;
|
|
29295
28339
|
try {
|
|
29296
|
-
const content =
|
|
28340
|
+
const content = readFileSync41(configPath, "utf-8");
|
|
29297
28341
|
const parsed = parseYaml7(content);
|
|
29298
28342
|
if (!parsed || typeof parsed !== "object") {
|
|
29299
28343
|
throw new Error("config is not a YAML object");
|
|
@@ -29360,11 +28404,11 @@ var init_config_check_drift = __esm({
|
|
|
29360
28404
|
});
|
|
29361
28405
|
|
|
29362
28406
|
// src/cli.ts
|
|
29363
|
-
import { readFileSync as
|
|
29364
|
-
import { resolve as resolve35, dirname as
|
|
28407
|
+
import { readFileSync as readFileSync42 } from "fs";
|
|
28408
|
+
import { resolve as resolve35, dirname as dirname17 } from "path";
|
|
29365
28409
|
import { fileURLToPath as fileURLToPath5 } from "url";
|
|
29366
28410
|
var __filename4 = fileURLToPath5(import.meta.url);
|
|
29367
|
-
var __dirname5 =
|
|
28411
|
+
var __dirname5 = dirname17(__filename4);
|
|
29368
28412
|
var args = process.argv.slice(2);
|
|
29369
28413
|
var subcommand = args[0];
|
|
29370
28414
|
async function main() {
|
|
@@ -29546,7 +28590,7 @@ Examples:
|
|
|
29546
28590
|
}
|
|
29547
28591
|
function printVersion() {
|
|
29548
28592
|
try {
|
|
29549
|
-
const pkg = JSON.parse(
|
|
28593
|
+
const pkg = JSON.parse(readFileSync42(resolve35(__dirname5, "../package.json"), "utf-8"));
|
|
29550
28594
|
console.log(`massu v${pkg.version}`);
|
|
29551
28595
|
} catch {
|
|
29552
28596
|
console.log("massu v0.1.0");
|