@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 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 Error(`CodeGraph database not found at ${dbPath}. Run 'npx @colbymchenry/codegraph sync' first.`);
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(dataDb2, codegraphDb2) {
17880
- const lastBuild = dataDb2.prepare("SELECT value FROM massu_meta WHERE key = 'last_build_time'").get();
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 = codegraphDb2.prepare("SELECT MAX(indexed_at) as latest FROM files").get();
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(dataDb2) {
17887
- dataDb2.prepare("INSERT OR REPLACE INTO massu_meta (key, value) VALUES ('last_build_time', ?)").run((/* @__PURE__ */ new Date()).toISOString());
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(dataDb2, pythonRoot) {
17890
- const lastBuild = dataDb2.prepare("SELECT value FROM massu_py_meta WHERE key = 'last_build_time'").get();
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(dataDb2) {
17912
- dataDb2.prepare("INSERT OR REPLACE INTO massu_py_meta (key, value) VALUES ('last_build_time', ?)").run((/* @__PURE__ */ new Date()).toISOString());
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(dataDb2, codegraphDb2) {
18092
- const files = codegraphDb2.prepare("SELECT path FROM files WHERE path LIKE 'src/%'").all();
18093
- dataDb2.exec("DELETE FROM massu_imports");
18094
- const insertStmt = dataDb2.prepare(
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 = dataDb2.transaction((edges) => {
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(dataDb2) {
18259
- dataDb2.exec("DELETE FROM massu_trpc_call_sites");
18260
- dataDb2.exec("DELETE FROM massu_trpc_procedures");
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 = dataDb2.prepare(
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 = dataDb2.prepare(
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 = dataDb2.transaction(() => {
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, dataDb2, visited, components, hooks, maxDepth = 5) {
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 = dataDb2.prepare(
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, dataDb2, visited, components, hooks, maxDepth - 1);
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, dataDb2) {
18361
+ function findTablesFromRouters(routerNames, dataDb) {
18353
18362
  const tables = /* @__PURE__ */ new Set();
18354
18363
  for (const routerName of routerNames) {
18355
- const procs = dataDb2.prepare(
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(dataDb2, codegraphDb2) {
18377
- dataDb2.exec("DELETE FROM massu_page_deps");
18378
- const pages = codegraphDb2.prepare(
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 = dataDb2.prepare(
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 = dataDb2.transaction(() => {
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, dataDb2, visited, components, hooks);
18401
+ traceImports(page.path, dataDb, visited, components, hooks);
18393
18402
  const allFiles = [...visited];
18394
18403
  const routers = findRouterCalls(allFiles);
18395
- const tables = findTablesFromRouters(routers, dataDb2);
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(dataDb2, pageFile) {
18412
- const row = dataDb2.prepare("SELECT * FROM massu_page_deps WHERE page_file = ?").get(pageFile);
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(dataDb2, file) {
18425
- const directPage = getPageChain(dataDb2, file);
18433
+ function findAffectedPages(dataDb, file) {
18434
+ const directPage = getPageChain(dataDb, file);
18426
18435
  if (directPage) return [directPage];
18427
- const importers = dataDb2.prepare(
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 = dataDb2.prepare(
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 = dataDb2.prepare("SELECT * FROM massu_page_deps").all();
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(dataDb2) {
18479
- dataDb2.exec("DELETE FROM massu_middleware_tree");
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 = dataDb2.prepare(
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 = dataDb2.prepare("INSERT INTO massu_middleware_tree (file) VALUES (?)");
18499
- const insertAll = dataDb2.transaction(() => {
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(dataDb2, file) {
18508
- const result = dataDb2.prepare("SELECT 1 FROM massu_middleware_tree WHERE file = ?").get(file);
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(dataDb2) {
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 = dataDb2.prepare(
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(dataDb2, codegraphDb2, domainName) {
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 = codegraphDb2.prepare("SELECT path FROM files WHERE path LIKE ?").all(srcPattern);
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(dataDb2, pythonRoot, excludeDirs = ["__pycache__", ".venv", "venv", ".mypy_cache", ".pytest_cache"]) {
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
- dataDb2.exec("DELETE FROM massu_py_imports");
18963
- const insertStmt = dataDb2.prepare(
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 = dataDb2.transaction((edges) => {
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(dataDb2, pythonRoot, excludeDirs = ["__pycache__", ".venv", "venv", ".mypy_cache", ".pytest_cache"]) {
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
- dataDb2.exec("DELETE FROM massu_py_routes");
19266
- dataDb2.exec("DELETE FROM massu_py_route_callers");
19267
- const insertStmt = dataDb2.prepare(
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
- dataDb2.transaction(() => {
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(dataDb2, pythonRoot, excludeDirs = ["__pycache__", ".venv", "venv", ".mypy_cache", ".pytest_cache"]) {
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
- dataDb2.exec("DELETE FROM massu_py_models");
19510
- dataDb2.exec("DELETE FROM massu_py_fk_edges");
19511
- const insertModel = dataDb2.prepare(
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 = dataDb2.prepare(
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
- dataDb2.transaction(() => {
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(dataDb2, alembicDir) {
19795
+ function buildPythonMigrationIndex(dataDb, alembicDir) {
19787
19796
  const projectRoot = getProjectRoot();
19788
19797
  const absDir = join18(projectRoot, alembicDir);
19789
- dataDb2.exec("DELETE FROM massu_py_migrations");
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 = dataDb2.prepare(
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
- dataDb2.transaction(() => {
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(dataDb2) {
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 = dataDb2.prepare("SELECT id, method, path FROM massu_py_routes").all();
19859
+ const routes = dataDb.prepare("SELECT id, method, path FROM massu_py_routes").all();
19851
19860
  if (routes.length === 0) return 0;
19852
- dataDb2.exec("DELETE FROM massu_py_route_callers");
19861
+ dataDb.exec("DELETE FROM massu_py_route_callers");
19853
19862
  const frontendFiles = walkFrontendFiles(srcDir);
19854
- const insertStmt = dataDb2.prepare(
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
- dataDb2.transaction(() => {
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, dataDb2) {
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, dataDb2);
21406
+ return handleSearch2(args2, dataDb);
21398
21407
  case "sentinel_detail":
21399
- return handleDetail2(args2, dataDb2);
21408
+ return handleDetail2(args2, dataDb);
21400
21409
  case "sentinel_impact":
21401
- return handleImpact(args2, dataDb2);
21410
+ return handleImpact(args2, dataDb);
21402
21411
  case "sentinel_validate":
21403
- return handleValidate(args2, dataDb2);
21412
+ return handleValidate(args2, dataDb);
21404
21413
  case "sentinel_register":
21405
- return handleRegister(args2, dataDb2);
21414
+ return handleRegister(args2, dataDb);
21406
21415
  case "sentinel_parity":
21407
- return handleParityCheck(args2, dataDb2);
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(dataDb2) {
21730
+ function scanTrpcProcedures(dataDb) {
21722
21731
  const features = [];
21723
21732
  const featureMap = /* @__PURE__ */ new Map();
21724
- const procedures = dataDb2.prepare(`
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(dataDb2) {
21773
+ function scanPageRoutes(dataDb) {
21765
21774
  const features = [];
21766
- const pages = dataDb2.prepare(`
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(dataDb2) {
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(dataDb2) {
21889
- const procedureFeatures = scanTrpcProcedures(dataDb2);
21890
- const pageFeatures = scanPageRoutes(dataDb2);
21891
- const componentFeatures = scanComponentExports(dataDb2);
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(dataDb2, {
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(dataDb2, featureId, comp.file, comp.name, comp.role, comp.isPrimary);
21924
+ linkComponent(dataDb, featureId, comp.file, comp.name, comp.role, comp.isPrimary);
21916
21925
  }
21917
21926
  for (const proc of feature.procedures) {
21918
- linkProcedure(dataDb2, featureId, proc.router, proc.procedure, proc.type);
21927
+ linkProcedure(dataDb, featureId, proc.router, proc.procedure, proc.type);
21919
21928
  }
21920
21929
  for (const page of feature.pages) {
21921
- linkPage(dataDb2, featureId, page.route, page.portal ?? void 0);
21930
+ linkPage(dataDb, featureId, page.route, page.portal ?? void 0);
21922
21931
  }
21923
- logChange(dataDb2, featureId, "created", "Auto-discovered by sentinel scanner", void 0, "scanner");
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 dataDb2 = null;
25708
+ let dataDb = null;
25700
25709
  try {
25701
- dataDb2 = getDataDb();
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 = dataDb2.prepare(sql).all(...params);
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
- dataDb2?.close();
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 dataDb2 = null;
25774
+ let dataDb = null;
25766
25775
  try {
25767
- dataDb2 = getDataDb();
25768
- const domains = dataDb2.prepare(
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
- dataDb2?.close();
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, dataDb2) {
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, dataDb2);
26233
+ return handlePyImports(args2, dataDb);
26225
26234
  case "py_routes":
26226
- return handlePyRoutes(args2, dataDb2);
26235
+ return handlePyRoutes(args2, dataDb);
26227
26236
  case "py_coupling":
26228
- return handlePyCoupling(args2, dataDb2);
26237
+ return handlePyCoupling(args2, dataDb);
26229
26238
  case "py_models":
26230
- return handlePyModels(args2, dataDb2);
26239
+ return handlePyModels(args2, dataDb);
26231
26240
  case "py_migrations":
26232
- return handlePyMigrations(args2, dataDb2);
26241
+ return handlePyMigrations(args2, dataDb);
26233
26242
  case "py_domains":
26234
- return handlePyDomains(args2, dataDb2);
26243
+ return handlePyDomains(args2, dataDb);
26235
26244
  case "py_impact":
26236
- return handlePyImpact(args2, dataDb2);
26245
+ return handlePyImpact(args2, dataDb);
26237
26246
  case "py_context":
26238
- return handlePyContext(args2, dataDb2);
26247
+ return handlePyContext(args2, dataDb);
26239
26248
  default:
26240
26249
  return text16(`Unknown Python tool: ${name}`);
26241
26250
  }
26242
26251
  }
26243
- function handlePyImports(args2, dataDb2) {
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 = dataDb2.prepare(
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 = dataDb2.prepare(
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 = dataDb2.prepare(
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 = dataDb2.prepare("SELECT COUNT(*) as cnt FROM massu_py_imports").get().cnt;
26289
- const files = dataDb2.prepare("SELECT COUNT(DISTINCT source_file) as cnt FROM massu_py_imports").get().cnt;
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, dataDb2) {
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 = dataDb2.prepare(query).all(...params);
26329
+ const routes = dataDb.prepare(query).all(...params);
26321
26330
  if (args2.uncoupled) {
26322
- const callerCountStmt = dataDb2.prepare("SELECT COUNT(*) as cnt FROM massu_py_route_callers WHERE route_id = ?");
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, dataDb2) {
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 = dataDb2.prepare(query).all(...params);
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, dataDb2) {
26384
+ function handlePyModels(args2, dataDb) {
26376
26385
  const lines = [];
26377
26386
  if (args2.fk_graph) {
26378
- const edges = dataDb2.prepare("SELECT * FROM massu_py_fk_edges ORDER BY source_table").all();
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 = dataDb2.prepare(
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 = dataDb2.prepare(`SELECT class_name, table_name, file, line FROM massu_py_models ORDER BY class_name LIMIT ${limit}`).all();
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, dataDb2) {
26431
+ function handlePyMigrations(args2, dataDb) {
26423
26432
  const lines = [];
26424
26433
  if (args2.drift) {
26425
- const models = dataDb2.prepare("SELECT class_name, table_name, columns FROM massu_py_models").all();
26426
- const migrations = dataDb2.prepare("SELECT revision, operations FROM massu_py_migrations").all();
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 = dataDb2.prepare(`SELECT * FROM massu_py_migrations ORDER BY id LIMIT ${limit}`).all();
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 = dataDb2.prepare("SELECT * FROM massu_py_migrations WHERE revision = ?").get(args2.revision);
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 = dataDb2.prepare("SELECT COUNT(*) as cnt FROM massu_py_migrations").get().cnt;
26469
- const head = dataDb2.prepare("SELECT revision FROM massu_py_migrations WHERE is_head = 1").get();
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, dataDb2) {
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 = dataDb2.prepare("SELECT source_file, target_file FROM massu_py_imports").all();
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 = dataDb2.prepare("SELECT DISTINCT source_file FROM massu_py_imports UNION SELECT DISTINCT target_file FROM massu_py_imports").all();
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, dataDb2) {
26532
+ function handlePyImpact(args2, dataDb) {
26524
26533
  const file = args2.file;
26525
26534
  const lines = [`## Impact Analysis: ${file}`, ""];
26526
- const importedBy = dataDb2.prepare(
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 = dataDb2.prepare(
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 = dataDb2.prepare(
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 = dataDb2.prepare("SELECT id FROM massu_py_routes WHERE file = ?").all(file);
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 = dataDb2.prepare(
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, dataDb2) {
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 = dataDb2.prepare(
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 = dataDb2.prepare(
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 = dataDb2.prepare("SELECT method, path, function_name, line FROM massu_py_routes WHERE file = ?").all(file);
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 = dataDb2.prepare("SELECT class_name, table_name, line FROM massu_py_models WHERE file = ?").all(file);
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(dataDb2, codegraphDb2, force = false) {
26662
+ function ensureIndexes(dataDb, codegraphDb, force = false) {
26654
26663
  const results = [];
26655
26664
  const config = getConfig();
26656
- if (force || isDataStale(dataDb2, codegraphDb2)) {
26657
- const importCount = buildImportIndex(dataDb2, codegraphDb2);
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(dataDb2);
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(dataDb2, codegraphDb2);
26672
+ const pageCount = buildPageDeps(dataDb, codegraphDb);
26664
26673
  results.push(`Page deps: ${pageCount} pages`);
26665
26674
  if (config.paths.middleware) {
26666
- const middlewareCount = buildMiddlewareTree(dataDb2);
26675
+ const middlewareCount = buildMiddlewareTree(dataDb);
26667
26676
  results.push(`Middleware tree: ${middlewareCount} files`);
26668
26677
  }
26669
- updateBuildTimestamp(dataDb2);
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(dataDb2, resolve31(getProjectRoot(), pythonRoot))) {
26675
- const pyImports = buildPythonImportIndex(dataDb2, pythonRoot, excludeDirs);
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(dataDb2, pythonRoot, excludeDirs);
26686
+ const pyRoutes = buildPythonRouteIndex(dataDb, pythonRoot, excludeDirs);
26678
26687
  results.push(`Python routes: ${pyRoutes}`);
26679
- const pyModels = buildPythonModelIndex(dataDb2, pythonRoot, excludeDirs);
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(dataDb2, config.python.alembic_dir);
26691
+ const pyMigrations = buildPythonMigrationIndex(dataDb, config.python.alembic_dir);
26683
26692
  results.push(`Python migrations: ${pyMigrations}`);
26684
26693
  }
26685
- const pyCoupling = buildPythonCouplingIndex(dataDb2);
26694
+ const pyCoupling = buildPythonCouplingIndex(dataDb);
26686
26695
  results.push(`Python coupling: ${pyCoupling}`);
26687
- updatePythonBuildTimestamp(dataDb2);
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
- async function handleToolCall(name, args2, dataDb2, codegraphDb2) {
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, dataDb2);
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
- return handlePythonToolCall(name, args2, dataDb2);
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
- return handleSync(dataDb2, codegraphDb2);
26949
- case "context":
26950
- return handleContext(args2.file, dataDb2, codegraphDb2);
26951
- case "trpc_map":
26952
- return handleTrpcMap(args2, dataDb2);
26953
- case "coupling_check":
26954
- return handleCouplingCheck(args2, dataDb2, codegraphDb2);
26955
- case "impact":
26956
- return handleImpact2(args2.file, dataDb2, codegraphDb2);
26957
- case "domains":
26958
- return handleDomains(args2, dataDb2, codegraphDb2);
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(dataDb2, codegraphDb2) {
26974
- const result = ensureIndexes(dataDb2, codegraphDb2, true);
27017
+ function handleSync(dataDb, codegraphDb) {
27018
+ const result = ensureIndexes(dataDb, codegraphDb, true);
26975
27019
  try {
26976
- const scanResult = runFeatureScan(dataDb2);
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, dataDb2, codegraphDb2) {
27030
+ function handleContext(file, dataDb, codegraphDb) {
26987
27031
  const lines = [];
26988
- const nodes = codegraphDb2.prepare(
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(dataDb2, file)) {
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 = dataDb2.prepare(
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 = dataDb2.prepare(
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, dataDb2) {
27243
+ function handleTrpcMap(args2, dataDb) {
27200
27244
  const lines = [];
27201
27245
  if (args2.uncoupled) {
27202
- const uncoupled = dataDb2.prepare(
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 = dataDb2.prepare(
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 = dataDb2.prepare(
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 = dataDb2.prepare(
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 = dataDb2.prepare(
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 = dataDb2.prepare("SELECT COUNT(*) as count FROM massu_trpc_procedures").get();
27262
- const coupled = dataDb2.prepare("SELECT COUNT(*) as count FROM massu_trpc_procedures WHERE has_ui_caller = 1").get();
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, dataDb2, codegraphDb2) {
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 = dataDb2.prepare(
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 = dataDb2.prepare(
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 = codegraphDb2.prepare(
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 = dataDb2.prepare(
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 = codegraphDb2.prepare(
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, dataDb2, codegraphDb2) {
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(dataDb2, file);
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(dataDb2, file);
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 = dataDb2.prepare(
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, dataDb2, codegraphDb2) {
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(dataDb2);
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(dataDb2, codegraphDb2, domainName);
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/server.ts
27580
- var server_exports = {};
27581
- import { readFileSync as readFileSync39 } from "fs";
27582
- import { resolve as resolve32, dirname as dirname16 } from "path";
27583
- import { fileURLToPath as fileURLToPath4 } from "url";
27584
- function getDb() {
27585
- if (!codegraphDb) codegraphDb = getCodeGraphDb();
27586
- if (!dataDb) dataDb = getDataDb();
27587
- return { codegraphDb, dataDb };
27588
- }
27589
- async function handleRequest(request) {
27590
- const { method, params, id } = request;
27591
- switch (method) {
27592
- case "initialize": {
27593
- return {
27594
- jsonrpc: "2.0",
27595
- id: id ?? null,
27596
- result: {
27597
- protocolVersion: "2024-11-05",
27598
- capabilities: {
27599
- tools: {}
27600
- },
27601
- serverInfo: {
27602
- name: getConfig().toolPrefix || "massu",
27603
- version: PKG_VERSION
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
- case "notifications/initialized": {
27609
- return { jsonrpc: "2.0", id: id ?? null, result: {} };
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
- case "tools/list": {
27612
- const tools = getToolDefinitions();
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
- jsonrpc: "2.0",
27615
- id: id ?? null,
27616
- result: { tools }
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
- case "tools/call": {
27620
- const toolName = params?.name;
27621
- const toolArgs = params?.arguments ?? {};
27622
- const { codegraphDb: cgDb, dataDb: lDb } = getDb();
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
- jsonrpc: "2.0",
27626
- id: id ?? null,
27627
- result
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
- case "ping": {
27631
- return { jsonrpc: "2.0", id: id ?? null, result: {} };
27891
+ }
27892
+ function closeCachedDbs() {
27893
+ if (codegraphDbCache) {
27894
+ codegraphDbCache.close();
27895
+ codegraphDbCache = null;
27632
27896
  }
27633
- default: {
27634
- return {
27635
- jsonrpc: "2.0",
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, codegraphDb, dataDb, buffer;
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
- codegraphDb = null;
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).trim();
27975
+ const line = buffer.slice(0, newlineIndex);
27702
27976
  buffer = buffer.slice(newlineIndex + 1);
27703
- if (!line) continue;
27704
- try {
27705
- const request = JSON.parse(line);
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
- if (codegraphDb) codegraphDb.close();
27726
- if (dataDb) dataDb.close();
27984
+ dispatcher.closeCachedDbs();
27727
27985
  process.exit(0);
27728
27986
  });
27729
27987
  process.on("uncaughtException", (error) => {