@massu/core 1.6.0 → 1.6.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/cli.js +730 -1686
- package/dist/hooks/session-start.js +10 -15
- package/docs/AUTHORING-ADAPTERS.md +41 -0
- package/docs/SECURITY.md +39 -0
- package/package.json +3 -3
- package/src/db.ts +24 -1
- package/src/security/registry-pubkey.generated.ts +1 -1
- package/src/server.ts +126 -25
- package/src/tool-db-needs.ts +226 -0
- package/src/tools.ts +110 -24
package/src/tools.ts
CHANGED
|
@@ -75,14 +75,26 @@ function stripPrefix(name: string): string {
|
|
|
75
75
|
|
|
76
76
|
/**
|
|
77
77
|
* Ensure indexes are built and up-to-date.
|
|
78
|
+
*
|
|
78
79
|
* Lazy initialization: only rebuilds if stale.
|
|
80
|
+
*
|
|
81
|
+
* **Codegraph-optional**: `codegraphDb` is now optional. When omitted, the
|
|
82
|
+
* JS index section (imports, tRPC, pages, middleware — all derived from
|
|
83
|
+
* CodeGraph AST data) is skipped. The Python index section (which only
|
|
84
|
+
* reads Python source files via tree-sitter into Data DB) still runs.
|
|
85
|
+
* This supports the lazy-per-tool-DB design from
|
|
86
|
+
* `plan-1.6.2-server-lazy-db-deps`: Python tools and any tool that needs
|
|
87
|
+
* fresh Python indexes can call `ensureIndexes(dataDb)` without requiring
|
|
88
|
+
* a CodeGraph DB.
|
|
79
89
|
*/
|
|
80
|
-
function ensureIndexes(dataDb: Database.Database, codegraphDb
|
|
90
|
+
function ensureIndexes(dataDb: Database.Database, codegraphDb?: Database.Database, force: boolean = false): string {
|
|
81
91
|
const results: string[] = [];
|
|
82
92
|
const config = getConfig();
|
|
83
93
|
|
|
84
|
-
// JS indexes
|
|
85
|
-
|
|
94
|
+
// JS indexes — require CodeGraph DB. Skipped when codegraphDb is undefined
|
|
95
|
+
// (e.g., a Python tool or memory tool triggered ensureIndexes for its
|
|
96
|
+
// own Python-index needs without needing JS indexes).
|
|
97
|
+
if (codegraphDb !== undefined && (force || isDataStale(dataDb, codegraphDb))) {
|
|
86
98
|
const importCount = buildImportIndex(dataDb, codegraphDb);
|
|
87
99
|
results.push(`Import edges: ${importCount}`);
|
|
88
100
|
|
|
@@ -259,24 +271,65 @@ export function getToolDefinitions(): ToolDefinition[] {
|
|
|
259
271
|
]);
|
|
260
272
|
}
|
|
261
273
|
|
|
274
|
+
/**
|
|
275
|
+
* Defensive assertion: a routing branch that consumes Data DB requires it
|
|
276
|
+
* to have been resolved by the dispatcher. Should never fire — the manifest
|
|
277
|
+
* declares which tools need Data DB and `server.ts:resolveDbsForTool`
|
|
278
|
+
* resolves accordingly. A throw here indicates a manifest/code drift.
|
|
279
|
+
*/
|
|
280
|
+
function assertDataDb(dataDb: Database.Database | undefined, toolName: string): Database.Database {
|
|
281
|
+
if (!dataDb) {
|
|
282
|
+
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'.`);
|
|
283
|
+
}
|
|
284
|
+
return dataDb;
|
|
285
|
+
}
|
|
286
|
+
|
|
287
|
+
/**
|
|
288
|
+
* Defensive assertion mirror of {@link assertDataDb} for CodeGraph DB.
|
|
289
|
+
*/
|
|
290
|
+
function assertCodegraphDb(codegraphDb: Database.Database | undefined, toolName: string): Database.Database {
|
|
291
|
+
if (!codegraphDb) {
|
|
292
|
+
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'.`);
|
|
293
|
+
}
|
|
294
|
+
return codegraphDb;
|
|
295
|
+
}
|
|
296
|
+
|
|
262
297
|
/**
|
|
263
298
|
* Handle a tool call and return the result.
|
|
299
|
+
*
|
|
300
|
+
* **Pre-dispatch ordering invariant (P-A-002c, plan-1.6.2-server-lazy-db-deps)**:
|
|
301
|
+
* 1. Tier gate (`isToolAllowed`) — checked BEFORE any DB access so
|
|
302
|
+
* free-tier users cannot provoke DB errors on paid tools.
|
|
303
|
+
* 2. Per-family routing (memory/observability/sentinel/knowledge/...) —
|
|
304
|
+
* each family opens ONLY the DB connections its handler needs.
|
|
305
|
+
* 3. Code-intel families (Python, core JS) invoke `ensureIndexes` at
|
|
306
|
+
* the top of their branch with the DBs they have. ensureIndexes is
|
|
307
|
+
* NEVER called unconditionally for memory/audit/knowledge/etc.
|
|
308
|
+
*
|
|
309
|
+
* **DB params**: `dataDb` and `codegraphDb` are OPTIONAL — the dispatcher
|
|
310
|
+
* (`server.ts:resolveDbsForTool`) resolves them based on the tool's entry
|
|
311
|
+
* in `TOOL_DB_NEEDS`. Memory/Knowledge DBs are opened per-call inside
|
|
312
|
+
* their routing branches (existing pattern, unchanged).
|
|
313
|
+
*
|
|
314
|
+
* **Defensive checks**: branches that require a DB call `assertDataDb`
|
|
315
|
+
* or `assertCodegraphDb` first. These should never fire — `TOOL_DB_NEEDS`
|
|
316
|
+
* guarantees the dispatcher resolved the right DBs — but the runtime
|
|
317
|
+
* check catches manifest/code drift loudly instead of silently passing
|
|
318
|
+
* `undefined` into handlers.
|
|
264
319
|
*/
|
|
265
320
|
export async function handleToolCall(
|
|
266
321
|
name: string,
|
|
267
322
|
args: Record<string, unknown>,
|
|
268
|
-
dataDb
|
|
269
|
-
codegraphDb
|
|
323
|
+
dataDb?: Database.Database,
|
|
324
|
+
codegraphDb?: Database.Database
|
|
270
325
|
): Promise<ToolResult> {
|
|
271
|
-
// P3-017: Tier gate — check before any routing
|
|
326
|
+
// P3-017: Tier gate — check before any routing (ordering invariant step 1)
|
|
272
327
|
const userTier = await getCurrentTier();
|
|
273
328
|
const requiredTier = getToolTier(name);
|
|
274
329
|
if (!isToolAllowed(name, userTier)) {
|
|
275
330
|
return text(`This tool requires ${requiredTier} tier. Current tier: ${userTier}. Upgrade at https://massu.ai/pricing`);
|
|
276
331
|
}
|
|
277
332
|
|
|
278
|
-
// Ensure indexes are built before any tool call
|
|
279
|
-
const syncMessage = ensureIndexes(dataDb, codegraphDb);
|
|
280
333
|
const pfx = prefix();
|
|
281
334
|
|
|
282
335
|
try {
|
|
@@ -307,7 +360,7 @@ export async function handleToolCall(
|
|
|
307
360
|
|
|
308
361
|
// Route sentinel tools to sentinel handler
|
|
309
362
|
if (name.startsWith(pfx + '_sentinel_')) {
|
|
310
|
-
return handleSentinelToolCall(name, args, dataDb);
|
|
363
|
+
return handleSentinelToolCall(name, args, assertDataDb(dataDb, name));
|
|
311
364
|
}
|
|
312
365
|
|
|
313
366
|
// Route analytics layer tools
|
|
@@ -375,9 +428,13 @@ export async function handleToolCall(
|
|
|
375
428
|
finally { knowledgeDb.close(); }
|
|
376
429
|
}
|
|
377
430
|
|
|
378
|
-
// Route Python tools (uses dataDb
|
|
431
|
+
// Route Python tools (uses dataDb only; codegraphDb not required).
|
|
432
|
+
// ensureIndexes runs WITHOUT codegraphDb — only the Python-index section
|
|
433
|
+
// rebuilds (against dataDb). JS-index section is skipped (no codegraph).
|
|
379
434
|
if (isPythonTool(name)) {
|
|
380
|
-
|
|
435
|
+
const pyDataDb = assertDataDb(dataDb, name);
|
|
436
|
+
ensureIndexes(pyDataDb);
|
|
437
|
+
return handlePythonToolCall(name, args, pyDataDb);
|
|
381
438
|
}
|
|
382
439
|
|
|
383
440
|
// Route license tools
|
|
@@ -387,22 +444,51 @@ export async function handleToolCall(
|
|
|
387
444
|
finally { memDb.close(); }
|
|
388
445
|
}
|
|
389
446
|
|
|
390
|
-
// Match core tools by base name
|
|
447
|
+
// Match core tools by base name. Each codegraph-dependent core tool
|
|
448
|
+
// asserts both DBs and runs ensureIndexes (full JS + Python rebuild
|
|
449
|
+
// when stale).
|
|
391
450
|
const baseName = stripPrefix(name);
|
|
392
451
|
switch (baseName) {
|
|
393
|
-
case 'sync':
|
|
394
|
-
|
|
395
|
-
|
|
396
|
-
return
|
|
397
|
-
|
|
398
|
-
|
|
399
|
-
|
|
400
|
-
|
|
401
|
-
|
|
402
|
-
return
|
|
403
|
-
|
|
404
|
-
|
|
452
|
+
case 'sync': {
|
|
453
|
+
const d = assertDataDb(dataDb, name);
|
|
454
|
+
const c = assertCodegraphDb(codegraphDb, name);
|
|
455
|
+
return handleSync(d, c);
|
|
456
|
+
}
|
|
457
|
+
case 'context': {
|
|
458
|
+
const d = assertDataDb(dataDb, name);
|
|
459
|
+
const c = assertCodegraphDb(codegraphDb, name);
|
|
460
|
+
ensureIndexes(d, c);
|
|
461
|
+
return handleContext(args.file as string, d, c);
|
|
462
|
+
}
|
|
463
|
+
case 'trpc_map': {
|
|
464
|
+
const d = assertDataDb(dataDb, name);
|
|
465
|
+
// trpc_map needs the tRPC index in Data DB. The index is built by
|
|
466
|
+
// ensureIndexes' JS section, which requires CodeGraph DB. If
|
|
467
|
+
// codegraphDb is provided (manifest declares 'codegraph'), rebuild
|
|
468
|
+
// the index; otherwise read whatever stale index exists.
|
|
469
|
+
ensureIndexes(d, codegraphDb);
|
|
470
|
+
return handleTrpcMap(args, d);
|
|
471
|
+
}
|
|
472
|
+
case 'coupling_check': {
|
|
473
|
+
const d = assertDataDb(dataDb, name);
|
|
474
|
+
const c = assertCodegraphDb(codegraphDb, name);
|
|
475
|
+
ensureIndexes(d, c);
|
|
476
|
+
return handleCouplingCheck(args, d, c);
|
|
477
|
+
}
|
|
478
|
+
case 'impact': {
|
|
479
|
+
const d = assertDataDb(dataDb, name);
|
|
480
|
+
const c = assertCodegraphDb(codegraphDb, name);
|
|
481
|
+
ensureIndexes(d, c);
|
|
482
|
+
return handleImpact(args.file as string, d, c);
|
|
483
|
+
}
|
|
484
|
+
case 'domains': {
|
|
485
|
+
const d = assertDataDb(dataDb, name);
|
|
486
|
+
const c = assertCodegraphDb(codegraphDb, name);
|
|
487
|
+
ensureIndexes(d, c);
|
|
488
|
+
return handleDomains(args, d, c);
|
|
489
|
+
}
|
|
405
490
|
case 'schema':
|
|
491
|
+
// Filesystem-only; no DB access.
|
|
406
492
|
return handleSchema(args);
|
|
407
493
|
default:
|
|
408
494
|
return text(`Unknown tool: ${name}`);
|