@papyruslabsai/seshat-mcp 0.11.1 → 0.12.0
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/index.d.ts +0 -28
- package/dist/index.js +3 -2
- package/dist/loader.d.ts +2 -2
- package/dist/tools/diff.d.ts +2 -2
- package/dist/tools/diff.js +6 -8
- package/dist/tools/functors.d.ts +10 -10
- package/dist/tools/functors.js +49 -62
- package/dist/tools/index.d.ts +11 -14
- package/dist/tools/index.js +48 -64
- package/dist/types.d.ts +14 -0
- package/package.json +1 -1
package/dist/index.d.ts
CHANGED
|
@@ -1,29 +1 @@
|
|
|
1
|
-
#!/usr/bin/env node
|
|
2
|
-
/**
|
|
3
|
-
* @papyruslabs/seshat-mcp — Semantic Code Analysis MCP Server
|
|
4
|
-
*
|
|
5
|
-
* Exposes a codebase's structure, dependencies, and constraints as queryable
|
|
6
|
-
* MCP tools. Reads pre-extracted analysis data from .seshat/_bundle.json.
|
|
7
|
-
*
|
|
8
|
-
* Multi-project mode:
|
|
9
|
-
* Set SESHAT_PROJECTS env var to comma-separated paths or a glob pattern.
|
|
10
|
-
* In multi-project mode, all tools require a `project` parameter.
|
|
11
|
-
* Use `list_projects` to see available projects.
|
|
12
|
-
*
|
|
13
|
-
* Single-project mode (default):
|
|
14
|
-
* When SESHAT_PROJECTS is not set, loads from CWD. No `project` param needed.
|
|
15
|
-
*
|
|
16
|
-
* 20 tools across 4 categories:
|
|
17
|
-
* Discovery: list_projects, query_entities, get_entity, list_modules, get_topology
|
|
18
|
-
* Graph: get_dependencies, get_data_flow, find_by_constraint, get_blast_radius
|
|
19
|
-
* Analysis: find_dead_code, find_layer_violations, get_coupling_metrics,
|
|
20
|
-
* get_auth_matrix, find_error_gaps, get_test_coverage,
|
|
21
|
-
* get_optimal_context, estimate_task_cost, report_actual_burn
|
|
22
|
-
* Diff: diff_bundle, conflict_matrix
|
|
23
|
-
*
|
|
24
|
-
* Usage:
|
|
25
|
-
* npx @papyruslabs/seshat-mcp # single project (CWD)
|
|
26
|
-
* SESHAT_PROJECTS=/path/a,/path/b npx @papyruslabs/seshat-mcp # multi-project
|
|
27
|
-
* SESHAT_PROJECTS="/home/user/projects/*" npx @papyruslabs/seshat-mcp # glob
|
|
28
|
-
*/
|
|
29
1
|
export {};
|
package/dist/index.js
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
|
-
|
|
1
|
+
!/usr/bin / env;
|
|
2
|
+
node;
|
|
2
3
|
/**
|
|
3
4
|
* @papyruslabs/seshat-mcp — Semantic Code Analysis MCP Server
|
|
4
5
|
*
|
|
@@ -34,7 +35,7 @@ import { CallToolRequestSchema, ListToolsRequestSchema, } from '@modelcontextpro
|
|
|
34
35
|
import { MultiLoader } from './loader.js';
|
|
35
36
|
import { bootstrap } from './bootstrap.js';
|
|
36
37
|
import { logTelemetry, isSupabaseConfigured } from './supabase.js';
|
|
37
|
-
import {
|
|
38
|
+
import { queryEntities, getEntity, getDependencies, getDataFlow, findByConstraint, getBlastRadius, listModules, getTopology, } from './tools/index.js';
|
|
38
39
|
import { findDeadCode, findLayerViolations, getCouplingMetrics, getAuthMatrix, findErrorGaps, getTestCoverage, getOptimalContext, estimateTaskCost, reportActualBurn, find_runtime_violations, find_ownership_violations, query_traits, simulate_mutation, query_data_targets, find_exposure_leaks, find_semantic_clones, create_symbol, } from './tools/functors.js';
|
|
39
40
|
import { diffBundle, conflictMatrix, } from './tools/diff.js';
|
|
40
41
|
// ─── Project Discovery ───────────────────────────────────────────
|
package/dist/loader.d.ts
CHANGED
|
@@ -4,7 +4,7 @@
|
|
|
4
4
|
* Discovers and loads .seshat/_bundle.json from the current working directory.
|
|
5
5
|
* Falls back to checking common alternative locations.
|
|
6
6
|
*/
|
|
7
|
-
import type { JstfEntity, Topology, Manifest, ProjectInfo } from './types.js';
|
|
7
|
+
import type { JstfEntity, Topology, Manifest, ProjectInfo, ProjectLoader } from './types.js';
|
|
8
8
|
export declare class BundleLoader {
|
|
9
9
|
private entities;
|
|
10
10
|
private topology;
|
|
@@ -31,7 +31,7 @@ export declare class BundleLoader {
|
|
|
31
31
|
* In single-project mode (1 dir), behaves identically to BundleLoader.
|
|
32
32
|
* In multi-project mode, `project` param is required on all accessors.
|
|
33
33
|
*/
|
|
34
|
-
export declare class MultiLoader {
|
|
34
|
+
export declare class MultiLoader implements ProjectLoader {
|
|
35
35
|
private projects;
|
|
36
36
|
private projectPaths;
|
|
37
37
|
private projectEntities;
|
package/dist/tools/diff.d.ts
CHANGED
|
@@ -11,7 +11,7 @@ export declare function diffBundle(args: {
|
|
|
11
11
|
worktree_path: string;
|
|
12
12
|
project?: string;
|
|
13
13
|
include_unchanged?: boolean;
|
|
14
|
-
}): Promise<unknown>;
|
|
14
|
+
}, loader: ProjectLoader): Promise<unknown>;
|
|
15
15
|
export declare function conflictMatrix(args: {
|
|
16
16
|
tasks: Array<{
|
|
17
17
|
id: string;
|
|
@@ -20,4 +20,4 @@ export declare function conflictMatrix(args: {
|
|
|
20
20
|
expand_blast_radius?: boolean;
|
|
21
21
|
}>;
|
|
22
22
|
project?: string;
|
|
23
|
-
}): unknown;
|
|
23
|
+
}, loader: ProjectLoader): unknown;
|
package/dist/tools/diff.js
CHANGED
|
@@ -11,7 +11,7 @@ import fs from 'fs';
|
|
|
11
11
|
import path from 'path';
|
|
12
12
|
import { bootstrap } from '../bootstrap.js';
|
|
13
13
|
import { computeBlastRadius } from '../graph.js';
|
|
14
|
-
import {
|
|
14
|
+
import { getGraph, validateProject, entityName, entityLayer, } from './index.js';
|
|
15
15
|
// ─── Entity Identity ─────────────────────────────────────────────
|
|
16
16
|
// Ported from api-v2/translator/seshat-pipeline/src/incremental/diff-engine.mjs
|
|
17
17
|
/**
|
|
@@ -145,11 +145,10 @@ function compareEntityFields(baseEntity, branchEntity) {
|
|
|
145
145
|
return changed;
|
|
146
146
|
}
|
|
147
147
|
// ─── Tool: diff_bundle ───────────────────────────────────────────
|
|
148
|
-
export async function diffBundle(args) {
|
|
149
|
-
const projErr = validateProject(args.project);
|
|
148
|
+
export async function diffBundle(args, loader) {
|
|
149
|
+
const projErr = validateProject(args.project, loader);
|
|
150
150
|
if (projErr)
|
|
151
151
|
return { error: projErr };
|
|
152
|
-
const loader = getLoader();
|
|
153
152
|
const baseEntities = loader.getEntities(args.project);
|
|
154
153
|
const baseManifest = loader.getManifest(args.project);
|
|
155
154
|
if (baseEntities.length === 0) {
|
|
@@ -366,11 +365,10 @@ function buildExecutionPlan(taskIds, tier3Edges) {
|
|
|
366
365
|
};
|
|
367
366
|
}
|
|
368
367
|
// ─── Tool: conflict_matrix ────────────────────────────────────────
|
|
369
|
-
export function conflictMatrix(args) {
|
|
370
|
-
const projErr = validateProject(args.project);
|
|
368
|
+
export function conflictMatrix(args, loader) {
|
|
369
|
+
const projErr = validateProject(args.project, loader);
|
|
371
370
|
if (projErr)
|
|
372
371
|
return { error: projErr };
|
|
373
|
-
const loader = getLoader();
|
|
374
372
|
const { tasks } = args;
|
|
375
373
|
if (!tasks || tasks.length < 2) {
|
|
376
374
|
return { error: 'At least 2 tasks are required to compute a conflict matrix.' };
|
|
@@ -402,7 +400,7 @@ export function conflictMatrix(args) {
|
|
|
402
400
|
}
|
|
403
401
|
// Expand blast radius if requested
|
|
404
402
|
if (task.expand_blast_radius && entityIds.size > 0) {
|
|
405
|
-
const g = getGraph(args.project);
|
|
403
|
+
const g = getGraph(args.project, loader);
|
|
406
404
|
const blastResult = computeBlastRadius(g, entityIds);
|
|
407
405
|
for (const affectedId of blastResult.affected) {
|
|
408
406
|
if (!entityIds.has(affectedId)) {
|
package/dist/tools/functors.d.ts
CHANGED
|
@@ -15,14 +15,14 @@ export declare function estimateTokens(e: JstfEntity): number;
|
|
|
15
15
|
export declare function findDeadCode(args: {
|
|
16
16
|
include_tests?: boolean;
|
|
17
17
|
project?: string;
|
|
18
|
-
}): unknown;
|
|
18
|
+
}, loader: ProjectLoader): unknown;
|
|
19
19
|
export declare function findLayerViolations(args?: {
|
|
20
20
|
project?: string;
|
|
21
21
|
}): unknown;
|
|
22
22
|
export declare function getCouplingMetrics(args: {
|
|
23
23
|
group_by?: 'module' | 'layer';
|
|
24
24
|
project?: string;
|
|
25
|
-
}): unknown;
|
|
25
|
+
}, loader: ProjectLoader): unknown;
|
|
26
26
|
export declare function getAuthMatrix(args?: {
|
|
27
27
|
project?: string;
|
|
28
28
|
}): unknown;
|
|
@@ -32,13 +32,13 @@ export declare function findErrorGaps(args?: {
|
|
|
32
32
|
export declare function getTestCoverage(args: {
|
|
33
33
|
weight_by_blast_radius?: boolean;
|
|
34
34
|
project?: string;
|
|
35
|
-
}): unknown;
|
|
35
|
+
}, loader: ProjectLoader): unknown;
|
|
36
36
|
export declare function getOptimalContext(args: {
|
|
37
37
|
target_entity: string;
|
|
38
38
|
max_tokens?: number;
|
|
39
39
|
strategy?: 'bfs' | 'blast_radius';
|
|
40
40
|
project?: string;
|
|
41
|
-
}): unknown;
|
|
41
|
+
}, loader: ProjectLoader): unknown;
|
|
42
42
|
/**
|
|
43
43
|
* Estimate token cost of a code change BEFORE starting work.
|
|
44
44
|
* Computes blast radius, sums source token counts, and projects total burn.
|
|
@@ -48,7 +48,7 @@ export declare function estimateTaskCost(args: {
|
|
|
48
48
|
target_entities: string[];
|
|
49
49
|
context_budget?: number;
|
|
50
50
|
project?: string;
|
|
51
|
-
}): Promise<unknown>;
|
|
51
|
+
}, loader: ProjectLoader): Promise<unknown>;
|
|
52
52
|
/**
|
|
53
53
|
* Close the calibration feedback loop by reporting actual token usage
|
|
54
54
|
* against a prior prediction from estimate_task_cost.
|
|
@@ -65,7 +65,7 @@ export declare function reportActualBurn(args: {
|
|
|
65
65
|
action?: 'complete' | 'abandon' | 'list';
|
|
66
66
|
project?: string;
|
|
67
67
|
notes?: string;
|
|
68
|
-
}): Promise<unknown>;
|
|
68
|
+
}, loader: ProjectLoader): Promise<unknown>;
|
|
69
69
|
export declare function find_runtime_violations(args?: {
|
|
70
70
|
project?: string;
|
|
71
71
|
}): unknown;
|
|
@@ -75,7 +75,7 @@ export declare function find_ownership_violations(args?: {
|
|
|
75
75
|
export declare function query_traits(args: {
|
|
76
76
|
trait: string;
|
|
77
77
|
project?: string;
|
|
78
|
-
}): unknown;
|
|
78
|
+
}, loader: ProjectLoader): unknown;
|
|
79
79
|
export declare function simulate_mutation(args: {
|
|
80
80
|
entity_id: string;
|
|
81
81
|
mutation: {
|
|
@@ -86,11 +86,11 @@ export declare function simulate_mutation(args: {
|
|
|
86
86
|
};
|
|
87
87
|
};
|
|
88
88
|
project?: string;
|
|
89
|
-
}): unknown;
|
|
89
|
+
}, loader: ProjectLoader): unknown;
|
|
90
90
|
export declare function query_data_targets(args: {
|
|
91
91
|
target_name: string;
|
|
92
92
|
project?: string;
|
|
93
|
-
}): unknown;
|
|
93
|
+
}, loader: ProjectLoader): unknown;
|
|
94
94
|
export declare function find_exposure_leaks(args?: {
|
|
95
95
|
project?: string;
|
|
96
96
|
}): unknown;
|
|
@@ -104,4 +104,4 @@ export declare function create_symbol(args: {
|
|
|
104
104
|
layer?: string;
|
|
105
105
|
project?: string;
|
|
106
106
|
description?: string;
|
|
107
|
-
}): unknown;
|
|
107
|
+
}, loader: ProjectLoader): unknown;
|
package/dist/tools/functors.js
CHANGED
|
@@ -7,7 +7,7 @@
|
|
|
7
7
|
*/
|
|
8
8
|
import path from 'path';
|
|
9
9
|
import { computeBlastRadius } from '../graph.js';
|
|
10
|
-
import {
|
|
10
|
+
import { getGraph, validateProject, entityName, entityLayer, entitySummary, } from './index.js';
|
|
11
11
|
import { isSupabaseConfigured, insertPrediction, updateActualBurn, abandonPrediction, } from '../supabase.js';
|
|
12
12
|
// ─── Layer ordering for violation detection ──────────────────────
|
|
13
13
|
const LAYER_ORDER = {
|
|
@@ -82,13 +82,12 @@ function dominantEstimator(entities) {
|
|
|
82
82
|
return 'heuristic';
|
|
83
83
|
}
|
|
84
84
|
// ─── Tool: find_dead_code ────────────────────────────────────────
|
|
85
|
-
export function findDeadCode(args) {
|
|
86
|
-
const projErr = validateProject(args.project);
|
|
85
|
+
export function findDeadCode(args, loader) {
|
|
86
|
+
const projErr = validateProject(args.project, loader);
|
|
87
87
|
if (projErr)
|
|
88
88
|
return { error: projErr };
|
|
89
89
|
const { include_tests = false } = args;
|
|
90
|
-
const
|
|
91
|
-
const g = getGraph(args.project);
|
|
90
|
+
const g = getGraph(args.project, loader);
|
|
92
91
|
const entities = loader.getEntities(args.project);
|
|
93
92
|
// Entry points: routes, exported functions, test files, plugin registrations
|
|
94
93
|
const entryPointIds = new Set();
|
|
@@ -132,9 +131,9 @@ export function findDeadCode(args) {
|
|
|
132
131
|
}
|
|
133
132
|
}
|
|
134
133
|
// Unreachable = dead code candidates
|
|
135
|
-
let deadEntities = entities.filter(e => e.id && !reachable.has(e.id));
|
|
134
|
+
let deadEntities = entities.filter((e) => e.id && !reachable.has(e.id));
|
|
136
135
|
if (!include_tests) {
|
|
137
|
-
deadEntities = deadEntities.filter(e => entityLayer(e) !== 'test');
|
|
136
|
+
deadEntities = deadEntities.filter((e) => entityLayer(e) !== 'test');
|
|
138
137
|
}
|
|
139
138
|
// Group by layer for overview
|
|
140
139
|
const byLayer = new Map();
|
|
@@ -153,10 +152,10 @@ export function findDeadCode(args) {
|
|
|
153
152
|
}
|
|
154
153
|
// ─── Tool: find_layer_violations ─────────────────────────────────
|
|
155
154
|
export function findLayerViolations(args) {
|
|
156
|
-
const projErr = validateProject(args?.project);
|
|
155
|
+
const projErr = validateProject(args?.project, loader);
|
|
157
156
|
if (projErr)
|
|
158
157
|
return { error: projErr };
|
|
159
|
-
const g = getGraph(args?.project);
|
|
158
|
+
const g = getGraph(args?.project, loader);
|
|
160
159
|
const violations = [];
|
|
161
160
|
for (const [callerId, calleeIds] of g.callees) {
|
|
162
161
|
const callerEntity = g.entityById.get(callerId);
|
|
@@ -208,13 +207,12 @@ export function findLayerViolations(args) {
|
|
|
208
207
|
};
|
|
209
208
|
}
|
|
210
209
|
// ─── Tool: get_coupling_metrics ──────────────────────────────────
|
|
211
|
-
export function getCouplingMetrics(args) {
|
|
212
|
-
const projErr = validateProject(args.project);
|
|
210
|
+
export function getCouplingMetrics(args, loader) {
|
|
211
|
+
const projErr = validateProject(args.project, loader);
|
|
213
212
|
if (projErr)
|
|
214
213
|
return { error: projErr };
|
|
215
214
|
const { group_by = 'module' } = args;
|
|
216
|
-
const
|
|
217
|
-
const g = getGraph(args.project);
|
|
215
|
+
const g = getGraph(args.project, loader);
|
|
218
216
|
const entities = loader.getEntities(args.project);
|
|
219
217
|
// Group entities
|
|
220
218
|
const groups = new Map();
|
|
@@ -281,12 +279,11 @@ export function getCouplingMetrics(args) {
|
|
|
281
279
|
}
|
|
282
280
|
// ─── Tool: get_auth_matrix ───────────────────────────────────────
|
|
283
281
|
export function getAuthMatrix(args) {
|
|
284
|
-
const projErr = validateProject(args?.project);
|
|
282
|
+
const projErr = validateProject(args?.project, loader);
|
|
285
283
|
if (projErr)
|
|
286
284
|
return { error: projErr };
|
|
287
|
-
const loader = getLoader();
|
|
288
285
|
const entities = loader.getEntities(args?.project);
|
|
289
|
-
const apiEntities = entities.filter(e => {
|
|
286
|
+
const apiEntities = entities.filter((e) => {
|
|
290
287
|
const layer = entityLayer(e);
|
|
291
288
|
return layer === 'route' || layer === 'controller' ||
|
|
292
289
|
e.context?.exposure === 'api';
|
|
@@ -339,11 +336,10 @@ export function getAuthMatrix(args) {
|
|
|
339
336
|
}
|
|
340
337
|
// ─── Tool: find_error_gaps ───────────────────────────────────────
|
|
341
338
|
export function findErrorGaps(args) {
|
|
342
|
-
const projErr = validateProject(args?.project);
|
|
339
|
+
const projErr = validateProject(args?.project, loader);
|
|
343
340
|
if (projErr)
|
|
344
341
|
return { error: projErr };
|
|
345
|
-
const
|
|
346
|
-
const g = getGraph(args?.project);
|
|
342
|
+
const g = getGraph(args?.project, loader);
|
|
347
343
|
const entities = loader.getEntities(args?.project);
|
|
348
344
|
// Find all fallible entities (throws === true or has THROWS tag)
|
|
349
345
|
const fallibleIds = new Set();
|
|
@@ -405,13 +401,12 @@ export function findErrorGaps(args) {
|
|
|
405
401
|
};
|
|
406
402
|
}
|
|
407
403
|
// ─── Tool: get_test_coverage ─────────────────────────────────────
|
|
408
|
-
export function getTestCoverage(args) {
|
|
409
|
-
const projErr = validateProject(args.project);
|
|
404
|
+
export function getTestCoverage(args, loader) {
|
|
405
|
+
const projErr = validateProject(args.project, loader);
|
|
410
406
|
if (projErr)
|
|
411
407
|
return { error: projErr };
|
|
412
408
|
const { weight_by_blast_radius = false } = args;
|
|
413
|
-
const
|
|
414
|
-
const g = getGraph(args.project);
|
|
409
|
+
const g = getGraph(args.project, loader);
|
|
415
410
|
const entities = loader.getEntities(args.project);
|
|
416
411
|
// Partition into test and non-test entities
|
|
417
412
|
const testIds = new Set();
|
|
@@ -445,8 +440,8 @@ export function getTestCoverage(args) {
|
|
|
445
440
|
}
|
|
446
441
|
}
|
|
447
442
|
}
|
|
448
|
-
const covered = productionEntities.filter(e => exercised.has(e.id));
|
|
449
|
-
const uncovered = productionEntities.filter(e => !exercised.has(e.id));
|
|
443
|
+
const covered = productionEntities.filter((e) => exercised.has(e.id));
|
|
444
|
+
const uncovered = productionEntities.filter((e) => !exercised.has(e.id));
|
|
450
445
|
const coveragePercent = productionEntities.length > 0
|
|
451
446
|
? Math.round((covered.length / productionEntities.length) * 1000) / 10
|
|
452
447
|
: 0;
|
|
@@ -484,13 +479,12 @@ export function getTestCoverage(args) {
|
|
|
484
479
|
return result;
|
|
485
480
|
}
|
|
486
481
|
// ─── Tool: get_optimal_context ───────────────────────────────────
|
|
487
|
-
export function getOptimalContext(args) {
|
|
488
|
-
const projErr = validateProject(args.project);
|
|
482
|
+
export function getOptimalContext(args, loader) {
|
|
483
|
+
const projErr = validateProject(args.project, loader);
|
|
489
484
|
if (projErr)
|
|
490
485
|
return { error: projErr };
|
|
491
486
|
const { target_entity, max_tokens = 8000, strategy = 'bfs' } = args;
|
|
492
|
-
const
|
|
493
|
-
const g = getGraph(args.project);
|
|
487
|
+
const g = getGraph(args.project, loader);
|
|
494
488
|
const entity = loader.getEntityById(target_entity, args.project) || loader.getEntityByName(target_entity, args.project);
|
|
495
489
|
if (!entity) {
|
|
496
490
|
return { error: `Entity not found: ${target_entity}` };
|
|
@@ -605,13 +599,12 @@ export function getOptimalContext(args) {
|
|
|
605
599
|
* Computes blast radius, sums source token counts, and projects total burn.
|
|
606
600
|
* Logs prediction to Supabase when configured (for calibration feedback loop).
|
|
607
601
|
*/
|
|
608
|
-
export async function estimateTaskCost(args) {
|
|
609
|
-
const projErr = validateProject(args.project);
|
|
602
|
+
export async function estimateTaskCost(args, loader) {
|
|
603
|
+
const projErr = validateProject(args.project, loader);
|
|
610
604
|
if (projErr)
|
|
611
605
|
return { error: projErr };
|
|
612
606
|
const { target_entities, context_budget = 200000 } = args;
|
|
613
|
-
const
|
|
614
|
-
const g = getGraph(args.project);
|
|
607
|
+
const g = getGraph(args.project, loader);
|
|
615
608
|
// Resolve target entities
|
|
616
609
|
const resolvedTargets = [];
|
|
617
610
|
const unresolvedNames = [];
|
|
@@ -674,7 +667,7 @@ export async function estimateTaskCost(args) {
|
|
|
674
667
|
let outgoing = 0;
|
|
675
668
|
let incoming = 0;
|
|
676
669
|
const entities = loader.getEntities(args.project);
|
|
677
|
-
const modIds = new Set(entities.filter(e => e.context?.module === mod).map(e => e.id));
|
|
670
|
+
const modIds = new Set(entities.filter((e) => e.context?.module === mod).map(e => e.id));
|
|
678
671
|
for (const id of modIds) {
|
|
679
672
|
const calleeSet = g.callees.get(id);
|
|
680
673
|
if (calleeSet) {
|
|
@@ -772,7 +765,7 @@ export async function estimateTaskCost(args) {
|
|
|
772
765
|
* Can also abandon a prediction (task was cancelled/not completed),
|
|
773
766
|
* or list recent predictions for calibration analysis.
|
|
774
767
|
*/
|
|
775
|
-
export async function reportActualBurn(args) {
|
|
768
|
+
export async function reportActualBurn(args, loader) {
|
|
776
769
|
if (!isSupabaseConfigured()) {
|
|
777
770
|
return {
|
|
778
771
|
error: 'Supabase not configured. Set SESHAT_SUPABASE_URL and SESHAT_SUPABASE_KEY env vars.',
|
|
@@ -830,10 +823,10 @@ export async function reportActualBurn(args) {
|
|
|
830
823
|
}
|
|
831
824
|
// ─── Tool: find_runtime_violations (Runtime Context) ────────────
|
|
832
825
|
export function find_runtime_violations(args) {
|
|
833
|
-
const projErr = validateProject(args?.project);
|
|
826
|
+
const projErr = validateProject(args?.project, loader);
|
|
834
827
|
if (projErr)
|
|
835
828
|
return { error: projErr };
|
|
836
|
-
const g = getGraph(args?.project);
|
|
829
|
+
const g = getGraph(args?.project, loader);
|
|
837
830
|
const violations = [];
|
|
838
831
|
for (const [callerId, calleeIds] of g.callees) {
|
|
839
832
|
const callerEntity = g.entityById.get(callerId);
|
|
@@ -871,10 +864,9 @@ export function find_runtime_violations(args) {
|
|
|
871
864
|
}
|
|
872
865
|
// ─── Tool: find_ownership_violations (Ownership & Lifetimes) ─────
|
|
873
866
|
export function find_ownership_violations(args) {
|
|
874
|
-
const projErr = validateProject(args?.project);
|
|
867
|
+
const projErr = validateProject(args?.project, loader);
|
|
875
868
|
if (projErr)
|
|
876
869
|
return { error: projErr };
|
|
877
|
-
const loader = getLoader();
|
|
878
870
|
const entities = loader.getEntities(args?.project);
|
|
879
871
|
const violations = [];
|
|
880
872
|
for (const e of entities) {
|
|
@@ -911,19 +903,18 @@ export function find_ownership_violations(args) {
|
|
|
911
903
|
};
|
|
912
904
|
}
|
|
913
905
|
// ─── Tool: query_traits (Trait Search) ───────────────────────────
|
|
914
|
-
export function query_traits(args) {
|
|
915
|
-
const projErr = validateProject(args.project);
|
|
906
|
+
export function query_traits(args, loader) {
|
|
907
|
+
const projErr = validateProject(args.project, loader);
|
|
916
908
|
if (projErr)
|
|
917
909
|
return { error: projErr };
|
|
918
910
|
const target = args.trait.toLowerCase();
|
|
919
|
-
const loader = getLoader();
|
|
920
911
|
const entities = loader.getEntities(args.project);
|
|
921
|
-
const results = entities.filter(e => {
|
|
912
|
+
const results = entities.filter((e) => {
|
|
922
913
|
if (!e.traits)
|
|
923
914
|
return false;
|
|
924
915
|
// Handle array of strings [ 'asyncContext', 'generator' ]
|
|
925
916
|
if (Array.isArray(e.traits)) {
|
|
926
|
-
return e.traits.some(t => t.toLowerCase().includes(target));
|
|
917
|
+
return e.traits.some((t) => t.toLowerCase().includes(target));
|
|
927
918
|
}
|
|
928
919
|
// Handle structured traits { self: { fallible: true } }
|
|
929
920
|
if (typeof e.traits === 'object') {
|
|
@@ -955,12 +946,11 @@ export function query_traits(args) {
|
|
|
955
946
|
};
|
|
956
947
|
}
|
|
957
948
|
// ─── Tool: simulate_mutation (Impact Simulator) ──────────────────
|
|
958
|
-
export function simulate_mutation(args) {
|
|
959
|
-
const projErr = validateProject(args.project);
|
|
949
|
+
export function simulate_mutation(args, loader) {
|
|
950
|
+
const projErr = validateProject(args.project, loader);
|
|
960
951
|
if (projErr)
|
|
961
952
|
return { error: projErr };
|
|
962
|
-
const
|
|
963
|
-
const g = getGraph(args.project);
|
|
953
|
+
const g = getGraph(args.project, loader);
|
|
964
954
|
const targetEntity = loader.getEntityById(args.entity_id, args.project)
|
|
965
955
|
|| loader.getEntityByName(args.entity_id, args.project);
|
|
966
956
|
if (!targetEntity) {
|
|
@@ -1036,11 +1026,10 @@ export function simulate_mutation(args) {
|
|
|
1036
1026
|
};
|
|
1037
1027
|
}
|
|
1038
1028
|
// ─── Tool: query_data_targets (Data Flow Analysis) ──────────────
|
|
1039
|
-
export function query_data_targets(args) {
|
|
1040
|
-
const projErr = validateProject(args.project);
|
|
1029
|
+
export function query_data_targets(args, loader) {
|
|
1030
|
+
const projErr = validateProject(args.project, loader);
|
|
1041
1031
|
if (projErr)
|
|
1042
1032
|
return { error: projErr };
|
|
1043
|
-
const loader = getLoader();
|
|
1044
1033
|
const entities = loader.getEntities(args.project);
|
|
1045
1034
|
const target = args.target_name.toLowerCase();
|
|
1046
1035
|
const readers = [];
|
|
@@ -1051,24 +1040,24 @@ export function query_data_targets(args) {
|
|
|
1051
1040
|
let isReader = false;
|
|
1052
1041
|
let isWriter = false;
|
|
1053
1042
|
// Check tables
|
|
1054
|
-
if (Array.isArray(e.data.tables) && e.data.tables.some(t => String(t).toLowerCase() === target)) {
|
|
1043
|
+
if (Array.isArray(e.data.tables) && e.data.tables.some((t) => String(t).toLowerCase() === target)) {
|
|
1055
1044
|
// By default, if they touch a table but don't specify mutation, we assume read
|
|
1056
1045
|
isReader = true;
|
|
1057
1046
|
}
|
|
1058
1047
|
// Check inputs (sources)
|
|
1059
1048
|
if (Array.isArray(e.data.inputs)) {
|
|
1060
|
-
if (e.data.inputs.some(i => i && typeof i === 'object' && String(i.name || i.source).toLowerCase() === target)) {
|
|
1049
|
+
if (e.data.inputs.some((i) => i && typeof i === 'object' && String(i.name || i.source).toLowerCase() === target)) {
|
|
1061
1050
|
isReader = true;
|
|
1062
1051
|
}
|
|
1063
1052
|
}
|
|
1064
1053
|
else if (Array.isArray(e.data.sources)) {
|
|
1065
|
-
if (e.data.sources.some(s => String(s).toLowerCase() === target)) {
|
|
1054
|
+
if (e.data.sources.some((s) => String(s).toLowerCase() === target)) {
|
|
1066
1055
|
isReader = true;
|
|
1067
1056
|
}
|
|
1068
1057
|
}
|
|
1069
1058
|
// Check mutations
|
|
1070
1059
|
if (Array.isArray(e.data.mutations)) {
|
|
1071
|
-
if (e.data.mutations.some(m => m && typeof m === 'object' && String(m.target).toLowerCase() === target)) {
|
|
1060
|
+
if (e.data.mutations.some((m) => m && typeof m === 'object' && String(m.target).toLowerCase() === target)) {
|
|
1072
1061
|
isWriter = true;
|
|
1073
1062
|
}
|
|
1074
1063
|
}
|
|
@@ -1091,10 +1080,10 @@ export function query_data_targets(args) {
|
|
|
1091
1080
|
}
|
|
1092
1081
|
// ─── Tool: find_exposure_leaks (Architectural Visibility) ───────
|
|
1093
1082
|
export function find_exposure_leaks(args) {
|
|
1094
|
-
const projErr = validateProject(args?.project);
|
|
1083
|
+
const projErr = validateProject(args?.project, loader);
|
|
1095
1084
|
if (projErr)
|
|
1096
1085
|
return { error: projErr };
|
|
1097
|
-
const g = getGraph(args?.project);
|
|
1086
|
+
const g = getGraph(args?.project, loader);
|
|
1098
1087
|
const leaks = [];
|
|
1099
1088
|
for (const [callerId, calleeIds] of g.callees) {
|
|
1100
1089
|
const callerEntity = g.entityById.get(callerId);
|
|
@@ -1126,10 +1115,9 @@ export function find_exposure_leaks(args) {
|
|
|
1126
1115
|
// ─── Tool: find_semantic_clones (Logic Analysis) ────────────────
|
|
1127
1116
|
import { createHash } from 'crypto';
|
|
1128
1117
|
export function find_semantic_clones(args) {
|
|
1129
|
-
const projErr = validateProject(args?.project);
|
|
1118
|
+
const projErr = validateProject(args?.project, loader);
|
|
1130
1119
|
if (projErr)
|
|
1131
1120
|
return { error: projErr };
|
|
1132
|
-
const loader = getLoader();
|
|
1133
1121
|
const entities = loader.getEntities(args?.project);
|
|
1134
1122
|
const { min_complexity = 5 } = args || {};
|
|
1135
1123
|
const logicHashes = new Map();
|
|
@@ -1173,11 +1161,10 @@ export function find_semantic_clones(args) {
|
|
|
1173
1161
|
};
|
|
1174
1162
|
}
|
|
1175
1163
|
// ─── Tool: create_symbol (Virtual Entry) ─────────────────────────
|
|
1176
|
-
export function create_symbol(args) {
|
|
1177
|
-
const projErr = validateProject(args.project);
|
|
1164
|
+
export function create_symbol(args, loader) {
|
|
1165
|
+
const projErr = validateProject(args.project, loader);
|
|
1178
1166
|
if (projErr)
|
|
1179
1167
|
return { error: projErr };
|
|
1180
|
-
const loader = getLoader();
|
|
1181
1168
|
// Create a skeleton JSTF-T entity
|
|
1182
1169
|
const virtualEntity = {
|
|
1183
1170
|
id: args.id,
|
package/dist/tools/index.d.ts
CHANGED
|
@@ -8,17 +8,14 @@
|
|
|
8
8
|
* `project` parameter. In multi-project mode, `project` is required.
|
|
9
9
|
*/
|
|
10
10
|
import type { JstfEntity } from '../types.js';
|
|
11
|
-
import { MultiLoader } from '../loader.js';
|
|
12
11
|
import { type CallGraph } from '../graph.js';
|
|
13
|
-
export declare function
|
|
14
|
-
export declare function getLoader(): MultiLoader;
|
|
15
|
-
export declare function getGraph(project?: string): CallGraph;
|
|
12
|
+
export declare function getGraph(project: string | undefined, loader: ProjectLoader): CallGraph;
|
|
16
13
|
/**
|
|
17
14
|
* Validate project param. Returns error string if invalid, null if OK.
|
|
18
15
|
* In single-project mode, project is optional (defaults to the only project).
|
|
19
16
|
* In multi-project mode, project is required.
|
|
20
17
|
*/
|
|
21
|
-
export declare function validateProject(project
|
|
18
|
+
export declare function validateProject(project: string | undefined, loader: ProjectLoader): string | null;
|
|
22
19
|
export declare function entityName(e: JstfEntity): string;
|
|
23
20
|
export declare function entityLayer(e: JstfEntity): string;
|
|
24
21
|
export declare function entitySummary(e: JstfEntity): Record<string, unknown>;
|
|
@@ -35,34 +32,34 @@ export declare function queryEntities(args: {
|
|
|
35
32
|
module?: string;
|
|
36
33
|
language?: string;
|
|
37
34
|
limit?: number;
|
|
38
|
-
}): unknown
|
|
35
|
+
}, loader: ProjectLoader): Promise<unknown>;
|
|
39
36
|
export declare function getEntity(args: {
|
|
40
37
|
id: string;
|
|
41
38
|
project?: string;
|
|
42
|
-
}): unknown;
|
|
39
|
+
}, loader: ProjectLoader): unknown;
|
|
43
40
|
export declare function getDependencies(args: {
|
|
44
41
|
entity_id: string;
|
|
45
42
|
direction?: 'callers' | 'callees' | 'both';
|
|
46
43
|
depth?: number;
|
|
47
44
|
project?: string;
|
|
48
|
-
}): unknown;
|
|
45
|
+
}, loader: ProjectLoader): unknown;
|
|
49
46
|
export declare function collectTransitive(adjacency: Map<string, Set<string>>, startId: string, maxDepth: number): string[];
|
|
50
47
|
export declare function getDataFlow(args: {
|
|
51
48
|
entity_id: string;
|
|
52
49
|
project?: string;
|
|
53
|
-
}): unknown;
|
|
50
|
+
}, loader: ProjectLoader): unknown;
|
|
54
51
|
export declare function findByConstraint(args: {
|
|
55
52
|
constraint: string;
|
|
56
53
|
project?: string;
|
|
57
|
-
}): unknown;
|
|
54
|
+
}, loader: ProjectLoader): unknown;
|
|
58
55
|
export declare function getBlastRadius(args: {
|
|
59
56
|
entity_ids: string[];
|
|
60
57
|
project?: string;
|
|
61
|
-
}): unknown;
|
|
58
|
+
}, loader: ProjectLoader): unknown;
|
|
62
59
|
export declare function listModules(args: {
|
|
63
60
|
group_by?: 'layer' | 'module' | 'file' | 'language';
|
|
64
61
|
project?: string;
|
|
65
|
-
}): unknown;
|
|
66
|
-
export declare function getTopology(args
|
|
62
|
+
}, loader: ProjectLoader): unknown;
|
|
63
|
+
export declare function getTopology(args: {
|
|
67
64
|
project?: string;
|
|
68
|
-
}): unknown;
|
|
65
|
+
} | undefined, loader: ProjectLoader): unknown;
|
package/dist/tools/index.js
CHANGED
|
@@ -8,29 +8,15 @@
|
|
|
8
8
|
* `project` parameter. In multi-project mode, `project` is required.
|
|
9
9
|
*/
|
|
10
10
|
import { buildCallGraph, computeBlastRadius } from '../graph.js';
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
let graphCache = new Map();
|
|
14
|
-
export function initTools(multiLoader) {
|
|
15
|
-
loader = multiLoader;
|
|
16
|
-
graphCache = new Map();
|
|
17
|
-
}
|
|
18
|
-
export function getLoader() {
|
|
19
|
-
return loader;
|
|
20
|
-
}
|
|
21
|
-
export function getGraph(project) {
|
|
22
|
-
const key = project || '__default__';
|
|
23
|
-
if (!graphCache.has(key)) {
|
|
24
|
-
graphCache.set(key, buildCallGraph(loader.getEntities(project)));
|
|
25
|
-
}
|
|
26
|
-
return graphCache.get(key);
|
|
11
|
+
export function getGraph(project, loader) {
|
|
12
|
+
return buildCallGraph(loader.getEntities(project));
|
|
27
13
|
}
|
|
28
14
|
/**
|
|
29
15
|
* Validate project param. Returns error string if invalid, null if OK.
|
|
30
16
|
* In single-project mode, project is optional (defaults to the only project).
|
|
31
17
|
* In multi-project mode, project is required.
|
|
32
18
|
*/
|
|
33
|
-
export function validateProject(project) {
|
|
19
|
+
export function validateProject(project, loader) {
|
|
34
20
|
if (!loader.isMultiProject())
|
|
35
21
|
return null; // single project, always OK
|
|
36
22
|
if (!project) {
|
|
@@ -155,7 +141,7 @@ export function normalizeConstraints(constraints) {
|
|
|
155
141
|
export function constraintMatches(constraints, target) {
|
|
156
142
|
// First check normalized tags
|
|
157
143
|
const tags = normalizeConstraints(constraints);
|
|
158
|
-
if (tags.some(t => t.toUpperCase().includes(target.toUpperCase())))
|
|
144
|
+
if (tags.some((t) => t.toUpperCase().includes(target.toUpperCase())))
|
|
159
145
|
return true;
|
|
160
146
|
// Also search raw constraint values for substring match
|
|
161
147
|
if (constraints && typeof constraints === 'object' && !Array.isArray(constraints)) {
|
|
@@ -166,42 +152,40 @@ export function constraintMatches(constraints, target) {
|
|
|
166
152
|
return false;
|
|
167
153
|
}
|
|
168
154
|
// ─── Tool: query_entities ─────────────────────────────────────────
|
|
169
|
-
export function queryEntities(args) {
|
|
170
|
-
const
|
|
171
|
-
if (
|
|
172
|
-
return { error:
|
|
173
|
-
const { query, layer, module, language, limit = 50 } = args;
|
|
174
|
-
let results = loader.getEntities(args.project);
|
|
175
|
-
if (layer) {
|
|
176
|
-
results = results.filter(e => entityLayer(e).toLowerCase() === layer.toLowerCase());
|
|
177
|
-
}
|
|
178
|
-
if (module) {
|
|
179
|
-
results = results.filter(e => e.context?.module?.toLowerCase().includes(module.toLowerCase()));
|
|
155
|
+
export async function queryEntities(args, loader) {
|
|
156
|
+
const apiKey = process.env.SESHAT_API_KEY;
|
|
157
|
+
if (!apiKey) {
|
|
158
|
+
return { error: 'SESHAT_API_KEY environment variable is missing. You must provide an API key to use Ptah Cloud tools.' };
|
|
180
159
|
}
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
const
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
160
|
+
// We are hardcoding the project_hash to 'seshat-fabric' for this local test,
|
|
161
|
+
// but in production the MCP would pass args.project or read from the manifest.
|
|
162
|
+
const project_hash = args.project || 'seshat-fabric';
|
|
163
|
+
try {
|
|
164
|
+
const res = await fetch('http://localhost:3001/api/mcp/execute', {
|
|
165
|
+
method: 'POST',
|
|
166
|
+
headers: {
|
|
167
|
+
'Content-Type': 'application/json',
|
|
168
|
+
'x-api-key': apiKey
|
|
169
|
+
},
|
|
170
|
+
body: JSON.stringify({
|
|
171
|
+
tool: 'query_entities',
|
|
172
|
+
project_hash: project_hash,
|
|
173
|
+
args
|
|
174
|
+
})
|
|
192
175
|
});
|
|
176
|
+
if (!res.ok) {
|
|
177
|
+
const errorText = await res.text();
|
|
178
|
+
return { error: `Cloud API Error (${res.status}): ${errorText}` };
|
|
179
|
+
}
|
|
180
|
+
return await res.json();
|
|
181
|
+
}
|
|
182
|
+
catch (error) {
|
|
183
|
+
return { error: `Failed to connect to Ptah Cloud: ${error.message}` };
|
|
193
184
|
}
|
|
194
|
-
const total = results.length;
|
|
195
|
-
const entities = results.slice(0, limit).map(entitySummary);
|
|
196
|
-
return {
|
|
197
|
-
total,
|
|
198
|
-
showing: entities.length,
|
|
199
|
-
entities,
|
|
200
|
-
};
|
|
201
185
|
}
|
|
202
186
|
// ─── Tool: get_entity ─────────────────────────────────────────────
|
|
203
|
-
export function getEntity(args) {
|
|
204
|
-
const projErr = validateProject(args.project);
|
|
187
|
+
export function getEntity(args, loader) {
|
|
188
|
+
const projErr = validateProject(args.project, loader);
|
|
205
189
|
if (projErr)
|
|
206
190
|
return { error: projErr };
|
|
207
191
|
const entity = loader.getEntityById(args.id, args.project) || loader.getEntityByName(args.id, args.project);
|
|
@@ -226,12 +210,12 @@ export function getEntity(args) {
|
|
|
226
210
|
};
|
|
227
211
|
}
|
|
228
212
|
// ─── Tool: get_dependencies ───────────────────────────────────────
|
|
229
|
-
export function getDependencies(args) {
|
|
230
|
-
const projErr = validateProject(args.project);
|
|
213
|
+
export function getDependencies(args, loader) {
|
|
214
|
+
const projErr = validateProject(args.project, loader);
|
|
231
215
|
if (projErr)
|
|
232
216
|
return { error: projErr };
|
|
233
217
|
const { entity_id, direction = 'both', depth = 2 } = args;
|
|
234
|
-
const g = getGraph(args.project);
|
|
218
|
+
const g = getGraph(args.project, loader);
|
|
235
219
|
const entity = loader.getEntityById(entity_id, args.project) || loader.getEntityByName(entity_id, args.project);
|
|
236
220
|
if (!entity) {
|
|
237
221
|
return { error: `Entity not found: ${entity_id}` };
|
|
@@ -282,8 +266,8 @@ export function collectTransitive(adjacency, startId, maxDepth) {
|
|
|
282
266
|
return [...visited];
|
|
283
267
|
}
|
|
284
268
|
// ─── Tool: get_data_flow ──────────────────────────────────────────
|
|
285
|
-
export function getDataFlow(args) {
|
|
286
|
-
const projErr = validateProject(args.project);
|
|
269
|
+
export function getDataFlow(args, loader) {
|
|
270
|
+
const projErr = validateProject(args.project, loader);
|
|
287
271
|
if (projErr)
|
|
288
272
|
return { error: projErr };
|
|
289
273
|
const entity = loader.getEntityById(args.entity_id, args.project) || loader.getEntityByName(args.entity_id, args.project);
|
|
@@ -298,12 +282,12 @@ export function getDataFlow(args) {
|
|
|
298
282
|
};
|
|
299
283
|
}
|
|
300
284
|
// ─── Tool: find_by_constraint ─────────────────────────────────────
|
|
301
|
-
export function findByConstraint(args) {
|
|
302
|
-
const projErr = validateProject(args.project);
|
|
285
|
+
export function findByConstraint(args, loader) {
|
|
286
|
+
const projErr = validateProject(args.project, loader);
|
|
303
287
|
if (projErr)
|
|
304
288
|
return { error: projErr };
|
|
305
289
|
const target = args.constraint;
|
|
306
|
-
const results = loader.getEntities(args.project).filter(e => constraintMatches(e.constraints, target));
|
|
290
|
+
const results = loader.getEntities(args.project).filter((e) => constraintMatches(e.constraints, target));
|
|
307
291
|
return {
|
|
308
292
|
constraint: args.constraint,
|
|
309
293
|
total: results.length,
|
|
@@ -311,11 +295,11 @@ export function findByConstraint(args) {
|
|
|
311
295
|
};
|
|
312
296
|
}
|
|
313
297
|
// ─── Tool: get_blast_radius ───────────────────────────────────────
|
|
314
|
-
export function getBlastRadius(args) {
|
|
315
|
-
const projErr = validateProject(args.project);
|
|
298
|
+
export function getBlastRadius(args, loader) {
|
|
299
|
+
const projErr = validateProject(args.project, loader);
|
|
316
300
|
if (projErr)
|
|
317
301
|
return { error: projErr };
|
|
318
|
-
const g = getGraph(args.project);
|
|
302
|
+
const g = getGraph(args.project, loader);
|
|
319
303
|
// Resolve names to IDs
|
|
320
304
|
const resolvedIds = new Set();
|
|
321
305
|
const notFound = [];
|
|
@@ -348,8 +332,8 @@ export function getBlastRadius(args) {
|
|
|
348
332
|
};
|
|
349
333
|
}
|
|
350
334
|
// ─── Tool: list_modules ───────────────────────────────────────────
|
|
351
|
-
export function listModules(args) {
|
|
352
|
-
const projErr = validateProject(args.project);
|
|
335
|
+
export function listModules(args, loader) {
|
|
336
|
+
const projErr = validateProject(args.project, loader);
|
|
353
337
|
if (projErr)
|
|
354
338
|
return { error: projErr };
|
|
355
339
|
const { group_by = 'layer' } = args;
|
|
@@ -385,8 +369,8 @@ export function listModules(args) {
|
|
|
385
369
|
};
|
|
386
370
|
}
|
|
387
371
|
// ─── Tool: get_topology ───────────────────────────────────────────
|
|
388
|
-
export function getTopology(args) {
|
|
389
|
-
const projErr = validateProject(args?.project);
|
|
372
|
+
export function getTopology(args, loader) {
|
|
373
|
+
const projErr = validateProject(args?.project, loader);
|
|
390
374
|
if (projErr)
|
|
391
375
|
return { error: projErr };
|
|
392
376
|
const topology = loader.getTopology(args?.project);
|
package/dist/types.d.ts
CHANGED
|
@@ -158,3 +158,17 @@ export interface ProjectInfo {
|
|
|
158
158
|
extractedAt: string;
|
|
159
159
|
layers: Record<string, number>;
|
|
160
160
|
}
|
|
161
|
+
export interface ProjectLoader {
|
|
162
|
+
getEntities(project?: string): JstfEntity[];
|
|
163
|
+
getTopology(project?: string): Topology | null;
|
|
164
|
+
getManifest(project?: string): Manifest | null;
|
|
165
|
+
getEntityById(id: string, project?: string): JstfEntity | undefined;
|
|
166
|
+
getEntityByName(name: string, project?: string): JstfEntity | undefined;
|
|
167
|
+
getProjectNames(): string[];
|
|
168
|
+
getProjectInfo(): ProjectInfo[];
|
|
169
|
+
isMultiProject(): boolean;
|
|
170
|
+
isLoaded(): boolean;
|
|
171
|
+
hasProject(name: string): boolean;
|
|
172
|
+
registerVirtualEntity(entity: JstfEntity, project?: string): void;
|
|
173
|
+
totalEntities(): number;
|
|
174
|
+
}
|
package/package.json
CHANGED