@papyruslabsai/seshat-mcp 0.20.0 → 0.20.1
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/LICENSE +21 -0
- package/README.md +87 -0
- package/package.json +41 -48
- package/dist/bootstrap.d.ts +0 -29
- package/dist/bootstrap.js +0 -190
- package/dist/graph.d.ts +0 -42
- package/dist/graph.js +0 -272
- package/dist/index.d.ts +0 -9
- package/dist/loader.d.ts +0 -62
- package/dist/loader.js +0 -264
- package/dist/supabase.d.ts +0 -99
- package/dist/supabase.js +0 -132
- package/dist/tools/dbops.d.ts +0 -24
- package/dist/tools/dbops.js +0 -78
- package/dist/tools/diff.d.ts +0 -28
- package/dist/tools/diff.js +0 -604
- package/dist/tools/functors.d.ts +0 -150
- package/dist/tools/functors.js +0 -1727
- package/dist/tools/index.d.ts +0 -66
- package/dist/tools/index.js +0 -389
- package/dist/types.d.ts +0 -174
- package/dist/types.js +0 -8
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 Papyrus Labs
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/README.md
ADDED
|
@@ -0,0 +1,87 @@
|
|
|
1
|
+
# Seshat — structural code intelligence for AI agents
|
|
2
|
+
|
|
3
|
+
**Your agent reconstructs your codebase from likelihood. Seshat compiles it.**
|
|
4
|
+
|
|
5
|
+
Seshat turns a repository into a typed symbol graph (every function, class, route, and
|
|
6
|
+
table, with its *real* dependency edges, data flow, and constraints) and serves it to your
|
|
7
|
+
agent over MCP. So before your agent edits a function, it can ask what will actually break
|
|
8
|
+
instead of guessing.
|
|
9
|
+
|
|
10
|
+
Backed by a compiled intermediate representation, not text search or embeddings: if Seshat
|
|
11
|
+
says a function has three callers, it has exactly three.
|
|
12
|
+
|
|
13
|
+
## Why
|
|
14
|
+
|
|
15
|
+
AI coding agents are fast but structurally blind. When an agent changes one function, it
|
|
16
|
+
often cannot see everything that depends on it, so it silently breaks callers it never
|
|
17
|
+
looked at. A large share of AI-introduced regressions come from exactly this. Seshat gives
|
|
18
|
+
the agent the map.
|
|
19
|
+
|
|
20
|
+
## Try it first (no install, no login)
|
|
21
|
+
|
|
22
|
+
Paste any public repo at **https://seshat.papyruslabs.ai/try** and watch it trace what a
|
|
23
|
+
change would break.
|
|
24
|
+
|
|
25
|
+
## Install
|
|
26
|
+
|
|
27
|
+
```
|
|
28
|
+
npx -y @papyruslabsai/seshat-mcp setup <your-key>
|
|
29
|
+
```
|
|
30
|
+
|
|
31
|
+
Get a free key at **https://seshat.papyruslabs.ai** (first extraction is free). The setup
|
|
32
|
+
command writes your MCP config and stores the key.
|
|
33
|
+
|
|
34
|
+
Or configure manually (Claude Code, Cursor, or any MCP client):
|
|
35
|
+
|
|
36
|
+
```json
|
|
37
|
+
{
|
|
38
|
+
"mcpServers": {
|
|
39
|
+
"seshat": {
|
|
40
|
+
"command": "npx",
|
|
41
|
+
"args": ["-y", "@papyruslabsai/seshat-mcp"],
|
|
42
|
+
"env": { "SESHAT_API_KEY": "your-key" }
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
```
|
|
47
|
+
|
|
48
|
+
## Tools
|
|
49
|
+
|
|
50
|
+
Point your agent at a repo with `sync_project`, then it investigates the way a senior
|
|
51
|
+
engineer does: orient, trace, verify.
|
|
52
|
+
|
|
53
|
+
**Orient**
|
|
54
|
+
- `list_projects` — what is synced
|
|
55
|
+
- `list_modules` — how the codebase is organized, by layer or module
|
|
56
|
+
- `query_entities` — find functions, classes, and routes by name, layer, or module
|
|
57
|
+
- `find_entry_points` — routes, exports, and the public API surface
|
|
58
|
+
|
|
59
|
+
**Investigate a symbol**
|
|
60
|
+
- `get_entity` — signature, callers, callees, data flow, side effects, and tables touched
|
|
61
|
+
- `get_dependencies` — the real call chain, callers and callees
|
|
62
|
+
- `get_blast_radius` — everything that breaks if you change it, transitively
|
|
63
|
+
- `get_data_flow` — what a function reads, returns, and mutates
|
|
64
|
+
- `get_optimal_context` — the minimal, ranked set of files to read before editing
|
|
65
|
+
- `find_by_constraint` — every function that touches a given table (or carries a given trait)
|
|
66
|
+
- `find_dead_code` — unreachable symbols, safe to delete
|
|
67
|
+
|
|
68
|
+
Every answer comes from the compiled graph and discloses the coverage behind it.
|
|
69
|
+
|
|
70
|
+
> History and cross-cutting audit tools (hotspots, co-change clusters, lineage, topology,
|
|
71
|
+
> semantic clones) are being hardened and will be added to this list as they land.
|
|
72
|
+
|
|
73
|
+
## Privacy
|
|
74
|
+
|
|
75
|
+
Analysis runs in the Papyrus Labs cloud, by design: the compiled graph is the product's
|
|
76
|
+
moat, and keeping extraction server-side is how that stays protected. Public repos are
|
|
77
|
+
cloned from GitHub; private repos require you to connect your GitHub account. Source is
|
|
78
|
+
processed to build the graph and cached to serve queries. See the privacy policy at
|
|
79
|
+
seshat.papyruslabs.ai.
|
|
80
|
+
|
|
81
|
+
## Pricing
|
|
82
|
+
|
|
83
|
+
First extraction is free. $0.03 per query after a free tier; a typical investigation is 5
|
|
84
|
+
to 15 queries. Details at https://seshat.papyruslabs.ai.
|
|
85
|
+
|
|
86
|
+
MIT licensed server. Named for the goddess who kept the records, built so your agent can
|
|
87
|
+
read them.
|
package/package.json
CHANGED
|
@@ -1,48 +1,41 @@
|
|
|
1
|
-
{
|
|
2
|
-
"name": "@papyruslabsai/seshat-mcp",
|
|
3
|
-
"version": "0.20.
|
|
4
|
-
"
|
|
5
|
-
"
|
|
6
|
-
"
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
"
|
|
11
|
-
|
|
12
|
-
"
|
|
13
|
-
"
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
"
|
|
20
|
-
"
|
|
21
|
-
},
|
|
22
|
-
"
|
|
23
|
-
"
|
|
24
|
-
},
|
|
25
|
-
"
|
|
26
|
-
"
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
"
|
|
31
|
-
},
|
|
32
|
-
"
|
|
33
|
-
"
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
"
|
|
37
|
-
"
|
|
38
|
-
"
|
|
39
|
-
|
|
40
|
-
"
|
|
41
|
-
|
|
42
|
-
"semantic",
|
|
43
|
-
"code-analysis",
|
|
44
|
-
"seshat",
|
|
45
|
-
"static-analysis"
|
|
46
|
-
],
|
|
47
|
-
"license": "MIT"
|
|
48
|
-
}
|
|
1
|
+
{
|
|
2
|
+
"name": "@papyruslabsai/seshat-mcp",
|
|
3
|
+
"version": "0.20.1",
|
|
4
|
+
"mcpName": "ai.papyruslabs/seshat-mcp",
|
|
5
|
+
"description": "Structural code intelligence for AI agents: a compiled typed symbol graph over MCP.",
|
|
6
|
+
"type": "module",
|
|
7
|
+
"bin": {
|
|
8
|
+
"seshat-mcp": "./dist/index.js"
|
|
9
|
+
},
|
|
10
|
+
"main": "./dist/index.js",
|
|
11
|
+
"scripts": {
|
|
12
|
+
"build": "tsc",
|
|
13
|
+
"start": "node dist/index.js"
|
|
14
|
+
},
|
|
15
|
+
"dependencies": {
|
|
16
|
+
"@modelcontextprotocol/sdk": "^1.12.1"
|
|
17
|
+
},
|
|
18
|
+
"devDependencies": {
|
|
19
|
+
"typescript": "^5.5.0",
|
|
20
|
+
"@types/node": "^20.0.0"
|
|
21
|
+
},
|
|
22
|
+
"engines": {
|
|
23
|
+
"node": ">=20"
|
|
24
|
+
},
|
|
25
|
+
"files": [
|
|
26
|
+
"dist/"
|
|
27
|
+
],
|
|
28
|
+
"repository": {
|
|
29
|
+
"type": "git",
|
|
30
|
+
"url": "https://github.com/papyruslabs-ai/seshat-mcp.git"
|
|
31
|
+
},
|
|
32
|
+
"keywords": [
|
|
33
|
+
"mcp",
|
|
34
|
+
"code-intelligence",
|
|
35
|
+
"structural-analysis",
|
|
36
|
+
"blast-radius",
|
|
37
|
+
"ai-agents",
|
|
38
|
+
"seshat"
|
|
39
|
+
],
|
|
40
|
+
"license": "MIT"
|
|
41
|
+
}
|
package/dist/bootstrap.d.ts
DELETED
|
@@ -1,29 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Auto-Bootstrap — extract a .seshat/ bundle on first run.
|
|
3
|
-
*
|
|
4
|
-
* When the MCP server starts and finds no .seshat/_bundle.json, this module
|
|
5
|
-
* spawns `npx @papyruslabsai/seshat-extract` to generate one on the fly.
|
|
6
|
-
*
|
|
7
|
-
* CI continues to regenerate the bundle on every merge to main, overwriting
|
|
8
|
-
* the bootstrap result. The bootstrap only runs when .seshat/ doesn't exist.
|
|
9
|
-
*
|
|
10
|
-
* Env vars:
|
|
11
|
-
* SESHAT_BOOTSTRAP_TIMEOUT — spawn timeout in ms (default: 120000)
|
|
12
|
-
*/
|
|
13
|
-
export interface BootstrapResult {
|
|
14
|
-
success: boolean;
|
|
15
|
-
entityCount: number;
|
|
16
|
-
languages: string[];
|
|
17
|
-
durationMs: number;
|
|
18
|
-
error?: string;
|
|
19
|
-
}
|
|
20
|
-
/**
|
|
21
|
-
* Auto-bootstrap: extract a .seshat/ bundle for the given project directory.
|
|
22
|
-
*
|
|
23
|
-
* Spawns `npx @papyruslabsai/seshat-extract <dir> <dir>/.seshat <name>`
|
|
24
|
-
* and waits for it to complete.
|
|
25
|
-
*
|
|
26
|
-
* @param projectDir - Absolute path to the project root
|
|
27
|
-
* @returns Bootstrap result with entity count, languages, duration, and any error
|
|
28
|
-
*/
|
|
29
|
-
export declare function bootstrap(projectDir: string): Promise<BootstrapResult>;
|
package/dist/bootstrap.js
DELETED
|
@@ -1,190 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Auto-Bootstrap — extract a .seshat/ bundle on first run.
|
|
3
|
-
*
|
|
4
|
-
* When the MCP server starts and finds no .seshat/_bundle.json, this module
|
|
5
|
-
* spawns `npx @papyruslabsai/seshat-extract` to generate one on the fly.
|
|
6
|
-
*
|
|
7
|
-
* CI continues to regenerate the bundle on every merge to main, overwriting
|
|
8
|
-
* the bootstrap result. The bootstrap only runs when .seshat/ doesn't exist.
|
|
9
|
-
*
|
|
10
|
-
* Env vars:
|
|
11
|
-
* SESHAT_BOOTSTRAP_TIMEOUT — spawn timeout in ms (default: 120000)
|
|
12
|
-
*/
|
|
13
|
-
import { spawn } from 'child_process';
|
|
14
|
-
import fs from 'fs';
|
|
15
|
-
import path from 'path';
|
|
16
|
-
import { execSync } from 'child_process';
|
|
17
|
-
// Project marker files — presence of any means "this is a code project"
|
|
18
|
-
const PROJECT_MARKERS = [
|
|
19
|
-
'.git',
|
|
20
|
-
'package.json',
|
|
21
|
-
'go.mod',
|
|
22
|
-
'Cargo.toml',
|
|
23
|
-
'pyproject.toml',
|
|
24
|
-
'pom.xml',
|
|
25
|
-
'build.gradle',
|
|
26
|
-
'Makefile',
|
|
27
|
-
'CMakeLists.txt',
|
|
28
|
-
];
|
|
29
|
-
/**
|
|
30
|
-
* Check if a directory looks like a code project.
|
|
31
|
-
*/
|
|
32
|
-
function isCodeProject(dir) {
|
|
33
|
-
for (const marker of PROJECT_MARKERS) {
|
|
34
|
-
const markerPath = path.join(dir, marker);
|
|
35
|
-
if (fs.existsSync(markerPath))
|
|
36
|
-
return true;
|
|
37
|
-
}
|
|
38
|
-
// Also check for *.sln files (C# solutions)
|
|
39
|
-
try {
|
|
40
|
-
const entries = fs.readdirSync(dir);
|
|
41
|
-
if (entries.some(e => e.endsWith('.sln')))
|
|
42
|
-
return true;
|
|
43
|
-
}
|
|
44
|
-
catch { }
|
|
45
|
-
return false;
|
|
46
|
-
}
|
|
47
|
-
/**
|
|
48
|
-
* Infer a project name from the directory.
|
|
49
|
-
* Priority: package.json name → git remote → directory basename
|
|
50
|
-
*/
|
|
51
|
-
function inferProjectName(dir) {
|
|
52
|
-
// 1. Try package.json
|
|
53
|
-
try {
|
|
54
|
-
const pkgPath = path.join(dir, 'package.json');
|
|
55
|
-
const pkg = JSON.parse(fs.readFileSync(pkgPath, 'utf-8'));
|
|
56
|
-
if (pkg.name) {
|
|
57
|
-
return pkg.name.replace(/^@[^/]+\//, '');
|
|
58
|
-
}
|
|
59
|
-
}
|
|
60
|
-
catch { }
|
|
61
|
-
// 2. Try git remote
|
|
62
|
-
try {
|
|
63
|
-
const remote = execSync('git remote get-url origin', {
|
|
64
|
-
cwd: dir, encoding: 'utf-8', stdio: ['pipe', 'pipe', 'pipe']
|
|
65
|
-
}).trim();
|
|
66
|
-
const match = remote.match(/\/([^/]+?)(?:\.git)?$/);
|
|
67
|
-
if (match)
|
|
68
|
-
return match[1];
|
|
69
|
-
}
|
|
70
|
-
catch { }
|
|
71
|
-
// 3. Fallback: directory basename
|
|
72
|
-
return path.basename(dir);
|
|
73
|
-
}
|
|
74
|
-
/**
|
|
75
|
-
* Auto-bootstrap: extract a .seshat/ bundle for the given project directory.
|
|
76
|
-
*
|
|
77
|
-
* Spawns `npx @papyruslabsai/seshat-extract <dir> <dir>/.seshat <name>`
|
|
78
|
-
* and waits for it to complete.
|
|
79
|
-
*
|
|
80
|
-
* @param projectDir - Absolute path to the project root
|
|
81
|
-
* @returns Bootstrap result with entity count, languages, duration, and any error
|
|
82
|
-
*/
|
|
83
|
-
export async function bootstrap(projectDir) {
|
|
84
|
-
const startTime = Date.now();
|
|
85
|
-
const timeoutMs = parseInt(process.env.SESHAT_BOOTSTRAP_TIMEOUT || '120000', 10);
|
|
86
|
-
// Sanity checks
|
|
87
|
-
if (!isCodeProject(projectDir)) {
|
|
88
|
-
return {
|
|
89
|
-
success: false,
|
|
90
|
-
entityCount: 0,
|
|
91
|
-
languages: [],
|
|
92
|
-
durationMs: Date.now() - startTime,
|
|
93
|
-
error: `${projectDir} does not appear to be a code project (no package.json, .git, go.mod, etc.)`,
|
|
94
|
-
};
|
|
95
|
-
}
|
|
96
|
-
const seshatDir = path.join(projectDir, '.seshat');
|
|
97
|
-
const projectName = inferProjectName(projectDir);
|
|
98
|
-
process.stderr.write(`[seshat-mcp] Auto-bootstrap: extracting ${projectName} from ${projectDir}\n`);
|
|
99
|
-
return new Promise((resolve) => {
|
|
100
|
-
// On Windows, npx is npx.cmd and must run through shell.
|
|
101
|
-
// shell: true concatenates args into a command string, so paths with
|
|
102
|
-
// spaces must be double-quoted to survive CMD parsing.
|
|
103
|
-
const isWindows = process.platform === 'win32';
|
|
104
|
-
const npxCmd = isWindows ? 'npx.cmd' : 'npx';
|
|
105
|
-
const q = (s) => isWindows && s.includes(' ') ? `"${s}"` : s;
|
|
106
|
-
const child = spawn(npxCmd, ['-y', '@papyruslabsai/seshat-extract', q(projectDir), q(seshatDir), projectName], {
|
|
107
|
-
cwd: projectDir,
|
|
108
|
-
shell: isWindows, // Windows needs shell: true for .cmd files
|
|
109
|
-
stdio: ['pipe', 'pipe', 'pipe'],
|
|
110
|
-
timeout: timeoutMs,
|
|
111
|
-
});
|
|
112
|
-
let stdout = '';
|
|
113
|
-
let stderr = '';
|
|
114
|
-
child.stdout?.on('data', (data) => {
|
|
115
|
-
stdout += data.toString();
|
|
116
|
-
});
|
|
117
|
-
child.stderr?.on('data', (data) => {
|
|
118
|
-
const text = data.toString();
|
|
119
|
-
stderr += text;
|
|
120
|
-
// Forward progress to parent stderr
|
|
121
|
-
process.stderr.write(`[seshat-extract] ${text}`);
|
|
122
|
-
});
|
|
123
|
-
child.on('error', (err) => {
|
|
124
|
-
resolve({
|
|
125
|
-
success: false,
|
|
126
|
-
entityCount: 0,
|
|
127
|
-
languages: [],
|
|
128
|
-
durationMs: Date.now() - startTime,
|
|
129
|
-
error: `Failed to spawn seshat-extract: ${err.message}`,
|
|
130
|
-
});
|
|
131
|
-
});
|
|
132
|
-
child.on('close', (code) => {
|
|
133
|
-
const durationMs = Date.now() - startTime;
|
|
134
|
-
if (code !== 0) {
|
|
135
|
-
resolve({
|
|
136
|
-
success: false,
|
|
137
|
-
entityCount: 0,
|
|
138
|
-
languages: [],
|
|
139
|
-
durationMs,
|
|
140
|
-
error: `seshat-extract exited with code ${code}. stderr: ${stderr.slice(-500)}`,
|
|
141
|
-
});
|
|
142
|
-
return;
|
|
143
|
-
}
|
|
144
|
-
// Parse the JSON result from stdout
|
|
145
|
-
try {
|
|
146
|
-
const result = JSON.parse(stdout.trim());
|
|
147
|
-
if (result.ok) {
|
|
148
|
-
process.stderr.write(`[seshat-mcp] Bootstrap complete: ${result.entities} entities, ${result.languages?.join(', ')} in ${(durationMs / 1000).toFixed(1)}s\n`);
|
|
149
|
-
resolve({
|
|
150
|
-
success: true,
|
|
151
|
-
entityCount: result.entities || 0,
|
|
152
|
-
languages: result.languages || [],
|
|
153
|
-
durationMs,
|
|
154
|
-
});
|
|
155
|
-
}
|
|
156
|
-
else {
|
|
157
|
-
resolve({
|
|
158
|
-
success: false,
|
|
159
|
-
entityCount: 0,
|
|
160
|
-
languages: [],
|
|
161
|
-
durationMs,
|
|
162
|
-
error: result.error || 'Unknown extraction error',
|
|
163
|
-
});
|
|
164
|
-
}
|
|
165
|
-
}
|
|
166
|
-
catch {
|
|
167
|
-
// JSON parse failed — check if bundle was written anyway
|
|
168
|
-
const bundlePath = path.join(seshatDir, '_bundle.json');
|
|
169
|
-
if (fs.existsSync(bundlePath)) {
|
|
170
|
-
process.stderr.write(`[seshat-mcp] Bootstrap produced bundle but JSON result was malformed. Proceeding.\n`);
|
|
171
|
-
resolve({
|
|
172
|
-
success: true,
|
|
173
|
-
entityCount: 0,
|
|
174
|
-
languages: [],
|
|
175
|
-
durationMs,
|
|
176
|
-
});
|
|
177
|
-
}
|
|
178
|
-
else {
|
|
179
|
-
resolve({
|
|
180
|
-
success: false,
|
|
181
|
-
entityCount: 0,
|
|
182
|
-
languages: [],
|
|
183
|
-
durationMs,
|
|
184
|
-
error: `seshat-extract succeeded but produced no parseable result. stdout: ${stdout.slice(-200)}`,
|
|
185
|
-
});
|
|
186
|
-
}
|
|
187
|
-
}
|
|
188
|
-
});
|
|
189
|
-
});
|
|
190
|
-
}
|
package/dist/graph.d.ts
DELETED
|
@@ -1,42 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Call Graph Construction & Blast Radius Computation
|
|
3
|
-
*
|
|
4
|
-
* Computes the set of entities affected by a change:
|
|
5
|
-
* affected(e) = ancestors(e) ∪ descendants(e) ∪ {e}
|
|
6
|
-
*
|
|
7
|
-
* Ancestors = all transitive callers (upstream).
|
|
8
|
-
* Descendants = all transitive callees (downstream).
|
|
9
|
-
*/
|
|
10
|
-
import type { JstfEntity } from './types.js';
|
|
11
|
-
export interface CallGraph {
|
|
12
|
-
callers: Map<string, Set<string>>;
|
|
13
|
-
callees: Map<string, Set<string>>;
|
|
14
|
-
entityById: Map<string, JstfEntity>;
|
|
15
|
-
/** Reference-resolution outcomes — honest sparsity as a reported number. */
|
|
16
|
-
resolutionStats?: {
|
|
17
|
-
resolved: number;
|
|
18
|
-
ambiguous: number;
|
|
19
|
-
unknown: number;
|
|
20
|
-
};
|
|
21
|
-
}
|
|
22
|
-
export interface BlastRadiusResult {
|
|
23
|
-
affected: string[];
|
|
24
|
-
depthMap: Record<string, number>;
|
|
25
|
-
ancestors: string[];
|
|
26
|
-
descendants: string[];
|
|
27
|
-
}
|
|
28
|
-
/**
|
|
29
|
-
* Build a bidirectional call graph from entities' dependency data.
|
|
30
|
-
*
|
|
31
|
-
* Reference resolution is identity-honest: a bare-name target resolves to the
|
|
32
|
-
* unique entity with that local name, or the unique same-file match when the
|
|
33
|
-
* name is ambiguous repo-wide. A reference that stays ambiguous produces NO
|
|
34
|
-
* edge — first-wins matching used to silently attribute edges to whichever
|
|
35
|
-
* same-named entity was indexed first.
|
|
36
|
-
*/
|
|
37
|
-
export declare function buildCallGraph(entities: JstfEntity[]): CallGraph;
|
|
38
|
-
/**
|
|
39
|
-
* Compute blast radius: all entities affected by changes to the given IDs.
|
|
40
|
-
* Traverses both callers (upstream) and callees (downstream).
|
|
41
|
-
*/
|
|
42
|
-
export declare function computeBlastRadius(graph: CallGraph, changedIds: Set<string>, maxDepth?: number): BlastRadiusResult;
|