@massu/core 1.6.1 → 1.6.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/cli.js +543 -285
- package/package.json +1 -1
- package/src/db.ts +24 -1
- package/src/security/registry-pubkey.generated.ts +1 -1
- package/src/server-dispatch.ts +225 -0
- package/src/server.ts +9 -114
- package/src/tool-db-needs.ts +226 -0
- package/src/tools.ts +110 -24
package/dist/cli.js
CHANGED
|
@@ -17612,7 +17612,7 @@ import { existsSync as existsSync23, mkdirSync as mkdirSync9, readdirSync as rea
|
|
|
17612
17612
|
function getCodeGraphDb() {
|
|
17613
17613
|
const dbPath = getResolvedPaths().codegraphDbPath;
|
|
17614
17614
|
if (!existsSync23(dbPath)) {
|
|
17615
|
-
throw new
|
|
17615
|
+
throw new CodegraphDbNotInitializedError(dbPath);
|
|
17616
17616
|
}
|
|
17617
17617
|
const db = new Database2(dbPath, { readonly: true });
|
|
17618
17618
|
db.pragma("journal_mode = WAL");
|
|
@@ -17876,18 +17876,18 @@ function initDataSchema(db) {
|
|
|
17876
17876
|
END;
|
|
17877
17877
|
`);
|
|
17878
17878
|
}
|
|
17879
|
-
function isDataStale(
|
|
17880
|
-
const lastBuild =
|
|
17879
|
+
function isDataStale(dataDb, codegraphDb) {
|
|
17880
|
+
const lastBuild = dataDb.prepare("SELECT value FROM massu_meta WHERE key = 'last_build_time'").get();
|
|
17881
17881
|
if (!lastBuild) return true;
|
|
17882
|
-
const latestIndexed =
|
|
17882
|
+
const latestIndexed = codegraphDb.prepare("SELECT MAX(indexed_at) as latest FROM files").get();
|
|
17883
17883
|
if (!latestIndexed?.latest) return true;
|
|
17884
17884
|
return latestIndexed.latest * 1e3 > new Date(lastBuild.value).getTime();
|
|
17885
17885
|
}
|
|
17886
|
-
function updateBuildTimestamp(
|
|
17887
|
-
|
|
17886
|
+
function updateBuildTimestamp(dataDb) {
|
|
17887
|
+
dataDb.prepare("INSERT OR REPLACE INTO massu_meta (key, value) VALUES ('last_build_time', ?)").run((/* @__PURE__ */ new Date()).toISOString());
|
|
17888
17888
|
}
|
|
17889
|
-
function isPythonDataStale(
|
|
17890
|
-
const lastBuild =
|
|
17889
|
+
function isPythonDataStale(dataDb, pythonRoot) {
|
|
17890
|
+
const lastBuild = dataDb.prepare("SELECT value FROM massu_py_meta WHERE key = 'last_build_time'").get();
|
|
17891
17891
|
if (!lastBuild) return true;
|
|
17892
17892
|
const lastBuildTime = new Date(lastBuild.value).getTime();
|
|
17893
17893
|
function checkDir(dir) {
|
|
@@ -17908,13 +17908,22 @@ function isPythonDataStale(dataDb2, pythonRoot) {
|
|
|
17908
17908
|
}
|
|
17909
17909
|
return checkDir(pythonRoot);
|
|
17910
17910
|
}
|
|
17911
|
-
function updatePythonBuildTimestamp(
|
|
17912
|
-
|
|
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());
|
|
17913
17913
|
}
|
|
17914
|
+
var CodegraphDbNotInitializedError;
|
|
17914
17915
|
var init_db = __esm({
|
|
17915
17916
|
"src/db.ts"() {
|
|
17916
17917
|
"use strict";
|
|
17917
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
|
+
};
|
|
17918
17927
|
}
|
|
17919
17928
|
});
|
|
17920
17929
|
|
|
@@ -18088,15 +18097,15 @@ function toRelative(absPath) {
|
|
|
18088
18097
|
}
|
|
18089
18098
|
return absPath;
|
|
18090
18099
|
}
|
|
18091
|
-
function buildImportIndex(
|
|
18092
|
-
const files =
|
|
18093
|
-
|
|
18094
|
-
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(
|
|
18095
18104
|
"INSERT INTO massu_imports (source_file, target_file, import_type, imported_names, line) VALUES (?, ?, ?, ?, ?)"
|
|
18096
18105
|
);
|
|
18097
18106
|
let edgeCount = 0;
|
|
18098
18107
|
const projectRoot = getProjectRoot();
|
|
18099
|
-
const insertMany =
|
|
18108
|
+
const insertMany = dataDb.transaction((edges) => {
|
|
18100
18109
|
for (const edge of edges) {
|
|
18101
18110
|
insertStmt.run(edge.source_file, edge.target_file, edge.import_type, edge.imported_names, edge.line);
|
|
18102
18111
|
}
|
|
@@ -18255,20 +18264,20 @@ function searchDirectory(dir, pattern, results) {
|
|
|
18255
18264
|
function escapeRegex2(str) {
|
|
18256
18265
|
return str.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
|
|
18257
18266
|
}
|
|
18258
|
-
function buildTrpcIndex(
|
|
18259
|
-
|
|
18260
|
-
|
|
18267
|
+
function buildTrpcIndex(dataDb) {
|
|
18268
|
+
dataDb.exec("DELETE FROM massu_trpc_call_sites");
|
|
18269
|
+
dataDb.exec("DELETE FROM massu_trpc_procedures");
|
|
18261
18270
|
const routerMappings = parseRootRouter();
|
|
18262
|
-
const insertProc =
|
|
18271
|
+
const insertProc = dataDb.prepare(
|
|
18263
18272
|
"INSERT INTO massu_trpc_procedures (router_file, router_name, procedure_name, procedure_type, has_ui_caller) VALUES (?, ?, ?, ?, ?)"
|
|
18264
18273
|
);
|
|
18265
|
-
const insertCallSite =
|
|
18274
|
+
const insertCallSite = dataDb.prepare(
|
|
18266
18275
|
"INSERT INTO massu_trpc_call_sites (procedure_id, file, line, call_pattern) VALUES (?, ?, ?, ?)"
|
|
18267
18276
|
);
|
|
18268
18277
|
let totalProcedures = 0;
|
|
18269
18278
|
let withCallers = 0;
|
|
18270
18279
|
let withoutCallers = 0;
|
|
18271
|
-
const insertAll =
|
|
18280
|
+
const insertAll = dataDb.transaction(() => {
|
|
18272
18281
|
for (const router of routerMappings) {
|
|
18273
18282
|
const procedures = extractProcedures(router.file);
|
|
18274
18283
|
for (const proc of procedures) {
|
|
@@ -18312,10 +18321,10 @@ function derivePortal(route) {
|
|
|
18312
18321
|
const parts = route.split("/").filter(Boolean);
|
|
18313
18322
|
return parts[0] ?? "default";
|
|
18314
18323
|
}
|
|
18315
|
-
function traceImports(startFile,
|
|
18324
|
+
function traceImports(startFile, dataDb, visited, components, hooks, maxDepth = 5) {
|
|
18316
18325
|
if (maxDepth <= 0 || visited.has(startFile)) return;
|
|
18317
18326
|
visited.add(startFile);
|
|
18318
|
-
const imports =
|
|
18327
|
+
const imports = dataDb.prepare(
|
|
18319
18328
|
"SELECT target_file, imported_names FROM massu_imports WHERE source_file = ?"
|
|
18320
18329
|
).all(startFile);
|
|
18321
18330
|
for (const imp of imports) {
|
|
@@ -18327,7 +18336,7 @@ function traceImports(startFile, dataDb2, visited, components, hooks, maxDepth =
|
|
|
18327
18336
|
hooks.add(target);
|
|
18328
18337
|
}
|
|
18329
18338
|
if (target.startsWith("src/")) {
|
|
18330
|
-
traceImports(target,
|
|
18339
|
+
traceImports(target, dataDb, visited, components, hooks, maxDepth - 1);
|
|
18331
18340
|
}
|
|
18332
18341
|
}
|
|
18333
18342
|
}
|
|
@@ -18349,10 +18358,10 @@ function findRouterCalls(files) {
|
|
|
18349
18358
|
}
|
|
18350
18359
|
return [...routers];
|
|
18351
18360
|
}
|
|
18352
|
-
function findTablesFromRouters(routerNames,
|
|
18361
|
+
function findTablesFromRouters(routerNames, dataDb) {
|
|
18353
18362
|
const tables = /* @__PURE__ */ new Set();
|
|
18354
18363
|
for (const routerName of routerNames) {
|
|
18355
|
-
const procs =
|
|
18364
|
+
const procs = dataDb.prepare(
|
|
18356
18365
|
"SELECT DISTINCT router_file FROM massu_trpc_procedures WHERE router_name = ?"
|
|
18357
18366
|
).all(routerName);
|
|
18358
18367
|
for (const proc of procs) {
|
|
@@ -18373,26 +18382,26 @@ function findTablesFromRouters(routerNames, dataDb2) {
|
|
|
18373
18382
|
}
|
|
18374
18383
|
return [...tables];
|
|
18375
18384
|
}
|
|
18376
|
-
function buildPageDeps(
|
|
18377
|
-
|
|
18378
|
-
const pages =
|
|
18385
|
+
function buildPageDeps(dataDb, codegraphDb) {
|
|
18386
|
+
dataDb.exec("DELETE FROM massu_page_deps");
|
|
18387
|
+
const pages = codegraphDb.prepare(
|
|
18379
18388
|
"SELECT path FROM files WHERE path LIKE 'src/app/%/page.tsx' OR path = 'src/app/page.tsx'"
|
|
18380
18389
|
).all();
|
|
18381
|
-
const insertStmt =
|
|
18390
|
+
const insertStmt = dataDb.prepare(
|
|
18382
18391
|
"INSERT INTO massu_page_deps (page_file, route, portal, components, hooks, routers, tables_touched) VALUES (?, ?, ?, ?, ?, ?, ?)"
|
|
18383
18392
|
);
|
|
18384
18393
|
let count = 0;
|
|
18385
|
-
const insertAll =
|
|
18394
|
+
const insertAll = dataDb.transaction(() => {
|
|
18386
18395
|
for (const page of pages) {
|
|
18387
18396
|
const route = deriveRoute(page.path);
|
|
18388
18397
|
const portal = derivePortal(route);
|
|
18389
18398
|
const visited = /* @__PURE__ */ new Set();
|
|
18390
18399
|
const components = /* @__PURE__ */ new Set();
|
|
18391
18400
|
const hooks = /* @__PURE__ */ new Set();
|
|
18392
|
-
traceImports(page.path,
|
|
18401
|
+
traceImports(page.path, dataDb, visited, components, hooks);
|
|
18393
18402
|
const allFiles = [...visited];
|
|
18394
18403
|
const routers = findRouterCalls(allFiles);
|
|
18395
|
-
const tables = findTablesFromRouters(routers,
|
|
18404
|
+
const tables = findTablesFromRouters(routers, dataDb);
|
|
18396
18405
|
insertStmt.run(
|
|
18397
18406
|
page.path,
|
|
18398
18407
|
route,
|
|
@@ -18408,8 +18417,8 @@ function buildPageDeps(dataDb2, codegraphDb2) {
|
|
|
18408
18417
|
insertAll();
|
|
18409
18418
|
return count;
|
|
18410
18419
|
}
|
|
18411
|
-
function getPageChain(
|
|
18412
|
-
const row =
|
|
18420
|
+
function getPageChain(dataDb, pageFile) {
|
|
18421
|
+
const row = dataDb.prepare("SELECT * FROM massu_page_deps WHERE page_file = ?").get(pageFile);
|
|
18413
18422
|
if (!row) return null;
|
|
18414
18423
|
return {
|
|
18415
18424
|
page: row.page_file,
|
|
@@ -18421,10 +18430,10 @@ function getPageChain(dataDb2, pageFile) {
|
|
|
18421
18430
|
tables: JSON.parse(row.tables_touched)
|
|
18422
18431
|
};
|
|
18423
18432
|
}
|
|
18424
|
-
function findAffectedPages(
|
|
18425
|
-
const directPage = getPageChain(
|
|
18433
|
+
function findAffectedPages(dataDb, file) {
|
|
18434
|
+
const directPage = getPageChain(dataDb, file);
|
|
18426
18435
|
if (directPage) return [directPage];
|
|
18427
|
-
const importers =
|
|
18436
|
+
const importers = dataDb.prepare(
|
|
18428
18437
|
"SELECT source_file FROM massu_imports WHERE target_file = ?"
|
|
18429
18438
|
).all(file);
|
|
18430
18439
|
const affectedFiles = /* @__PURE__ */ new Set([file, ...importers.map((i) => i.source_file)]);
|
|
@@ -18435,7 +18444,7 @@ function findAffectedPages(dataDb2, file) {
|
|
|
18435
18444
|
while (frontier.length > 0 && depth < maxDepth) {
|
|
18436
18445
|
const next = [];
|
|
18437
18446
|
for (const f2 of frontier) {
|
|
18438
|
-
const upstreamImporters =
|
|
18447
|
+
const upstreamImporters = dataDb.prepare(
|
|
18439
18448
|
"SELECT source_file FROM massu_imports WHERE target_file = ?"
|
|
18440
18449
|
).all(f2);
|
|
18441
18450
|
for (const imp of upstreamImporters) {
|
|
@@ -18449,7 +18458,7 @@ function findAffectedPages(dataDb2, file) {
|
|
|
18449
18458
|
frontier = next;
|
|
18450
18459
|
depth++;
|
|
18451
18460
|
}
|
|
18452
|
-
const allPages =
|
|
18461
|
+
const allPages = dataDb.prepare("SELECT * FROM massu_page_deps").all();
|
|
18453
18462
|
const results = [];
|
|
18454
18463
|
for (const row of allPages) {
|
|
18455
18464
|
if (affectedFiles.has(row.page_file)) {
|
|
@@ -18475,8 +18484,8 @@ var init_page_deps = __esm({
|
|
|
18475
18484
|
});
|
|
18476
18485
|
|
|
18477
18486
|
// src/middleware-tree.ts
|
|
18478
|
-
function buildMiddlewareTree(
|
|
18479
|
-
|
|
18487
|
+
function buildMiddlewareTree(dataDb) {
|
|
18488
|
+
dataDb.exec("DELETE FROM massu_middleware_tree");
|
|
18480
18489
|
const config = getConfig();
|
|
18481
18490
|
const middlewareFile = config.paths.middleware ?? "src/middleware.ts";
|
|
18482
18491
|
if (!middlewareFile) return 0;
|
|
@@ -18485,7 +18494,7 @@ function buildMiddlewareTree(dataDb2) {
|
|
|
18485
18494
|
visited.add(middlewareFile);
|
|
18486
18495
|
while (queue.length > 0) {
|
|
18487
18496
|
const current = queue.shift();
|
|
18488
|
-
const imports =
|
|
18497
|
+
const imports = dataDb.prepare(
|
|
18489
18498
|
"SELECT target_file FROM massu_imports WHERE source_file = ?"
|
|
18490
18499
|
).all(current);
|
|
18491
18500
|
for (const imp of imports) {
|
|
@@ -18495,8 +18504,8 @@ function buildMiddlewareTree(dataDb2) {
|
|
|
18495
18504
|
}
|
|
18496
18505
|
}
|
|
18497
18506
|
}
|
|
18498
|
-
const insertStmt =
|
|
18499
|
-
const insertAll =
|
|
18507
|
+
const insertStmt = dataDb.prepare("INSERT INTO massu_middleware_tree (file) VALUES (?)");
|
|
18508
|
+
const insertAll = dataDb.transaction(() => {
|
|
18500
18509
|
for (const file of visited) {
|
|
18501
18510
|
insertStmt.run(file);
|
|
18502
18511
|
}
|
|
@@ -18504,8 +18513,8 @@ function buildMiddlewareTree(dataDb2) {
|
|
|
18504
18513
|
insertAll();
|
|
18505
18514
|
return visited.size;
|
|
18506
18515
|
}
|
|
18507
|
-
function isInMiddlewareTree(
|
|
18508
|
-
const result =
|
|
18516
|
+
function isInMiddlewareTree(dataDb, file) {
|
|
18517
|
+
const result = dataDb.prepare("SELECT 1 FROM massu_middleware_tree WHERE file = ?").get(file);
|
|
18509
18518
|
return result !== void 0;
|
|
18510
18519
|
}
|
|
18511
18520
|
var init_middleware_tree = __esm({
|
|
@@ -18567,12 +18576,12 @@ function globMatchSimple(name, pattern) {
|
|
|
18567
18576
|
const regexStr = pattern.replace(/\./g, "\\.").replace(/\*/g, ".*").replace(/\?/g, ".");
|
|
18568
18577
|
return new RegExp(`^${regexStr}$`).test(name);
|
|
18569
18578
|
}
|
|
18570
|
-
function findCrossDomainImports(
|
|
18579
|
+
function findCrossDomainImports(dataDb) {
|
|
18571
18580
|
const domains = getDomains();
|
|
18572
18581
|
const config = getConfig();
|
|
18573
18582
|
const srcPrefix = config.paths.source;
|
|
18574
18583
|
const srcPattern = srcPrefix + "/%";
|
|
18575
|
-
const imports =
|
|
18584
|
+
const imports = dataDb.prepare(
|
|
18576
18585
|
"SELECT source_file, target_file FROM massu_imports WHERE source_file LIKE ? AND target_file LIKE ?"
|
|
18577
18586
|
).all(srcPattern, srcPattern);
|
|
18578
18587
|
const crossings = [];
|
|
@@ -18594,7 +18603,7 @@ function findCrossDomainImports(dataDb2) {
|
|
|
18594
18603
|
}
|
|
18595
18604
|
return crossings;
|
|
18596
18605
|
}
|
|
18597
|
-
function getFilesInDomain(
|
|
18606
|
+
function getFilesInDomain(dataDb, codegraphDb, domainName) {
|
|
18598
18607
|
const domains = getDomains();
|
|
18599
18608
|
const config = getConfig();
|
|
18600
18609
|
const domain = domains.find((d2) => d2.name === domainName);
|
|
@@ -18602,7 +18611,7 @@ function getFilesInDomain(dataDb2, codegraphDb2, domainName) {
|
|
|
18602
18611
|
const srcPrefix = config.paths.source;
|
|
18603
18612
|
const routersPath = config.paths.routers ?? "src/server/api/routers";
|
|
18604
18613
|
const srcPattern = srcPrefix + "/%";
|
|
18605
|
-
const allFiles =
|
|
18614
|
+
const allFiles = codegraphDb.prepare("SELECT path FROM files WHERE path LIKE ?").all(srcPattern);
|
|
18606
18615
|
const routers = [];
|
|
18607
18616
|
const pages = [];
|
|
18608
18617
|
const components = [];
|
|
@@ -18956,16 +18965,16 @@ function walkPythonFiles(dir, excludeDirs) {
|
|
|
18956
18965
|
}
|
|
18957
18966
|
return files;
|
|
18958
18967
|
}
|
|
18959
|
-
function buildPythonImportIndex(
|
|
18968
|
+
function buildPythonImportIndex(dataDb, pythonRoot, excludeDirs = ["__pycache__", ".venv", "venv", ".mypy_cache", ".pytest_cache"]) {
|
|
18960
18969
|
const projectRoot = getProjectRoot();
|
|
18961
18970
|
const absRoot = resolve24(projectRoot, pythonRoot);
|
|
18962
|
-
|
|
18963
|
-
const insertStmt =
|
|
18971
|
+
dataDb.exec("DELETE FROM massu_py_imports");
|
|
18972
|
+
const insertStmt = dataDb.prepare(
|
|
18964
18973
|
"INSERT INTO massu_py_imports (source_file, target_file, import_type, imported_names, line) VALUES (?, ?, ?, ?, ?)"
|
|
18965
18974
|
);
|
|
18966
18975
|
const files = walkPythonFiles(absRoot, excludeDirs);
|
|
18967
18976
|
let edgeCount = 0;
|
|
18968
|
-
const insertMany =
|
|
18977
|
+
const insertMany = dataDb.transaction((edges) => {
|
|
18969
18978
|
for (const edge of edges) {
|
|
18970
18979
|
insertStmt.run(edge.source, edge.target, edge.type, edge.names, edge.line);
|
|
18971
18980
|
}
|
|
@@ -19259,17 +19268,17 @@ function walkPyFiles(dir, excludeDirs) {
|
|
|
19259
19268
|
}
|
|
19260
19269
|
return files;
|
|
19261
19270
|
}
|
|
19262
|
-
function buildPythonRouteIndex(
|
|
19271
|
+
function buildPythonRouteIndex(dataDb, pythonRoot, excludeDirs = ["__pycache__", ".venv", "venv", ".mypy_cache", ".pytest_cache"]) {
|
|
19263
19272
|
const projectRoot = getProjectRoot();
|
|
19264
19273
|
const absRoot = join16(projectRoot, pythonRoot);
|
|
19265
|
-
|
|
19266
|
-
|
|
19267
|
-
const insertStmt =
|
|
19274
|
+
dataDb.exec("DELETE FROM massu_py_routes");
|
|
19275
|
+
dataDb.exec("DELETE FROM massu_py_route_callers");
|
|
19276
|
+
const insertStmt = dataDb.prepare(
|
|
19268
19277
|
"INSERT INTO massu_py_routes (file, method, path, function_name, dependencies, request_model, response_model, is_authenticated, line) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?)"
|
|
19269
19278
|
);
|
|
19270
19279
|
const files = walkPyFiles(absRoot, excludeDirs);
|
|
19271
19280
|
let count = 0;
|
|
19272
|
-
|
|
19281
|
+
dataDb.transaction(() => {
|
|
19273
19282
|
for (const absFile of files) {
|
|
19274
19283
|
const relFile = relative7(projectRoot, absFile);
|
|
19275
19284
|
let source;
|
|
@@ -19503,20 +19512,20 @@ function walkPyFiles2(dir, excludeDirs) {
|
|
|
19503
19512
|
}
|
|
19504
19513
|
return files;
|
|
19505
19514
|
}
|
|
19506
|
-
function buildPythonModelIndex(
|
|
19515
|
+
function buildPythonModelIndex(dataDb, pythonRoot, excludeDirs = ["__pycache__", ".venv", "venv", ".mypy_cache", ".pytest_cache"]) {
|
|
19507
19516
|
const projectRoot = getProjectRoot();
|
|
19508
19517
|
const absRoot = join17(projectRoot, pythonRoot);
|
|
19509
|
-
|
|
19510
|
-
|
|
19511
|
-
const insertModel =
|
|
19518
|
+
dataDb.exec("DELETE FROM massu_py_models");
|
|
19519
|
+
dataDb.exec("DELETE FROM massu_py_fk_edges");
|
|
19520
|
+
const insertModel = dataDb.prepare(
|
|
19512
19521
|
"INSERT INTO massu_py_models (class_name, table_name, file, line, columns, relationships, foreign_keys) VALUES (?, ?, ?, ?, ?, ?, ?)"
|
|
19513
19522
|
);
|
|
19514
|
-
const insertFk =
|
|
19523
|
+
const insertFk = dataDb.prepare(
|
|
19515
19524
|
"INSERT INTO massu_py_fk_edges (source_table, source_column, target_table, target_column) VALUES (?, ?, ?, ?)"
|
|
19516
19525
|
);
|
|
19517
19526
|
const files = walkPyFiles2(absRoot, excludeDirs);
|
|
19518
19527
|
let count = 0;
|
|
19519
|
-
|
|
19528
|
+
dataDb.transaction(() => {
|
|
19520
19529
|
for (const absFile of files) {
|
|
19521
19530
|
const relFile = relative8(projectRoot, absFile);
|
|
19522
19531
|
let source;
|
|
@@ -19783,10 +19792,10 @@ var init_migration_parser = __esm({
|
|
|
19783
19792
|
// src/python/migration-indexer.ts
|
|
19784
19793
|
import { readFileSync as readFileSync29, readdirSync as readdirSync20 } from "fs";
|
|
19785
19794
|
import { join as join18, relative as relative9 } from "path";
|
|
19786
|
-
function buildPythonMigrationIndex(
|
|
19795
|
+
function buildPythonMigrationIndex(dataDb, alembicDir) {
|
|
19787
19796
|
const projectRoot = getProjectRoot();
|
|
19788
19797
|
const absDir = join18(projectRoot, alembicDir);
|
|
19789
|
-
|
|
19798
|
+
dataDb.exec("DELETE FROM massu_py_migrations");
|
|
19790
19799
|
const versionsDir = join18(absDir, "versions");
|
|
19791
19800
|
let files = [];
|
|
19792
19801
|
try {
|
|
@@ -19797,7 +19806,7 @@ function buildPythonMigrationIndex(dataDb2, alembicDir) {
|
|
|
19797
19806
|
} catch {
|
|
19798
19807
|
}
|
|
19799
19808
|
}
|
|
19800
|
-
const insertStmt =
|
|
19809
|
+
const insertStmt = dataDb.prepare(
|
|
19801
19810
|
"INSERT INTO massu_py_migrations (revision, down_revision, file, description, operations, is_head) VALUES (?, ?, ?, ?, ?, ?)"
|
|
19802
19811
|
);
|
|
19803
19812
|
let count = 0;
|
|
@@ -19823,7 +19832,7 @@ function buildPythonMigrationIndex(dataDb2, alembicDir) {
|
|
|
19823
19832
|
operations: JSON.stringify(parsed.operations)
|
|
19824
19833
|
});
|
|
19825
19834
|
}
|
|
19826
|
-
|
|
19835
|
+
dataDb.transaction(() => {
|
|
19827
19836
|
for (const row of rows) {
|
|
19828
19837
|
const isHead = !hasDownRef.has(row.revision) ? 1 : 0;
|
|
19829
19838
|
insertStmt.run(row.revision, row.downRevision, row.file, row.description, row.operations, isHead);
|
|
@@ -19843,15 +19852,15 @@ var init_migration_indexer = __esm({
|
|
|
19843
19852
|
// src/python/coupling-detector.ts
|
|
19844
19853
|
import { readFileSync as readFileSync30, readdirSync as readdirSync21 } from "fs";
|
|
19845
19854
|
import { join as join19, relative as relative10 } from "path";
|
|
19846
|
-
function buildPythonCouplingIndex(
|
|
19855
|
+
function buildPythonCouplingIndex(dataDb) {
|
|
19847
19856
|
const projectRoot = getProjectRoot();
|
|
19848
19857
|
const config = getConfig();
|
|
19849
19858
|
const srcDir = join19(projectRoot, config.paths.source);
|
|
19850
|
-
const routes =
|
|
19859
|
+
const routes = dataDb.prepare("SELECT id, method, path FROM massu_py_routes").all();
|
|
19851
19860
|
if (routes.length === 0) return 0;
|
|
19852
|
-
|
|
19861
|
+
dataDb.exec("DELETE FROM massu_py_route_callers");
|
|
19853
19862
|
const frontendFiles = walkFrontendFiles(srcDir);
|
|
19854
|
-
const insertStmt =
|
|
19863
|
+
const insertStmt = dataDb.prepare(
|
|
19855
19864
|
"INSERT INTO massu_py_route_callers (route_id, frontend_file, line, call_pattern) VALUES (?, ?, ?, ?)"
|
|
19856
19865
|
);
|
|
19857
19866
|
let count = 0;
|
|
@@ -19873,7 +19882,7 @@ function buildPythonCouplingIndex(dataDb2) {
|
|
|
19873
19882
|
/\.patch\s*\(\s*[`'"](\/api\/[^`'"]*)[`'"]/g
|
|
19874
19883
|
// client.patch('/api/...')
|
|
19875
19884
|
];
|
|
19876
|
-
|
|
19885
|
+
dataDb.transaction(() => {
|
|
19877
19886
|
for (const absFile of frontendFiles) {
|
|
19878
19887
|
const relFile = relative10(projectRoot, absFile);
|
|
19879
19888
|
let source;
|
|
@@ -21389,22 +21398,22 @@ function getSentinelToolDefinitions() {
|
|
|
21389
21398
|
}
|
|
21390
21399
|
];
|
|
21391
21400
|
}
|
|
21392
|
-
function handleSentinelToolCall(name, args2,
|
|
21401
|
+
function handleSentinelToolCall(name, args2, dataDb) {
|
|
21393
21402
|
const prefix3 = getConfig().toolPrefix + "_";
|
|
21394
21403
|
const baseName = name.startsWith(prefix3) ? name.slice(prefix3.length) : name;
|
|
21395
21404
|
switch (baseName) {
|
|
21396
21405
|
case "sentinel_search":
|
|
21397
|
-
return handleSearch2(args2,
|
|
21406
|
+
return handleSearch2(args2, dataDb);
|
|
21398
21407
|
case "sentinel_detail":
|
|
21399
|
-
return handleDetail2(args2,
|
|
21408
|
+
return handleDetail2(args2, dataDb);
|
|
21400
21409
|
case "sentinel_impact":
|
|
21401
|
-
return handleImpact(args2,
|
|
21410
|
+
return handleImpact(args2, dataDb);
|
|
21402
21411
|
case "sentinel_validate":
|
|
21403
|
-
return handleValidate(args2,
|
|
21412
|
+
return handleValidate(args2, dataDb);
|
|
21404
21413
|
case "sentinel_register":
|
|
21405
|
-
return handleRegister(args2,
|
|
21414
|
+
return handleRegister(args2, dataDb);
|
|
21406
21415
|
case "sentinel_parity":
|
|
21407
|
-
return handleParityCheck(args2,
|
|
21416
|
+
return handleParityCheck(args2, dataDb);
|
|
21408
21417
|
default:
|
|
21409
21418
|
return text4(`Unknown sentinel tool: ${name}`);
|
|
21410
21419
|
}
|
|
@@ -21718,10 +21727,10 @@ function parseFeatureAnnotations(source) {
|
|
|
21718
21727
|
}
|
|
21719
21728
|
return annotations;
|
|
21720
21729
|
}
|
|
21721
|
-
function scanTrpcProcedures(
|
|
21730
|
+
function scanTrpcProcedures(dataDb) {
|
|
21722
21731
|
const features = [];
|
|
21723
21732
|
const featureMap = /* @__PURE__ */ new Map();
|
|
21724
|
-
const procedures =
|
|
21733
|
+
const procedures = dataDb.prepare(`
|
|
21725
21734
|
SELECT router_name, procedure_name, procedure_type, router_file
|
|
21726
21735
|
FROM massu_trpc_procedures
|
|
21727
21736
|
ORDER BY router_name, procedure_name
|
|
@@ -21761,9 +21770,9 @@ function scanTrpcProcedures(dataDb2) {
|
|
|
21761
21770
|
}
|
|
21762
21771
|
return Array.from(featureMap.values());
|
|
21763
21772
|
}
|
|
21764
|
-
function scanPageRoutes(
|
|
21773
|
+
function scanPageRoutes(dataDb) {
|
|
21765
21774
|
const features = [];
|
|
21766
|
-
const pages =
|
|
21775
|
+
const pages = dataDb.prepare(`
|
|
21767
21776
|
SELECT page_file, route, portal, components, hooks, routers
|
|
21768
21777
|
FROM massu_page_deps
|
|
21769
21778
|
ORDER BY route
|
|
@@ -21795,7 +21804,7 @@ function scanPageRoutes(dataDb2) {
|
|
|
21795
21804
|
}
|
|
21796
21805
|
return features;
|
|
21797
21806
|
}
|
|
21798
|
-
function scanComponentExports(
|
|
21807
|
+
function scanComponentExports(dataDb) {
|
|
21799
21808
|
const features = [];
|
|
21800
21809
|
const config = getConfig();
|
|
21801
21810
|
const projectRoot = getProjectRoot();
|
|
@@ -21885,10 +21894,10 @@ function walkDir2(dir) {
|
|
|
21885
21894
|
}
|
|
21886
21895
|
return results;
|
|
21887
21896
|
}
|
|
21888
|
-
function runFeatureScan(
|
|
21889
|
-
const procedureFeatures = scanTrpcProcedures(
|
|
21890
|
-
const pageFeatures = scanPageRoutes(
|
|
21891
|
-
const componentFeatures = scanComponentExports(
|
|
21897
|
+
function runFeatureScan(dataDb) {
|
|
21898
|
+
const procedureFeatures = scanTrpcProcedures(dataDb);
|
|
21899
|
+
const pageFeatures = scanPageRoutes(dataDb);
|
|
21900
|
+
const componentFeatures = scanComponentExports(dataDb);
|
|
21892
21901
|
const allFeatures = /* @__PURE__ */ new Map();
|
|
21893
21902
|
for (const f2 of procedureFeatures) {
|
|
21894
21903
|
allFeatures.set(f2.feature_key, f2);
|
|
@@ -21901,7 +21910,7 @@ function runFeatureScan(dataDb2) {
|
|
|
21901
21910
|
}
|
|
21902
21911
|
let registered = 0;
|
|
21903
21912
|
for (const feature of allFeatures.values()) {
|
|
21904
|
-
const featureId = upsertFeature(
|
|
21913
|
+
const featureId = upsertFeature(dataDb, {
|
|
21905
21914
|
feature_key: feature.feature_key,
|
|
21906
21915
|
domain: feature.domain,
|
|
21907
21916
|
subdomain: feature.subdomain,
|
|
@@ -21912,15 +21921,15 @@ function runFeatureScan(dataDb2) {
|
|
|
21912
21921
|
portal_scope: feature.portal_scope
|
|
21913
21922
|
});
|
|
21914
21923
|
for (const comp of feature.components) {
|
|
21915
|
-
linkComponent(
|
|
21924
|
+
linkComponent(dataDb, featureId, comp.file, comp.name, comp.role, comp.isPrimary);
|
|
21916
21925
|
}
|
|
21917
21926
|
for (const proc of feature.procedures) {
|
|
21918
|
-
linkProcedure(
|
|
21927
|
+
linkProcedure(dataDb, featureId, proc.router, proc.procedure, proc.type);
|
|
21919
21928
|
}
|
|
21920
21929
|
for (const page of feature.pages) {
|
|
21921
|
-
linkPage(
|
|
21930
|
+
linkPage(dataDb, featureId, page.route, page.portal ?? void 0);
|
|
21922
21931
|
}
|
|
21923
|
-
logChange(
|
|
21932
|
+
logChange(dataDb, featureId, "created", "Auto-discovered by sentinel scanner", void 0, "scanner");
|
|
21924
21933
|
registered++;
|
|
21925
21934
|
}
|
|
21926
21935
|
return {
|
|
@@ -25696,9 +25705,9 @@ function handleGaps(db, args2) {
|
|
|
25696
25705
|
lines.push(`## Knowledge Gap Analysis (${checkType})`);
|
|
25697
25706
|
lines.push("");
|
|
25698
25707
|
if (checkType === "features") {
|
|
25699
|
-
let
|
|
25708
|
+
let dataDb = null;
|
|
25700
25709
|
try {
|
|
25701
|
-
|
|
25710
|
+
dataDb = getDataDb();
|
|
25702
25711
|
let sql = "SELECT feature_key, title, domain, status FROM massu_sentinel WHERE status = 'active'";
|
|
25703
25712
|
const params = [];
|
|
25704
25713
|
if (domain) {
|
|
@@ -25706,7 +25715,7 @@ function handleGaps(db, args2) {
|
|
|
25706
25715
|
params.push(`%${domain}%`);
|
|
25707
25716
|
}
|
|
25708
25717
|
sql += " ORDER BY domain, feature_key";
|
|
25709
|
-
const features =
|
|
25718
|
+
const features = dataDb.prepare(sql).all(...params);
|
|
25710
25719
|
lines.push(`| Feature | Domain | Knowledge Hits | Status |`);
|
|
25711
25720
|
lines.push(`|---------|--------|----------------|--------|`);
|
|
25712
25721
|
let gapCount = 0;
|
|
@@ -25735,7 +25744,7 @@ function handleGaps(db, args2) {
|
|
|
25735
25744
|
} catch (error) {
|
|
25736
25745
|
lines.push(`Error querying sentinel: ${error instanceof Error ? error.message : String(error)}`);
|
|
25737
25746
|
} finally {
|
|
25738
|
-
|
|
25747
|
+
dataDb?.close();
|
|
25739
25748
|
}
|
|
25740
25749
|
} else if (checkType === "routers") {
|
|
25741
25750
|
try {
|
|
@@ -25762,10 +25771,10 @@ function handleGaps(db, args2) {
|
|
|
25762
25771
|
lines.push("### Pattern Coverage");
|
|
25763
25772
|
lines.push(`Documented domains: ${[...documentedDomains].join(", ")}`);
|
|
25764
25773
|
lines.push("");
|
|
25765
|
-
let
|
|
25774
|
+
let dataDb = null;
|
|
25766
25775
|
try {
|
|
25767
|
-
|
|
25768
|
-
const domains =
|
|
25776
|
+
dataDb = getDataDb();
|
|
25777
|
+
const domains = dataDb.prepare(
|
|
25769
25778
|
"SELECT DISTINCT domain FROM massu_sentinel WHERE status = 'active' ORDER BY domain"
|
|
25770
25779
|
).all();
|
|
25771
25780
|
for (const d2 of domains) {
|
|
@@ -25774,7 +25783,7 @@ function handleGaps(db, args2) {
|
|
|
25774
25783
|
}
|
|
25775
25784
|
} catch {
|
|
25776
25785
|
} finally {
|
|
25777
|
-
|
|
25786
|
+
dataDb?.close();
|
|
25778
25787
|
}
|
|
25779
25788
|
} else if (checkType === "incidents") {
|
|
25780
25789
|
const incidents = db.prepare(
|
|
@@ -26217,30 +26226,30 @@ function isPythonTool(name) {
|
|
|
26217
26226
|
const base = stripPrefix2(name);
|
|
26218
26227
|
return base.startsWith("py_");
|
|
26219
26228
|
}
|
|
26220
|
-
function handlePythonToolCall(name, args2,
|
|
26229
|
+
function handlePythonToolCall(name, args2, dataDb) {
|
|
26221
26230
|
const baseName = stripPrefix2(name);
|
|
26222
26231
|
switch (baseName) {
|
|
26223
26232
|
case "py_imports":
|
|
26224
|
-
return handlePyImports(args2,
|
|
26233
|
+
return handlePyImports(args2, dataDb);
|
|
26225
26234
|
case "py_routes":
|
|
26226
|
-
return handlePyRoutes(args2,
|
|
26235
|
+
return handlePyRoutes(args2, dataDb);
|
|
26227
26236
|
case "py_coupling":
|
|
26228
|
-
return handlePyCoupling(args2,
|
|
26237
|
+
return handlePyCoupling(args2, dataDb);
|
|
26229
26238
|
case "py_models":
|
|
26230
|
-
return handlePyModels(args2,
|
|
26239
|
+
return handlePyModels(args2, dataDb);
|
|
26231
26240
|
case "py_migrations":
|
|
26232
|
-
return handlePyMigrations(args2,
|
|
26241
|
+
return handlePyMigrations(args2, dataDb);
|
|
26233
26242
|
case "py_domains":
|
|
26234
|
-
return handlePyDomains(args2,
|
|
26243
|
+
return handlePyDomains(args2, dataDb);
|
|
26235
26244
|
case "py_impact":
|
|
26236
|
-
return handlePyImpact(args2,
|
|
26245
|
+
return handlePyImpact(args2, dataDb);
|
|
26237
26246
|
case "py_context":
|
|
26238
|
-
return handlePyContext(args2,
|
|
26247
|
+
return handlePyContext(args2, dataDb);
|
|
26239
26248
|
default:
|
|
26240
26249
|
return text16(`Unknown Python tool: ${name}`);
|
|
26241
26250
|
}
|
|
26242
26251
|
}
|
|
26243
|
-
function handlePyImports(args2,
|
|
26252
|
+
function handlePyImports(args2, dataDb) {
|
|
26244
26253
|
const lines = [];
|
|
26245
26254
|
const file = args2.file;
|
|
26246
26255
|
const importedBy = args2.imported_by;
|
|
@@ -26251,7 +26260,7 @@ function handlePyImports(args2, dataDb2) {
|
|
|
26251
26260
|
let traverse2 = function(f2, depth) {
|
|
26252
26261
|
if (depth > maxDepth || visited.has(f2)) return;
|
|
26253
26262
|
visited.add(f2);
|
|
26254
|
-
const imports =
|
|
26263
|
+
const imports = dataDb.prepare(
|
|
26255
26264
|
"SELECT target_file, imported_names FROM massu_py_imports WHERE source_file = ?"
|
|
26256
26265
|
).all(f2);
|
|
26257
26266
|
for (const imp of imports) {
|
|
@@ -26266,7 +26275,7 @@ function handlePyImports(args2, dataDb2) {
|
|
|
26266
26275
|
const visited = /* @__PURE__ */ new Set();
|
|
26267
26276
|
traverse2(file, 0);
|
|
26268
26277
|
} else {
|
|
26269
|
-
const imports =
|
|
26278
|
+
const imports = dataDb.prepare(
|
|
26270
26279
|
"SELECT target_file, import_type, imported_names, line FROM massu_py_imports WHERE source_file = ? ORDER BY line"
|
|
26271
26280
|
).all(file);
|
|
26272
26281
|
lines.push(`## Imports from ${file} (${imports.length} edges)`);
|
|
@@ -26276,7 +26285,7 @@ function handlePyImports(args2, dataDb2) {
|
|
|
26276
26285
|
}
|
|
26277
26286
|
}
|
|
26278
26287
|
} else if (importedBy) {
|
|
26279
|
-
const importers =
|
|
26288
|
+
const importers = dataDb.prepare(
|
|
26280
26289
|
"SELECT source_file, imported_names, line FROM massu_py_imports WHERE target_file = ? ORDER BY source_file"
|
|
26281
26290
|
).all(importedBy);
|
|
26282
26291
|
lines.push(`## Files importing ${importedBy} (${importers.length} edges)`);
|
|
@@ -26285,8 +26294,8 @@ function handlePyImports(args2, dataDb2) {
|
|
|
26285
26294
|
lines.push(`- ${imp.source_file}:${imp.line}${names.length > 0 ? " (" + names.join(", ") + ")" : ""}`);
|
|
26286
26295
|
}
|
|
26287
26296
|
} else {
|
|
26288
|
-
const total =
|
|
26289
|
-
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;
|
|
26290
26299
|
lines.push("## Python Import Index Summary");
|
|
26291
26300
|
lines.push(`- Total import edges: ${total}`);
|
|
26292
26301
|
lines.push(`- Files with imports: ${files}`);
|
|
@@ -26296,7 +26305,7 @@ function handlePyImports(args2, dataDb2) {
|
|
|
26296
26305
|
}
|
|
26297
26306
|
return text16(lines.join("\n") || "No Python import data available. Run sync first.");
|
|
26298
26307
|
}
|
|
26299
|
-
function handlePyRoutes(args2,
|
|
26308
|
+
function handlePyRoutes(args2, dataDb) {
|
|
26300
26309
|
const lines = [];
|
|
26301
26310
|
const limit = Math.min(Math.max(args2.limit || 500, 1), 5e3);
|
|
26302
26311
|
let query = "SELECT * FROM massu_py_routes WHERE 1=1";
|
|
@@ -26317,9 +26326,9 @@ function handlePyRoutes(args2, dataDb2) {
|
|
|
26317
26326
|
query += " AND is_authenticated = 0";
|
|
26318
26327
|
}
|
|
26319
26328
|
query += ` ORDER BY file, line LIMIT ${limit}`;
|
|
26320
|
-
const routes =
|
|
26329
|
+
const routes = dataDb.prepare(query).all(...params);
|
|
26321
26330
|
if (args2.uncoupled) {
|
|
26322
|
-
const callerCountStmt =
|
|
26331
|
+
const callerCountStmt = dataDb.prepare("SELECT COUNT(*) as cnt FROM massu_py_route_callers WHERE route_id = ?");
|
|
26323
26332
|
const uncoupledRoutes = routes.filter((r2) => {
|
|
26324
26333
|
const callers = callerCountStmt.get(r2.id).cnt;
|
|
26325
26334
|
return callers === 0;
|
|
@@ -26340,7 +26349,7 @@ function handlePyRoutes(args2, dataDb2) {
|
|
|
26340
26349
|
}
|
|
26341
26350
|
return text16(lines.join("\n") || "No Python routes found.");
|
|
26342
26351
|
}
|
|
26343
|
-
function handlePyCoupling(args2,
|
|
26352
|
+
function handlePyCoupling(args2, dataDb) {
|
|
26344
26353
|
const lines = [];
|
|
26345
26354
|
let query = `
|
|
26346
26355
|
SELECT rc.frontend_file, rc.call_pattern, rc.line as caller_line,
|
|
@@ -26359,7 +26368,7 @@ function handlePyCoupling(args2, dataDb2) {
|
|
|
26359
26368
|
params.push(`%${args2.backend_path}%`);
|
|
26360
26369
|
}
|
|
26361
26370
|
query += " ORDER BY rc.frontend_file, rc.line";
|
|
26362
|
-
const couplings =
|
|
26371
|
+
const couplings = dataDb.prepare(query).all(...params);
|
|
26363
26372
|
lines.push(`## Frontend \u2194 Backend Coupling (${couplings.length} connections)`);
|
|
26364
26373
|
let currentFrontend = "";
|
|
26365
26374
|
for (const c2 of couplings) {
|
|
@@ -26372,17 +26381,17 @@ function handlePyCoupling(args2, dataDb2) {
|
|
|
26372
26381
|
}
|
|
26373
26382
|
return text16(lines.join("\n") || "No coupling data found.");
|
|
26374
26383
|
}
|
|
26375
|
-
function handlePyModels(args2,
|
|
26384
|
+
function handlePyModels(args2, dataDb) {
|
|
26376
26385
|
const lines = [];
|
|
26377
26386
|
if (args2.fk_graph) {
|
|
26378
|
-
const edges =
|
|
26387
|
+
const edges = dataDb.prepare("SELECT * FROM massu_py_fk_edges ORDER BY source_table").all();
|
|
26379
26388
|
lines.push(`## Foreign Key Graph (${edges.length} edges)`);
|
|
26380
26389
|
for (const e2 of edges) {
|
|
26381
26390
|
lines.push(`- ${e2.source_table}.${e2.source_column} \u2192 ${e2.target_table}.${e2.target_column}`);
|
|
26382
26391
|
}
|
|
26383
26392
|
} else if (args2.model || args2.table) {
|
|
26384
26393
|
const search = args2.model || args2.table;
|
|
26385
|
-
const model =
|
|
26394
|
+
const model = dataDb.prepare(
|
|
26386
26395
|
"SELECT * FROM massu_py_models WHERE class_name = ? OR table_name = ?"
|
|
26387
26396
|
).get(search, search);
|
|
26388
26397
|
if (!model) return text16(`Model "${search}" not found.`);
|
|
@@ -26411,7 +26420,7 @@ function handlePyModels(args2, dataDb2) {
|
|
|
26411
26420
|
}
|
|
26412
26421
|
} else {
|
|
26413
26422
|
const limit = Math.min(Math.max(args2.limit || 500, 1), 5e3);
|
|
26414
|
-
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();
|
|
26415
26424
|
lines.push(`## Python Models (${models.length})`);
|
|
26416
26425
|
for (const m3 of models) {
|
|
26417
26426
|
lines.push(`- ${m3.class_name} (${m3.table_name || "no table"}) \u2014 ${m3.file}:${m3.line}`);
|
|
@@ -26419,11 +26428,11 @@ function handlePyModels(args2, dataDb2) {
|
|
|
26419
26428
|
}
|
|
26420
26429
|
return text16(lines.join("\n") || "No Python models found.");
|
|
26421
26430
|
}
|
|
26422
|
-
function handlePyMigrations(args2,
|
|
26431
|
+
function handlePyMigrations(args2, dataDb) {
|
|
26423
26432
|
const lines = [];
|
|
26424
26433
|
if (args2.drift) {
|
|
26425
|
-
const models =
|
|
26426
|
-
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();
|
|
26427
26436
|
const migratedTables = /* @__PURE__ */ new Set();
|
|
26428
26437
|
for (const m3 of migrations) {
|
|
26429
26438
|
const ops = safeParseArray(m3.operations);
|
|
@@ -26444,14 +26453,14 @@ function handlePyMigrations(args2, dataDb2) {
|
|
|
26444
26453
|
}
|
|
26445
26454
|
} else if (args2.chain) {
|
|
26446
26455
|
const limit = Math.min(Math.max(args2.limit || 500, 1), 5e3);
|
|
26447
|
-
const migrations =
|
|
26456
|
+
const migrations = dataDb.prepare(`SELECT * FROM massu_py_migrations ORDER BY id LIMIT ${limit}`).all();
|
|
26448
26457
|
lines.push(`## Migration Chain (${migrations.length} revisions)`);
|
|
26449
26458
|
for (const m3 of migrations) {
|
|
26450
26459
|
const head = m3.is_head ? " [HEAD]" : "";
|
|
26451
26460
|
lines.push(`- ${m3.revision}${head} \u2190 ${m3.down_revision || "BASE"}: ${m3.description || "(no description)"} (${m3.file})`);
|
|
26452
26461
|
}
|
|
26453
26462
|
} else if (args2.revision) {
|
|
26454
|
-
const m3 =
|
|
26463
|
+
const m3 = dataDb.prepare("SELECT * FROM massu_py_migrations WHERE revision = ?").get(args2.revision);
|
|
26455
26464
|
if (!m3) return text16(`Revision "${args2.revision}" not found.`);
|
|
26456
26465
|
lines.push(`## Revision: ${m3.revision}`);
|
|
26457
26466
|
lines.push(`Down: ${m3.down_revision || "BASE"}`);
|
|
@@ -26465,15 +26474,15 @@ function handlePyMigrations(args2, dataDb2) {
|
|
|
26465
26474
|
}
|
|
26466
26475
|
}
|
|
26467
26476
|
} else {
|
|
26468
|
-
const total =
|
|
26469
|
-
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();
|
|
26470
26479
|
lines.push("## Migration Summary");
|
|
26471
26480
|
lines.push(`- Total revisions: ${total}`);
|
|
26472
26481
|
lines.push(`- Current head: ${head?.revision || "N/A"}`);
|
|
26473
26482
|
}
|
|
26474
26483
|
return text16(lines.join("\n") || "No Python migration data found.");
|
|
26475
26484
|
}
|
|
26476
|
-
function handlePyDomains(args2,
|
|
26485
|
+
function handlePyDomains(args2, dataDb) {
|
|
26477
26486
|
const lines = [];
|
|
26478
26487
|
const config = getConfig();
|
|
26479
26488
|
const domains = config.python?.domains || [];
|
|
@@ -26487,7 +26496,7 @@ function handlePyDomains(args2, dataDb2) {
|
|
|
26487
26496
|
lines.push(`Allowed imports from: ${domainConfig.allowed_imports_from.join(", ") || "any"}`);
|
|
26488
26497
|
}
|
|
26489
26498
|
} else if (args2.crossings) {
|
|
26490
|
-
const imports =
|
|
26499
|
+
const imports = dataDb.prepare("SELECT source_file, target_file FROM massu_py_imports").all();
|
|
26491
26500
|
const violations = [];
|
|
26492
26501
|
for (const imp of imports) {
|
|
26493
26502
|
const srcDomain = classifyPythonFileDomain(imp.source_file);
|
|
@@ -26506,7 +26515,7 @@ function handlePyDomains(args2, dataDb2) {
|
|
|
26506
26515
|
if (violations.length > 50) lines.push(`... and ${violations.length - 50} more`);
|
|
26507
26516
|
} else if (args2.domain) {
|
|
26508
26517
|
const domainName = args2.domain;
|
|
26509
|
-
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();
|
|
26510
26519
|
const filesInDomain = allFiles.filter((f2) => classifyPythonFileDomain(f2.source_file) === domainName);
|
|
26511
26520
|
lines.push(`## Domain: ${domainName} (${filesInDomain.length} files)`);
|
|
26512
26521
|
for (const f2 of filesInDomain) {
|
|
@@ -26520,17 +26529,17 @@ function handlePyDomains(args2, dataDb2) {
|
|
|
26520
26529
|
}
|
|
26521
26530
|
return text16(lines.join("\n") || "No Python domains configured.");
|
|
26522
26531
|
}
|
|
26523
|
-
function handlePyImpact(args2,
|
|
26532
|
+
function handlePyImpact(args2, dataDb) {
|
|
26524
26533
|
const file = args2.file;
|
|
26525
26534
|
const lines = [`## Impact Analysis: ${file}`, ""];
|
|
26526
|
-
const importedBy =
|
|
26535
|
+
const importedBy = dataDb.prepare(
|
|
26527
26536
|
"SELECT source_file FROM massu_py_imports WHERE target_file = ?"
|
|
26528
26537
|
).all(file);
|
|
26529
26538
|
lines.push(`### Imported By (${importedBy.length} files)`);
|
|
26530
26539
|
for (const imp of importedBy.slice(0, 20)) {
|
|
26531
26540
|
lines.push(`- ${imp.source_file}`);
|
|
26532
26541
|
}
|
|
26533
|
-
const routes =
|
|
26542
|
+
const routes = dataDb.prepare(
|
|
26534
26543
|
"SELECT method, path, function_name FROM massu_py_routes WHERE file = ?"
|
|
26535
26544
|
).all(file);
|
|
26536
26545
|
if (routes.length > 0) {
|
|
@@ -26540,7 +26549,7 @@ function handlePyImpact(args2, dataDb2) {
|
|
|
26540
26549
|
lines.push(`- ${r2.method} ${r2.path} \u2192 ${r2.function_name}`);
|
|
26541
26550
|
}
|
|
26542
26551
|
}
|
|
26543
|
-
const models =
|
|
26552
|
+
const models = dataDb.prepare(
|
|
26544
26553
|
"SELECT class_name, table_name FROM massu_py_models WHERE file = ?"
|
|
26545
26554
|
).all(file);
|
|
26546
26555
|
if (models.length > 0) {
|
|
@@ -26550,10 +26559,10 @@ function handlePyImpact(args2, dataDb2) {
|
|
|
26550
26559
|
lines.push(`- ${m3.class_name} (${m3.table_name || "no table"})`);
|
|
26551
26560
|
}
|
|
26552
26561
|
}
|
|
26553
|
-
const routeIds =
|
|
26562
|
+
const routeIds = dataDb.prepare("SELECT id FROM massu_py_routes WHERE file = ?").all(file);
|
|
26554
26563
|
if (routeIds.length > 0) {
|
|
26555
26564
|
const placeholders = routeIds.map(() => "?").join(",");
|
|
26556
|
-
const callers =
|
|
26565
|
+
const callers = dataDb.prepare(
|
|
26557
26566
|
`SELECT DISTINCT frontend_file FROM massu_py_route_callers WHERE route_id IN (${placeholders})`
|
|
26558
26567
|
).all(...routeIds.map((r2) => r2.id));
|
|
26559
26568
|
if (callers.length > 0) {
|
|
@@ -26570,13 +26579,13 @@ function handlePyImpact(args2, dataDb2) {
|
|
|
26570
26579
|
### Domain: ${domain}`);
|
|
26571
26580
|
return text16(lines.join("\n"));
|
|
26572
26581
|
}
|
|
26573
|
-
function handlePyContext(args2,
|
|
26582
|
+
function handlePyContext(args2, dataDb) {
|
|
26574
26583
|
const file = args2.file;
|
|
26575
26584
|
const lines = [`## Python Context: ${file}`, ""];
|
|
26576
26585
|
const config = getConfig();
|
|
26577
26586
|
const domain = classifyPythonFileDomain(file);
|
|
26578
26587
|
lines.push(`**Domain**: ${domain}`);
|
|
26579
|
-
const imports =
|
|
26588
|
+
const imports = dataDb.prepare(
|
|
26580
26589
|
"SELECT target_file, imported_names FROM massu_py_imports WHERE source_file = ? LIMIT 20"
|
|
26581
26590
|
).all(file);
|
|
26582
26591
|
if (imports.length > 0) {
|
|
@@ -26586,7 +26595,7 @@ function handlePyContext(args2, dataDb2) {
|
|
|
26586
26595
|
lines.push(`- ${imp.target_file}${names.length > 0 ? ": " + names.join(", ") : ""}`);
|
|
26587
26596
|
}
|
|
26588
26597
|
}
|
|
26589
|
-
const importedBy =
|
|
26598
|
+
const importedBy = dataDb.prepare(
|
|
26590
26599
|
"SELECT source_file FROM massu_py_imports WHERE target_file = ? LIMIT 10"
|
|
26591
26600
|
).all(file);
|
|
26592
26601
|
if (importedBy.length > 0) {
|
|
@@ -26595,14 +26604,14 @@ function handlePyContext(args2, dataDb2) {
|
|
|
26595
26604
|
lines.push(`- ${imp.source_file}`);
|
|
26596
26605
|
}
|
|
26597
26606
|
}
|
|
26598
|
-
const routes =
|
|
26607
|
+
const routes = dataDb.prepare("SELECT method, path, function_name, line FROM massu_py_routes WHERE file = ?").all(file);
|
|
26599
26608
|
if (routes.length > 0) {
|
|
26600
26609
|
lines.push("\n### Routes");
|
|
26601
26610
|
for (const r2 of routes) {
|
|
26602
26611
|
lines.push(`- ${r2.method} ${r2.path} \u2192 ${r2.function_name} (L${r2.line})`);
|
|
26603
26612
|
}
|
|
26604
26613
|
}
|
|
26605
|
-
const models =
|
|
26614
|
+
const models = dataDb.prepare("SELECT class_name, table_name, line FROM massu_py_models WHERE file = ?").all(file);
|
|
26606
26615
|
if (models.length > 0) {
|
|
26607
26616
|
lines.push("\n### Models");
|
|
26608
26617
|
for (const m3 of models) {
|
|
@@ -26650,41 +26659,41 @@ function stripPrefix3(name) {
|
|
|
26650
26659
|
}
|
|
26651
26660
|
return name;
|
|
26652
26661
|
}
|
|
26653
|
-
function ensureIndexes(
|
|
26662
|
+
function ensureIndexes(dataDb, codegraphDb, force = false) {
|
|
26654
26663
|
const results = [];
|
|
26655
26664
|
const config = getConfig();
|
|
26656
|
-
if (force || isDataStale(
|
|
26657
|
-
const importCount = buildImportIndex(
|
|
26665
|
+
if (codegraphDb !== void 0 && (force || isDataStale(dataDb, codegraphDb))) {
|
|
26666
|
+
const importCount = buildImportIndex(dataDb, codegraphDb);
|
|
26658
26667
|
results.push(`Import edges: ${importCount}`);
|
|
26659
26668
|
if (config.framework.router === "trpc") {
|
|
26660
|
-
const trpcStats = buildTrpcIndex(
|
|
26669
|
+
const trpcStats = buildTrpcIndex(dataDb);
|
|
26661
26670
|
results.push(`tRPC procedures: ${trpcStats.totalProcedures} (${trpcStats.withCallers} with UI, ${trpcStats.withoutCallers} without)`);
|
|
26662
26671
|
}
|
|
26663
|
-
const pageCount = buildPageDeps(
|
|
26672
|
+
const pageCount = buildPageDeps(dataDb, codegraphDb);
|
|
26664
26673
|
results.push(`Page deps: ${pageCount} pages`);
|
|
26665
26674
|
if (config.paths.middleware) {
|
|
26666
|
-
const middlewareCount = buildMiddlewareTree(
|
|
26675
|
+
const middlewareCount = buildMiddlewareTree(dataDb);
|
|
26667
26676
|
results.push(`Middleware tree: ${middlewareCount} files`);
|
|
26668
26677
|
}
|
|
26669
|
-
updateBuildTimestamp(
|
|
26678
|
+
updateBuildTimestamp(dataDb);
|
|
26670
26679
|
}
|
|
26671
26680
|
if (config.python?.root) {
|
|
26672
26681
|
const pythonRoot = config.python.root;
|
|
26673
26682
|
const excludeDirs = config.python.exclude_dirs || ["__pycache__", ".venv", "venv", ".mypy_cache", ".pytest_cache"];
|
|
26674
|
-
if (force || isPythonDataStale(
|
|
26675
|
-
const pyImports = buildPythonImportIndex(
|
|
26683
|
+
if (force || isPythonDataStale(dataDb, resolve31(getProjectRoot(), pythonRoot))) {
|
|
26684
|
+
const pyImports = buildPythonImportIndex(dataDb, pythonRoot, excludeDirs);
|
|
26676
26685
|
results.push(`Python imports: ${pyImports}`);
|
|
26677
|
-
const pyRoutes = buildPythonRouteIndex(
|
|
26686
|
+
const pyRoutes = buildPythonRouteIndex(dataDb, pythonRoot, excludeDirs);
|
|
26678
26687
|
results.push(`Python routes: ${pyRoutes}`);
|
|
26679
|
-
const pyModels = buildPythonModelIndex(
|
|
26688
|
+
const pyModels = buildPythonModelIndex(dataDb, pythonRoot, excludeDirs);
|
|
26680
26689
|
results.push(`Python models: ${pyModels}`);
|
|
26681
26690
|
if (config.python.alembic_dir) {
|
|
26682
|
-
const pyMigrations = buildPythonMigrationIndex(
|
|
26691
|
+
const pyMigrations = buildPythonMigrationIndex(dataDb, config.python.alembic_dir);
|
|
26683
26692
|
results.push(`Python migrations: ${pyMigrations}`);
|
|
26684
26693
|
}
|
|
26685
|
-
const pyCoupling = buildPythonCouplingIndex(
|
|
26694
|
+
const pyCoupling = buildPythonCouplingIndex(dataDb);
|
|
26686
26695
|
results.push(`Python coupling: ${pyCoupling}`);
|
|
26687
|
-
updatePythonBuildTimestamp(
|
|
26696
|
+
updatePythonBuildTimestamp(dataDb);
|
|
26688
26697
|
}
|
|
26689
26698
|
}
|
|
26690
26699
|
if (results.length === 0) return "Indexes are up-to-date.";
|
|
@@ -26812,13 +26821,24 @@ function getToolDefinitions() {
|
|
|
26812
26821
|
}] : []
|
|
26813
26822
|
]);
|
|
26814
26823
|
}
|
|
26815
|
-
|
|
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) {
|
|
26816
26837
|
const userTier = await getCurrentTier();
|
|
26817
26838
|
const requiredTier = getToolTier(name);
|
|
26818
26839
|
if (!isToolAllowed(name, userTier)) {
|
|
26819
26840
|
return text17(`This tool requires ${requiredTier} tier. Current tier: ${userTier}. Upgrade at https://massu.ai/pricing`);
|
|
26820
26841
|
}
|
|
26821
|
-
const syncMessage = ensureIndexes(dataDb2, codegraphDb2);
|
|
26822
26842
|
const pfx = prefix2();
|
|
26823
26843
|
try {
|
|
26824
26844
|
if (name.startsWith(pfx + "_memory_")) {
|
|
@@ -26841,7 +26861,7 @@ async function handleToolCall(name, args2, dataDb2, codegraphDb2) {
|
|
|
26841
26861
|
return handleDocsToolCall(name, args2);
|
|
26842
26862
|
}
|
|
26843
26863
|
if (name.startsWith(pfx + "_sentinel_")) {
|
|
26844
|
-
return handleSentinelToolCall(name, args2,
|
|
26864
|
+
return handleSentinelToolCall(name, args2, assertDataDb(dataDb, name));
|
|
26845
26865
|
}
|
|
26846
26866
|
if (isAnalyticsTool(name)) {
|
|
26847
26867
|
const memDb = getMemoryDb();
|
|
@@ -26932,7 +26952,9 @@ async function handleToolCall(name, args2, dataDb2, codegraphDb2) {
|
|
|
26932
26952
|
}
|
|
26933
26953
|
}
|
|
26934
26954
|
if (isPythonTool(name)) {
|
|
26935
|
-
|
|
26955
|
+
const pyDataDb = assertDataDb(dataDb, name);
|
|
26956
|
+
ensureIndexes(pyDataDb);
|
|
26957
|
+
return handlePythonToolCall(name, args2, pyDataDb);
|
|
26936
26958
|
}
|
|
26937
26959
|
if (isLicenseTool(name)) {
|
|
26938
26960
|
const memDb = getMemoryDb();
|
|
@@ -26944,18 +26966,40 @@ async function handleToolCall(name, args2, dataDb2, codegraphDb2) {
|
|
|
26944
26966
|
}
|
|
26945
26967
|
const baseName = stripPrefix3(name);
|
|
26946
26968
|
switch (baseName) {
|
|
26947
|
-
case "sync":
|
|
26948
|
-
|
|
26949
|
-
|
|
26950
|
-
return
|
|
26951
|
-
|
|
26952
|
-
|
|
26953
|
-
|
|
26954
|
-
|
|
26955
|
-
|
|
26956
|
-
return
|
|
26957
|
-
|
|
26958
|
-
|
|
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
|
+
}
|
|
26959
27003
|
case "schema":
|
|
26960
27004
|
return handleSchema(args2);
|
|
26961
27005
|
default:
|
|
@@ -26970,10 +27014,10 @@ async function handleToolCall(name, args2, dataDb2, codegraphDb2) {
|
|
|
26970
27014
|
function text17(content) {
|
|
26971
27015
|
return { content: [{ type: "text", text: content }] };
|
|
26972
27016
|
}
|
|
26973
|
-
function handleSync(
|
|
26974
|
-
const result = ensureIndexes(
|
|
27017
|
+
function handleSync(dataDb, codegraphDb) {
|
|
27018
|
+
const result = ensureIndexes(dataDb, codegraphDb, true);
|
|
26975
27019
|
try {
|
|
26976
|
-
const scanResult = runFeatureScan(
|
|
27020
|
+
const scanResult = runFeatureScan(dataDb);
|
|
26977
27021
|
return text17(`${result}
|
|
26978
27022
|
|
|
26979
27023
|
Feature scan: ${scanResult.registered} features registered (${scanResult.fromProcedures} from procedures, ${scanResult.fromPages} from pages, ${scanResult.fromComponents} from components)`);
|
|
@@ -26983,9 +27027,9 @@ Feature scan: ${scanResult.registered} features registered (${scanResult.fromPro
|
|
|
26983
27027
|
Feature scan failed: ${error instanceof Error ? error.message : String(error)}`);
|
|
26984
27028
|
}
|
|
26985
27029
|
}
|
|
26986
|
-
function handleContext(file,
|
|
27030
|
+
function handleContext(file, dataDb, codegraphDb) {
|
|
26987
27031
|
const lines = [];
|
|
26988
|
-
const nodes =
|
|
27032
|
+
const nodes = codegraphDb.prepare(
|
|
26989
27033
|
"SELECT name, kind, start_line, end_line FROM nodes WHERE file_path = ? ORDER BY start_line"
|
|
26990
27034
|
).all(file);
|
|
26991
27035
|
if (nodes.length > 0) {
|
|
@@ -27012,7 +27056,7 @@ function handleContext(file, dataDb2, codegraphDb2) {
|
|
|
27012
27056
|
}
|
|
27013
27057
|
lines.push("");
|
|
27014
27058
|
}
|
|
27015
|
-
if (isInMiddlewareTree(
|
|
27059
|
+
if (isInMiddlewareTree(dataDb, file)) {
|
|
27016
27060
|
lines.push("## WARNING: Middleware Import Tree");
|
|
27017
27061
|
lines.push("This file is imported (directly or transitively) by the middleware entry point.");
|
|
27018
27062
|
lines.push("NO Node.js dependencies allowed (pino, winston, fs, crypto, path, child_process).");
|
|
@@ -27021,7 +27065,7 @@ function handleContext(file, dataDb2, codegraphDb2) {
|
|
|
27021
27065
|
const domain = classifyFile(file);
|
|
27022
27066
|
lines.push(`## Domain: ${domain}`);
|
|
27023
27067
|
lines.push("");
|
|
27024
|
-
const imports =
|
|
27068
|
+
const imports = dataDb.prepare(
|
|
27025
27069
|
"SELECT target_file, imported_names FROM massu_imports WHERE source_file = ? LIMIT 20"
|
|
27026
27070
|
).all(file);
|
|
27027
27071
|
if (imports.length > 0) {
|
|
@@ -27032,7 +27076,7 @@ function handleContext(file, dataDb2, codegraphDb2) {
|
|
|
27032
27076
|
}
|
|
27033
27077
|
lines.push("");
|
|
27034
27078
|
}
|
|
27035
|
-
const importedBy =
|
|
27079
|
+
const importedBy = dataDb.prepare(
|
|
27036
27080
|
"SELECT source_file FROM massu_imports WHERE target_file = ? LIMIT 20"
|
|
27037
27081
|
).all(file);
|
|
27038
27082
|
if (importedBy.length > 0) {
|
|
@@ -27196,10 +27240,10 @@ function handleContext(file, dataDb2, codegraphDb2) {
|
|
|
27196
27240
|
}
|
|
27197
27241
|
return text17(lines.join("\n") || "No context available for this file.");
|
|
27198
27242
|
}
|
|
27199
|
-
function handleTrpcMap(args2,
|
|
27243
|
+
function handleTrpcMap(args2, dataDb) {
|
|
27200
27244
|
const lines = [];
|
|
27201
27245
|
if (args2.uncoupled) {
|
|
27202
|
-
const uncoupled =
|
|
27246
|
+
const uncoupled = dataDb.prepare(
|
|
27203
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"
|
|
27204
27248
|
).all();
|
|
27205
27249
|
lines.push(`## Uncoupled Procedures (${uncoupled.length} total)`);
|
|
@@ -27214,7 +27258,7 @@ function handleTrpcMap(args2, dataDb2) {
|
|
|
27214
27258
|
lines.push(`- ${proc.procedure_name} (${proc.procedure_type})`);
|
|
27215
27259
|
}
|
|
27216
27260
|
} else if (args2.router) {
|
|
27217
|
-
const procs =
|
|
27261
|
+
const procs = dataDb.prepare(
|
|
27218
27262
|
"SELECT id, procedure_name, procedure_type, has_ui_caller FROM massu_trpc_procedures WHERE router_name = ? ORDER BY procedure_name"
|
|
27219
27263
|
).all(args2.router);
|
|
27220
27264
|
lines.push(`## Router: ${args2.router} (${procs.length} procedures)`);
|
|
@@ -27222,7 +27266,7 @@ function handleTrpcMap(args2, dataDb2) {
|
|
|
27222
27266
|
for (const proc of procs) {
|
|
27223
27267
|
const status = proc.has_ui_caller ? "" : " [NO UI CALLERS]";
|
|
27224
27268
|
lines.push(`### ${args2.router}.${proc.procedure_name} (${proc.procedure_type})${status}`);
|
|
27225
|
-
const callSites =
|
|
27269
|
+
const callSites = dataDb.prepare(
|
|
27226
27270
|
"SELECT file, line, call_pattern FROM massu_trpc_call_sites WHERE procedure_id = ?"
|
|
27227
27271
|
).all(proc.id);
|
|
27228
27272
|
if (callSites.length > 0) {
|
|
@@ -27236,7 +27280,7 @@ function handleTrpcMap(args2, dataDb2) {
|
|
|
27236
27280
|
lines.push("");
|
|
27237
27281
|
}
|
|
27238
27282
|
} else if (args2.procedure) {
|
|
27239
|
-
const procs =
|
|
27283
|
+
const procs = dataDb.prepare(
|
|
27240
27284
|
"SELECT id, router_name, router_file, procedure_type, has_ui_caller FROM massu_trpc_procedures WHERE procedure_name = ? ORDER BY router_name"
|
|
27241
27285
|
).all(args2.procedure);
|
|
27242
27286
|
lines.push(`## Procedure "${args2.procedure}" found in ${procs.length} routers`);
|
|
@@ -27244,7 +27288,7 @@ function handleTrpcMap(args2, dataDb2) {
|
|
|
27244
27288
|
for (const proc of procs) {
|
|
27245
27289
|
lines.push(`### ${proc.router_name}.${args2.procedure} (${proc.procedure_type})`);
|
|
27246
27290
|
lines.push(`File: ${proc.router_file}`);
|
|
27247
|
-
const callSites =
|
|
27291
|
+
const callSites = dataDb.prepare(
|
|
27248
27292
|
"SELECT file, line, call_pattern FROM massu_trpc_call_sites WHERE procedure_id = ?"
|
|
27249
27293
|
).all(proc.id);
|
|
27250
27294
|
if (callSites.length > 0) {
|
|
@@ -27258,8 +27302,8 @@ function handleTrpcMap(args2, dataDb2) {
|
|
|
27258
27302
|
lines.push("");
|
|
27259
27303
|
}
|
|
27260
27304
|
} else {
|
|
27261
|
-
const total =
|
|
27262
|
-
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();
|
|
27263
27307
|
const uncoupled = total.count - coupled.count;
|
|
27264
27308
|
lines.push("## tRPC Procedure Summary");
|
|
27265
27309
|
lines.push(`- Total procedures: ${total.count}`);
|
|
@@ -27271,16 +27315,16 @@ function handleTrpcMap(args2, dataDb2) {
|
|
|
27271
27315
|
}
|
|
27272
27316
|
return text17(lines.join("\n"));
|
|
27273
27317
|
}
|
|
27274
|
-
function handleCouplingCheck(args2,
|
|
27318
|
+
function handleCouplingCheck(args2, dataDb, codegraphDb) {
|
|
27275
27319
|
const lines = [];
|
|
27276
27320
|
const stagedFiles = args2.staged_files;
|
|
27277
27321
|
let uncoupledProcs;
|
|
27278
27322
|
if (stagedFiles) {
|
|
27279
|
-
uncoupledProcs =
|
|
27323
|
+
uncoupledProcs = dataDb.prepare(
|
|
27280
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(",")})`
|
|
27281
27325
|
).all(...stagedFiles);
|
|
27282
27326
|
} else {
|
|
27283
|
-
uncoupledProcs =
|
|
27327
|
+
uncoupledProcs = dataDb.prepare(
|
|
27284
27328
|
"SELECT router_name, procedure_name, procedure_type, router_file FROM massu_trpc_procedures WHERE has_ui_caller = 0"
|
|
27285
27329
|
).all();
|
|
27286
27330
|
}
|
|
@@ -27296,12 +27340,12 @@ function handleCouplingCheck(args2, dataDb2, codegraphDb2) {
|
|
|
27296
27340
|
lines.push("### Uncoupled Procedures: 0 (PASS)");
|
|
27297
27341
|
lines.push("");
|
|
27298
27342
|
}
|
|
27299
|
-
const allPages =
|
|
27343
|
+
const allPages = codegraphDb.prepare(
|
|
27300
27344
|
"SELECT path FROM files WHERE path LIKE 'src/app/%/page.tsx' OR path = 'src/app/page.tsx'"
|
|
27301
27345
|
).all();
|
|
27302
27346
|
const pageImports = /* @__PURE__ */ new Set();
|
|
27303
27347
|
for (const page of allPages) {
|
|
27304
|
-
const imports =
|
|
27348
|
+
const imports = dataDb.prepare(
|
|
27305
27349
|
"SELECT target_file FROM massu_imports WHERE source_file = ?"
|
|
27306
27350
|
).all(page.path);
|
|
27307
27351
|
for (const imp of imports) {
|
|
@@ -27311,7 +27355,7 @@ function handleCouplingCheck(args2, dataDb2, codegraphDb2) {
|
|
|
27311
27355
|
let componentFiles;
|
|
27312
27356
|
if (stagedFiles) {
|
|
27313
27357
|
const placeholders = stagedFiles.map(() => "?").join(",");
|
|
27314
|
-
componentFiles =
|
|
27358
|
+
componentFiles = codegraphDb.prepare(
|
|
27315
27359
|
`SELECT path FROM files WHERE path LIKE 'src/components/%' AND path IN (${placeholders})`
|
|
27316
27360
|
).all(...stagedFiles);
|
|
27317
27361
|
} else {
|
|
@@ -27329,11 +27373,11 @@ function handleCouplingCheck(args2, dataDb2, codegraphDb2) {
|
|
|
27329
27373
|
lines.push(`### RESULT: ${totalIssues === 0 ? "PASS" : `FAIL (${totalIssues} issues)`}`);
|
|
27330
27374
|
return text17(lines.join("\n"));
|
|
27331
27375
|
}
|
|
27332
|
-
function handleImpact2(file,
|
|
27376
|
+
function handleImpact2(file, dataDb, codegraphDb) {
|
|
27333
27377
|
const lines = [];
|
|
27334
27378
|
lines.push(`## Impact Analysis: ${file}`);
|
|
27335
27379
|
lines.push("");
|
|
27336
|
-
const affectedPages = findAffectedPages(
|
|
27380
|
+
const affectedPages = findAffectedPages(dataDb, file);
|
|
27337
27381
|
if (affectedPages.length > 0) {
|
|
27338
27382
|
const portals = [...new Set(affectedPages.map((p19) => p19.portal))];
|
|
27339
27383
|
const allTables = [...new Set(affectedPages.flatMap((p19) => p19.tables))];
|
|
@@ -27363,7 +27407,7 @@ function handleImpact2(file, dataDb2, codegraphDb2) {
|
|
|
27363
27407
|
lines.push("No pages affected (file may not be in any page dependency chain).");
|
|
27364
27408
|
lines.push("");
|
|
27365
27409
|
}
|
|
27366
|
-
const inMiddleware = isInMiddlewareTree(
|
|
27410
|
+
const inMiddleware = isInMiddlewareTree(dataDb, file);
|
|
27367
27411
|
if (inMiddleware) {
|
|
27368
27412
|
lines.push("### WARNING: In Middleware Import Tree");
|
|
27369
27413
|
lines.push("Changes to this file affect Edge Runtime. No Node.js deps allowed.");
|
|
@@ -27373,7 +27417,7 @@ function handleImpact2(file, dataDb2, codegraphDb2) {
|
|
|
27373
27417
|
lines.push("");
|
|
27374
27418
|
const fileDomain = classifyFile(file);
|
|
27375
27419
|
lines.push(`### Domain: ${fileDomain}`);
|
|
27376
|
-
const imports =
|
|
27420
|
+
const imports = dataDb.prepare(
|
|
27377
27421
|
"SELECT target_file FROM massu_imports WHERE source_file = ?"
|
|
27378
27422
|
).all(file);
|
|
27379
27423
|
const crossings = [];
|
|
@@ -27391,7 +27435,7 @@ function handleImpact2(file, dataDb2, codegraphDb2) {
|
|
|
27391
27435
|
}
|
|
27392
27436
|
return text17(lines.join("\n"));
|
|
27393
27437
|
}
|
|
27394
|
-
function handleDomains(args2,
|
|
27438
|
+
function handleDomains(args2, dataDb, codegraphDb) {
|
|
27395
27439
|
const lines = [];
|
|
27396
27440
|
const domains = getConfig().domains;
|
|
27397
27441
|
if (args2.file) {
|
|
@@ -27404,7 +27448,7 @@ function handleDomains(args2, dataDb2, codegraphDb2) {
|
|
|
27404
27448
|
lines.push(`Allowed imports from: ${domainConfig.allowedImportsFrom.join(", ") || "any domain (system)"}`);
|
|
27405
27449
|
}
|
|
27406
27450
|
} else if (args2.crossings) {
|
|
27407
|
-
const crossings = findCrossDomainImports(
|
|
27451
|
+
const crossings = findCrossDomainImports(dataDb);
|
|
27408
27452
|
const violations = crossings.filter((c2) => !c2.allowed);
|
|
27409
27453
|
const allowed = crossings.filter((c2) => c2.allowed);
|
|
27410
27454
|
lines.push(`## Cross-Domain Import Analysis`);
|
|
@@ -27423,7 +27467,7 @@ function handleDomains(args2, dataDb2, codegraphDb2) {
|
|
|
27423
27467
|
}
|
|
27424
27468
|
} else if (args2.domain) {
|
|
27425
27469
|
const domainName = args2.domain;
|
|
27426
|
-
const files = getFilesInDomain(
|
|
27470
|
+
const files = getFilesInDomain(dataDb, codegraphDb, domainName);
|
|
27427
27471
|
const config = domains.find((d2) => d2.name === domainName);
|
|
27428
27472
|
lines.push(`## Domain: ${domainName}`);
|
|
27429
27473
|
if (config) {
|
|
@@ -27576,69 +27620,302 @@ var init_tools = __esm({
|
|
|
27576
27620
|
}
|
|
27577
27621
|
});
|
|
27578
27622
|
|
|
27579
|
-
// src/
|
|
27580
|
-
|
|
27581
|
-
|
|
27582
|
-
|
|
27583
|
-
|
|
27584
|
-
function
|
|
27585
|
-
|
|
27586
|
-
|
|
27587
|
-
|
|
27588
|
-
|
|
27589
|
-
|
|
27590
|
-
|
|
27591
|
-
|
|
27592
|
-
|
|
27593
|
-
|
|
27594
|
-
|
|
27595
|
-
|
|
27596
|
-
|
|
27597
|
-
|
|
27598
|
-
|
|
27599
|
-
|
|
27600
|
-
|
|
27601
|
-
|
|
27602
|
-
|
|
27603
|
-
|
|
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
|
+
|
|
27762
|
+
// src/server-dispatch.ts
|
|
27763
|
+
function createDispatcher(options) {
|
|
27764
|
+
let codegraphDbCache = null;
|
|
27765
|
+
let dataDbCache = null;
|
|
27766
|
+
function resolveDbsForTool(toolName) {
|
|
27767
|
+
const needs = getToolDbNeeds(toolName, getConfig().toolPrefix);
|
|
27768
|
+
let dataDbResolved;
|
|
27769
|
+
let codegraphDbResolved;
|
|
27770
|
+
if (needs.includes("data")) {
|
|
27771
|
+
if (!dataDbCache) dataDbCache = getDataDb();
|
|
27772
|
+
dataDbResolved = dataDbCache;
|
|
27773
|
+
}
|
|
27774
|
+
if (needs.includes("codegraph")) {
|
|
27775
|
+
if (!codegraphDbCache) codegraphDbCache = getCodeGraphDb();
|
|
27776
|
+
codegraphDbResolved = codegraphDbCache;
|
|
27777
|
+
}
|
|
27778
|
+
return { needs, dataDb: dataDbResolved, codegraphDb: codegraphDbResolved };
|
|
27779
|
+
}
|
|
27780
|
+
async function handleRequest(request) {
|
|
27781
|
+
const { method, params, id } = request;
|
|
27782
|
+
switch (method) {
|
|
27783
|
+
case "initialize": {
|
|
27784
|
+
return {
|
|
27785
|
+
jsonrpc: "2.0",
|
|
27786
|
+
id: id ?? null,
|
|
27787
|
+
result: {
|
|
27788
|
+
protocolVersion: "2024-11-05",
|
|
27789
|
+
capabilities: { tools: {} },
|
|
27790
|
+
serverInfo: {
|
|
27791
|
+
name: getConfig().toolPrefix || "massu",
|
|
27792
|
+
version: options.serverInfoVersion
|
|
27793
|
+
}
|
|
27794
|
+
}
|
|
27795
|
+
};
|
|
27796
|
+
}
|
|
27797
|
+
case "notifications/initialized": {
|
|
27798
|
+
return { jsonrpc: "2.0", id: id ?? null, result: {} };
|
|
27799
|
+
}
|
|
27800
|
+
case "tools/list": {
|
|
27801
|
+
const tools = getToolDefinitions();
|
|
27802
|
+
return { jsonrpc: "2.0", id: id ?? null, result: { tools } };
|
|
27803
|
+
}
|
|
27804
|
+
case "tools/call": {
|
|
27805
|
+
const toolName = params?.name ?? "";
|
|
27806
|
+
const toolArgs = params?.arguments ?? {};
|
|
27807
|
+
try {
|
|
27808
|
+
const { dataDb, codegraphDb } = resolveDbsForTool(toolName);
|
|
27809
|
+
const result = await handleToolCall(toolName, toolArgs, dataDb, codegraphDb);
|
|
27810
|
+
return { jsonrpc: "2.0", id: id ?? null, result };
|
|
27811
|
+
} catch (err) {
|
|
27812
|
+
if (err instanceof CodegraphDbNotInitializedError) {
|
|
27813
|
+
return {
|
|
27814
|
+
jsonrpc: "2.0",
|
|
27815
|
+
id: id ?? null,
|
|
27816
|
+
error: {
|
|
27817
|
+
code: -32001,
|
|
27818
|
+
message: "Tool requires CodeGraph database which is not initialized for this repo",
|
|
27819
|
+
data: {
|
|
27820
|
+
remedy: "npx @colbymchenry/codegraph@0.7.4 init . && npx @colbymchenry/codegraph@0.7.4 index .",
|
|
27821
|
+
codegraphDbPath: err.dbPath,
|
|
27822
|
+
tool: toolName
|
|
27823
|
+
}
|
|
27824
|
+
}
|
|
27825
|
+
};
|
|
27826
|
+
}
|
|
27827
|
+
if (err instanceof UnknownToolError) {
|
|
27828
|
+
return {
|
|
27829
|
+
jsonrpc: "2.0",
|
|
27830
|
+
id: id ?? null,
|
|
27831
|
+
error: {
|
|
27832
|
+
code: -32602,
|
|
27833
|
+
message: `Unknown tool: ${err.toolName}`,
|
|
27834
|
+
data: {
|
|
27835
|
+
remedy: "Tool not registered in TOOL_DB_NEEDS manifest. See packages/core/src/tool-db-needs.ts.",
|
|
27836
|
+
tool: toolName
|
|
27837
|
+
}
|
|
27838
|
+
}
|
|
27839
|
+
};
|
|
27604
27840
|
}
|
|
27841
|
+
throw err;
|
|
27605
27842
|
}
|
|
27606
|
-
}
|
|
27607
|
-
|
|
27608
|
-
|
|
27609
|
-
|
|
27843
|
+
}
|
|
27844
|
+
case "ping": {
|
|
27845
|
+
return { jsonrpc: "2.0", id: id ?? null, result: {} };
|
|
27846
|
+
}
|
|
27847
|
+
default: {
|
|
27848
|
+
return {
|
|
27849
|
+
jsonrpc: "2.0",
|
|
27850
|
+
id: id ?? null,
|
|
27851
|
+
error: { code: -32601, message: `Method not found: ${method}` }
|
|
27852
|
+
};
|
|
27853
|
+
}
|
|
27610
27854
|
}
|
|
27611
|
-
|
|
27612
|
-
|
|
27855
|
+
}
|
|
27856
|
+
async function processLine(line) {
|
|
27857
|
+
const trimmed = line.trim();
|
|
27858
|
+
if (!trimmed) return null;
|
|
27859
|
+
let request;
|
|
27860
|
+
try {
|
|
27861
|
+
request = JSON.parse(trimmed);
|
|
27862
|
+
} catch (parseError) {
|
|
27613
27863
|
return {
|
|
27614
|
-
|
|
27615
|
-
|
|
27616
|
-
|
|
27864
|
+
response: {
|
|
27865
|
+
jsonrpc: "2.0",
|
|
27866
|
+
id: null,
|
|
27867
|
+
error: {
|
|
27868
|
+
code: -32700,
|
|
27869
|
+
message: `Parse error: ${parseError instanceof Error ? parseError.message : String(parseError)}`
|
|
27870
|
+
}
|
|
27871
|
+
},
|
|
27872
|
+
emit: true
|
|
27617
27873
|
};
|
|
27618
27874
|
}
|
|
27619
|
-
|
|
27620
|
-
const
|
|
27621
|
-
|
|
27622
|
-
|
|
27623
|
-
const result = await handleToolCall(toolName, toolArgs, lDb, cgDb);
|
|
27875
|
+
try {
|
|
27876
|
+
const response = await handleRequest(request);
|
|
27877
|
+
return { response, emit: request.id !== void 0 };
|
|
27878
|
+
} catch (error) {
|
|
27624
27879
|
return {
|
|
27625
|
-
|
|
27626
|
-
|
|
27627
|
-
|
|
27880
|
+
response: {
|
|
27881
|
+
jsonrpc: "2.0",
|
|
27882
|
+
id: request.id ?? null,
|
|
27883
|
+
error: {
|
|
27884
|
+
code: -32603,
|
|
27885
|
+
message: `Internal error: ${error instanceof Error ? error.message : String(error)}`
|
|
27886
|
+
}
|
|
27887
|
+
},
|
|
27888
|
+
emit: true
|
|
27628
27889
|
};
|
|
27629
27890
|
}
|
|
27630
|
-
|
|
27631
|
-
|
|
27891
|
+
}
|
|
27892
|
+
function closeCachedDbs() {
|
|
27893
|
+
if (codegraphDbCache) {
|
|
27894
|
+
codegraphDbCache.close();
|
|
27895
|
+
codegraphDbCache = null;
|
|
27632
27896
|
}
|
|
27633
|
-
|
|
27634
|
-
|
|
27635
|
-
|
|
27636
|
-
id: id ?? null,
|
|
27637
|
-
error: { code: -32601, message: `Method not found: ${method}` }
|
|
27638
|
-
};
|
|
27897
|
+
if (dataDbCache) {
|
|
27898
|
+
dataDbCache.close();
|
|
27899
|
+
dataDbCache = null;
|
|
27639
27900
|
}
|
|
27640
27901
|
}
|
|
27902
|
+
return { handleRequest, processLine, closeCachedDbs };
|
|
27641
27903
|
}
|
|
27904
|
+
var init_server_dispatch = __esm({
|
|
27905
|
+
"src/server-dispatch.ts"() {
|
|
27906
|
+
"use strict";
|
|
27907
|
+
init_db();
|
|
27908
|
+
init_config();
|
|
27909
|
+
init_tools();
|
|
27910
|
+
init_tool_db_needs();
|
|
27911
|
+
}
|
|
27912
|
+
});
|
|
27913
|
+
|
|
27914
|
+
// src/server.ts
|
|
27915
|
+
var server_exports = {};
|
|
27916
|
+
import { readFileSync as readFileSync39 } from "fs";
|
|
27917
|
+
import { resolve as resolve32, dirname as dirname16 } from "path";
|
|
27918
|
+
import { fileURLToPath as fileURLToPath4 } from "url";
|
|
27642
27919
|
function pruneMemoryOnStartup() {
|
|
27643
27920
|
try {
|
|
27644
27921
|
const memDb = getMemoryDb();
|
|
@@ -27662,15 +27939,13 @@ function pruneMemoryOnStartup() {
|
|
|
27662
27939
|
);
|
|
27663
27940
|
}
|
|
27664
27941
|
}
|
|
27665
|
-
var __dirname4, PKG_VERSION,
|
|
27942
|
+
var __dirname4, PKG_VERSION, dispatcher, buffer;
|
|
27666
27943
|
var init_server = __esm({
|
|
27667
27944
|
"src/server.ts"() {
|
|
27668
27945
|
"use strict";
|
|
27669
|
-
init_db();
|
|
27670
|
-
init_config();
|
|
27671
|
-
init_tools();
|
|
27672
27946
|
init_memory_db();
|
|
27673
27947
|
init_license();
|
|
27948
|
+
init_server_dispatch();
|
|
27674
27949
|
__dirname4 = dirname16(fileURLToPath4(import.meta.url));
|
|
27675
27950
|
PKG_VERSION = (() => {
|
|
27676
27951
|
try {
|
|
@@ -27680,8 +27955,7 @@ var init_server = __esm({
|
|
|
27680
27955
|
return "0.0.0";
|
|
27681
27956
|
}
|
|
27682
27957
|
})();
|
|
27683
|
-
|
|
27684
|
-
dataDb = null;
|
|
27958
|
+
dispatcher = createDispatcher({ serverInfoVersion: PKG_VERSION });
|
|
27685
27959
|
pruneMemoryOnStartup();
|
|
27686
27960
|
getCurrentTier().then((tier) => {
|
|
27687
27961
|
process.stderr.write(`massu: License tier: ${tier}
|
|
@@ -27698,32 +27972,16 @@ var init_server = __esm({
|
|
|
27698
27972
|
buffer += chunk;
|
|
27699
27973
|
let newlineIndex;
|
|
27700
27974
|
while ((newlineIndex = buffer.indexOf("\n")) !== -1) {
|
|
27701
|
-
const line = buffer.slice(0, newlineIndex)
|
|
27975
|
+
const line = buffer.slice(0, newlineIndex);
|
|
27702
27976
|
buffer = buffer.slice(newlineIndex + 1);
|
|
27703
|
-
|
|
27704
|
-
|
|
27705
|
-
|
|
27706
|
-
const response = await handleRequest(request);
|
|
27707
|
-
if (request.id !== void 0) {
|
|
27708
|
-
const responseStr = JSON.stringify(response);
|
|
27709
|
-
process.stdout.write(responseStr + "\n");
|
|
27710
|
-
}
|
|
27711
|
-
} catch (error) {
|
|
27712
|
-
const errorResponse = {
|
|
27713
|
-
jsonrpc: "2.0",
|
|
27714
|
-
id: null,
|
|
27715
|
-
error: {
|
|
27716
|
-
code: -32700,
|
|
27717
|
-
message: `Parse error: ${error instanceof Error ? error.message : String(error)}`
|
|
27718
|
-
}
|
|
27719
|
-
};
|
|
27720
|
-
process.stdout.write(JSON.stringify(errorResponse) + "\n");
|
|
27977
|
+
const result = await dispatcher.processLine(line);
|
|
27978
|
+
if (result && result.emit) {
|
|
27979
|
+
process.stdout.write(JSON.stringify(result.response) + "\n");
|
|
27721
27980
|
}
|
|
27722
27981
|
}
|
|
27723
27982
|
});
|
|
27724
27983
|
process.stdin.on("end", () => {
|
|
27725
|
-
|
|
27726
|
-
if (dataDb) dataDb.close();
|
|
27984
|
+
dispatcher.closeCachedDbs();
|
|
27727
27985
|
process.exit(0);
|
|
27728
27986
|
});
|
|
27729
27987
|
process.on("uncaughtException", (error) => {
|