skannr 0.1.3 → 0.1.4
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/.eslintrc.js +22 -22
- package/README.md +260 -174
- package/dist/agent-cli.js +25 -25
- package/dist/agent.js +4 -4
- package/dist/blast-radius.d.ts +80 -0
- package/dist/blast-radius.d.ts.map +1 -0
- package/dist/blast-radius.js +545 -0
- package/dist/blast-radius.js.map +1 -0
- package/dist/cli.js +55 -17
- package/dist/cli.js.map +1 -1
- package/dist/mcp-server.d.ts.map +1 -1
- package/dist/mcp-server.js +98 -24
- package/dist/mcp-server.js.map +1 -1
- package/dist/telemetry.js +12 -12
- package/gemini-extension/GEMINI.md +26 -26
- package/gemini-extension/gemini-extension.json +12 -12
- package/gemini-extension/package.json +14 -14
- package/gemini-extension/src/server.ts +69 -69
- package/gemini-extension/tsconfig.json +14 -14
- package/jest.config.js +4 -4
- package/package.json +54 -53
- package/src/agent-cli.ts +397 -397
- package/src/agent.ts +344 -344
- package/src/benchmark.ts +389 -389
- package/src/blast-radius.ts +661 -0
- package/src/cache.ts +317 -317
- package/src/cli.ts +461 -415
- package/src/config.ts +22 -22
- package/src/formatter.ts +105 -105
- package/src/index.ts +223 -223
- package/src/languages/GenericAdapter.ts +44 -44
- package/src/languages/LanguageAdapter.ts +21 -21
- package/src/languages/PythonAdapter.ts +285 -285
- package/src/languages/TypeScriptAdapter.ts +453 -453
- package/src/languages/registry.ts +49 -49
- package/src/mapper.ts +455 -455
- package/src/mcp-cli.ts +8 -8
- package/src/mcp-server.ts +151 -103
- package/src/ranker-enhanced.ts +514 -514
- package/src/ranker.ts +110 -110
- package/src/scanner.ts +226 -226
- package/src/skeletonizer.ts +22 -22
- package/src/telemetry.ts +146 -146
- package/src/tokenizer.ts +20 -20
- package/src/types.ts +92 -92
- package/src/watcher.ts +119 -119
- package/src/why.ts +88 -88
- package/tests/agent.tools.test.ts +81 -81
- package/tests/benchmark.test.ts +30 -30
- package/tests/blast-radius.test.ts +290 -0
- package/tests/fixtures/sample.py +17 -17
- package/tests/fixtures/sample.ts +13 -13
- package/tests/fixtures/src/api/routes.ts +1 -1
- package/tests/fixtures/src/auth/permission.ts +3 -3
- package/tests/python-adapter.test.ts +31 -31
- package/tests/ranker-enhanced.test.ts +70 -70
- package/tests/ranker.test.ts +79 -79
- package/tests/scanner.scope.test.ts +66 -66
- package/tests/setup-fixtures.js +28 -28
- package/tests/skeletonizer.test.ts +149 -149
- package/tsconfig.json +21 -21
- package/uca-landing/index.html +17 -17
- package/uca-landing/package.json +23 -23
- package/uca-landing/postcss.config.js +6 -6
- package/uca-landing/src/App.jsx +43 -43
- package/uca-landing/src/components/AgentMode.jsx +45 -45
- package/uca-landing/src/components/CliReference.jsx +58 -58
- package/uca-landing/src/components/Features.jsx +82 -82
- package/uca-landing/src/components/Footer.jsx +35 -35
- package/uca-landing/src/components/Hero.jsx +125 -125
- package/uca-landing/src/components/HowItWorks.jsx +60 -60
- package/uca-landing/src/components/Install.jsx +103 -103
- package/uca-landing/src/components/LanguageSupport.jsx +63 -63
- package/uca-landing/src/components/Navbar.jsx +86 -86
- package/uca-landing/src/components/Problem.jsx +51 -51
- package/uca-landing/src/components/Reveal.jsx +40 -40
- package/uca-landing/src/components/WorksWith.jsx +59 -59
- package/uca-landing/src/hooks/useScrollNav.js +13 -13
- package/uca-landing/src/hooks/useTypewriter.js +41 -41
- package/uca-landing/src/index.css +13 -13
- package/uca-landing/src/main.jsx +10 -10
- package/uca-landing/tailwind.config.js +68 -68
- package/uca-landing/vercel.json +3 -3
- package/uca-landing/vite.config.js +6 -6
- package/dist/rocket-chat-scope.d.ts +0 -7
- package/dist/rocket-chat-scope.d.ts.map +0 -1
- package/dist/rocket-chat-scope.js +0 -95
- package/dist/rocket-chat-scope.js.map +0 -1
package/.eslintrc.js
CHANGED
|
@@ -1,22 +1,22 @@
|
|
|
1
|
-
module.exports = {
|
|
2
|
-
parser: '@typescript-eslint/parser',
|
|
3
|
-
extends: [
|
|
4
|
-
'eslint:recommended',
|
|
5
|
-
'plugin:@typescript-eslint/recommended',
|
|
6
|
-
],
|
|
7
|
-
parserOptions: {
|
|
8
|
-
ecmaVersion: 2022,
|
|
9
|
-
sourceType: 'module',
|
|
10
|
-
},
|
|
11
|
-
env: {
|
|
12
|
-
node: true,
|
|
13
|
-
es6: true,
|
|
14
|
-
jest: true,
|
|
15
|
-
},
|
|
16
|
-
rules: {
|
|
17
|
-
'@typescript-eslint/explicit-function-return-type': 'off',
|
|
18
|
-
'@typescript-eslint/no-explicit-any': 'warn',
|
|
19
|
-
'@typescript-eslint/no-unused-vars': ['error', { argsIgnorePattern: '^_' }],
|
|
20
|
-
'no-console': 'off',
|
|
21
|
-
},
|
|
22
|
-
};
|
|
1
|
+
module.exports = {
|
|
2
|
+
parser: '@typescript-eslint/parser',
|
|
3
|
+
extends: [
|
|
4
|
+
'eslint:recommended',
|
|
5
|
+
'plugin:@typescript-eslint/recommended',
|
|
6
|
+
],
|
|
7
|
+
parserOptions: {
|
|
8
|
+
ecmaVersion: 2022,
|
|
9
|
+
sourceType: 'module',
|
|
10
|
+
},
|
|
11
|
+
env: {
|
|
12
|
+
node: true,
|
|
13
|
+
es6: true,
|
|
14
|
+
jest: true,
|
|
15
|
+
},
|
|
16
|
+
rules: {
|
|
17
|
+
'@typescript-eslint/explicit-function-return-type': 'off',
|
|
18
|
+
'@typescript-eslint/no-explicit-any': 'warn',
|
|
19
|
+
'@typescript-eslint/no-unused-vars': ['error', { argsIgnorePattern: '^_' }],
|
|
20
|
+
'no-console': 'off',
|
|
21
|
+
},
|
|
22
|
+
};
|
package/README.md
CHANGED
|
@@ -1,174 +1,260 @@
|
|
|
1
|
-
# Skannr
|
|
2
|
-
|
|
3
|
-
A CLI tool and MCP server that helps AI agents understand **any codebase**.
|
|
4
|
-
It scans files, generates compressed structural "skeletons", and ranks results
|
|
5
|
-
using hybrid retrieval — reducing token usage by ~96% vs full file scans.
|
|
6
|
-
|
|
7
|
-
## How It Works
|
|
8
|
-
|
|
9
|
-
1. You point it at any repo with `--root /path/to/repo`
|
|
10
|
-
2. It auto-detects the language (TypeScript, JavaScript, Python, or generic fallback)
|
|
11
|
-
3. It auto-discovers your project's modules from the folder structure
|
|
12
|
-
4. For your question, it ranks the most relevant files using lexical + structural + dependency-graph analysis
|
|
13
|
-
5. It strips function bodies from files (keeping types, signatures, imports)
|
|
14
|
-
6. Returns compact skeletons an AI can reason over without blowing the context window
|
|
15
|
-
|
|
16
|
-
## Install
|
|
17
|
-
|
|
18
|
-
```bash
|
|
19
|
-
npm install -g skannr
|
|
20
|
-
```
|
|
21
|
-
|
|
22
|
-
## Usage
|
|
23
|
-
|
|
24
|
-
### CLI
|
|
25
|
-
|
|
26
|
-
```bash
|
|
27
|
-
# Basic
|
|
28
|
-
skannr --question "how does authentication work?" --root /path/to/any/repo
|
|
29
|
-
|
|
30
|
-
# Limit results
|
|
31
|
-
skannr --question "database connection setup" --root . --limit 5
|
|
32
|
-
|
|
33
|
-
# Focus on specific modules (auto-discovered if not specified)
|
|
34
|
-
skannr --question "permission checks" --root . --modules auth,middleware
|
|
35
|
-
|
|
36
|
-
# Force language
|
|
37
|
-
skannr --question "class structure" --root /path/to/python/project --lang python
|
|
38
|
-
|
|
39
|
-
# Interactive agent mode
|
|
40
|
-
skannr-agent --root /path/to/repo
|
|
41
|
-
|
|
42
|
-
# Cache management
|
|
43
|
-
skannr --cache-stats
|
|
44
|
-
skannr --cache-clear
|
|
45
|
-
skannr --question "..." --skip-cache
|
|
46
|
-
|
|
47
|
-
# Output: human (default), markdown, or json
|
|
48
|
-
skannr --question "..." --root . --format markdown
|
|
49
|
-
skannr --question "..." --root . --format json
|
|
50
|
-
|
|
51
|
-
# Repository health report (JSON on stdout)
|
|
52
|
-
skannr --report --root .
|
|
53
|
-
|
|
54
|
-
# Re-run analysis when files change (debounced; uses fresh analysis each pass)
|
|
55
|
-
skannr --question "..." --root . --watch
|
|
56
|
-
```
|
|
57
|
-
|
|
58
|
-
### Watch mode (`--watch`)
|
|
59
|
-
|
|
60
|
-
Use `--watch` when you want Skannr to stay running and **re-analyze after relevant file changes** (large repos you edit often). Changes under common build/vendor dirs are ignored (`node_modules`, `.git`, `dist`, etc.). Press **Ctrl+C** to stop.
|
|
61
|
-
|
|
62
|
-
Each run bypasses the analysis cache so results reflect the tree as it is now.
|
|
63
|
-
|
|
64
|
-
### Anonymous telemetry (opt-in)
|
|
65
|
-
|
|
66
|
-
Telemetry is **off unless you enable it** (or accept deferred opt-in — see below). It sends **only which CLI flags were used** — never your question text, file paths, or code.
|
|
67
|
-
|
|
68
|
-
- Enable: `skannr --telemetry-on`
|
|
69
|
-
- Disable: `skannr --telemetry-off`
|
|
70
|
-
|
|
71
|
-
Settings are stored under `~/.skannr/config.json`. The first time you run an analyze command with no config yet, Skannr may show a short notice; you can opt in or out anytime with the flags above.
|
|
72
|
-
|
|
73
|
-
If you take no action, telemetry may turn on automatically **after 7 days** from that notice unless you explicitly disabled it with `--telemetry-off`.
|
|
74
|
-
|
|
75
|
-
## MCP Server
|
|
76
|
-
|
|
77
|
-
`skannr` ships with a built-in MCP server. One-time setup per AI tool:
|
|
78
|
-
|
|
79
|
-
### Cursor
|
|
80
|
-
|
|
81
|
-
`~/.cursor/mcp.json`:
|
|
82
|
-
|
|
83
|
-
```json
|
|
84
|
-
{
|
|
85
|
-
"mcpServers": {
|
|
86
|
-
"skannr": {
|
|
87
|
-
"command": "npx",
|
|
88
|
-
"args": ["-y", "skannr", "--mcp"]
|
|
89
|
-
}
|
|
90
|
-
}
|
|
91
|
-
}
|
|
92
|
-
```
|
|
93
|
-
|
|
94
|
-
### Claude Desktop / Claude Code
|
|
95
|
-
|
|
96
|
-
`~/Library/Application Support/Claude/claude_desktop_config.json`:
|
|
97
|
-
|
|
98
|
-
```json
|
|
99
|
-
{
|
|
100
|
-
"mcpServers": {
|
|
101
|
-
"skannr": {
|
|
102
|
-
"command": "npx",
|
|
103
|
-
"args": ["-y", "skannr", "--mcp"]
|
|
104
|
-
}
|
|
105
|
-
}
|
|
106
|
-
}
|
|
107
|
-
```
|
|
108
|
-
|
|
109
|
-
### Gemini CLI
|
|
110
|
-
|
|
111
|
-
`~/.gemini/config.json`:
|
|
112
|
-
|
|
113
|
-
```json
|
|
114
|
-
{
|
|
115
|
-
"mcpServers": {
|
|
116
|
-
"skannr": {
|
|
117
|
-
"command": "npx",
|
|
118
|
-
"args": ["-y", "skannr", "--mcp"]
|
|
119
|
-
}
|
|
120
|
-
}
|
|
121
|
-
}
|
|
122
|
-
```
|
|
123
|
-
|
|
124
|
-
Alternatively run the dedicated binary: `skannr-mcp` (same stdio server).
|
|
125
|
-
|
|
126
|
-
## Config File (optional)
|
|
127
|
-
|
|
128
|
-
Drop a `code-analyzer.config.json` in your repo root:
|
|
129
|
-
|
|
130
|
-
```json
|
|
131
|
-
{
|
|
132
|
-
"modules": {
|
|
133
|
-
"auth": ["src/auth", "lib/auth"],
|
|
134
|
-
"api": ["src/api", "src/routes"]
|
|
135
|
-
},
|
|
136
|
-
"exclude": ["**/generated/**", "**/migrations/**"],
|
|
137
|
-
"extensions": [".ts", ".js"],
|
|
138
|
-
"defaultLimit": 10
|
|
139
|
-
}
|
|
140
|
-
```
|
|
141
|
-
|
|
142
|
-
## Supported Languages
|
|
143
|
-
|
|
144
|
-
| Language | Skeleton Support |
|
|
145
|
-
|---|---|
|
|
146
|
-
| TypeScript / TSX | Full AST (ts-morph) |
|
|
147
|
-
| JavaScript / JSX | Full AST (ts-morph) |
|
|
148
|
-
| Python | Regex-based (signatures + types) |
|
|
149
|
-
| Others | First 50 lines (generic fallback) |
|
|
150
|
-
|
|
151
|
-
## Performance
|
|
152
|
-
|
|
153
|
-
Benchmarked on large TypeScript monorepo:
|
|
154
|
-
|
|
155
|
-
| Metric | Result |
|
|
156
|
-
|---|---|
|
|
157
|
-
| Token Reduction vs Full Scan | ~96.5% |
|
|
158
|
-
| Token Reduction vs Top-N | ~78.2% |
|
|
159
|
-
| Avg keyword coverage | ~75% |
|
|
160
|
-
| Directory diversity (top-5) | ~80% |
|
|
161
|
-
| Average execution time | ~1.2s |
|
|
162
|
-
|
|
163
|
-
## Interactive Agent Commands
|
|
164
|
-
|
|
165
|
-
```
|
|
166
|
-
/help Show all commands
|
|
167
|
-
/files List retrieved files
|
|
168
|
-
/symbols <query> Search for symbols
|
|
169
|
-
/symbol <id> Get full implementation
|
|
170
|
-
/deps <file> Show imports for a file
|
|
171
|
-
/refresh Re-analyze with new context
|
|
172
|
-
/stats Show mapping statistics
|
|
173
|
-
/exit Quit
|
|
174
|
-
```
|
|
1
|
+
# Skannr
|
|
2
|
+
|
|
3
|
+
A CLI tool and MCP server that helps AI agents understand **any codebase**.
|
|
4
|
+
It scans files, generates compressed structural "skeletons", and ranks results
|
|
5
|
+
using hybrid retrieval — reducing token usage by ~96% vs full file scans.
|
|
6
|
+
|
|
7
|
+
## How It Works
|
|
8
|
+
|
|
9
|
+
1. You point it at any repo with `--root /path/to/repo`
|
|
10
|
+
2. It auto-detects the language (TypeScript, JavaScript, Python, or generic fallback)
|
|
11
|
+
3. It auto-discovers your project's modules from the folder structure
|
|
12
|
+
4. For your question, it ranks the most relevant files using lexical + structural + dependency-graph analysis
|
|
13
|
+
5. It strips function bodies from files (keeping types, signatures, imports)
|
|
14
|
+
6. Returns compact skeletons an AI can reason over without blowing the context window
|
|
15
|
+
|
|
16
|
+
## Install
|
|
17
|
+
|
|
18
|
+
```bash
|
|
19
|
+
npm install -g skannr
|
|
20
|
+
```
|
|
21
|
+
|
|
22
|
+
## Usage
|
|
23
|
+
|
|
24
|
+
### CLI
|
|
25
|
+
|
|
26
|
+
```bash
|
|
27
|
+
# Basic
|
|
28
|
+
skannr --question "how does authentication work?" --root /path/to/any/repo
|
|
29
|
+
|
|
30
|
+
# Limit results
|
|
31
|
+
skannr --question "database connection setup" --root . --limit 5
|
|
32
|
+
|
|
33
|
+
# Focus on specific modules (auto-discovered if not specified)
|
|
34
|
+
skannr --question "permission checks" --root . --modules auth,middleware
|
|
35
|
+
|
|
36
|
+
# Force language
|
|
37
|
+
skannr --question "class structure" --root /path/to/python/project --lang python
|
|
38
|
+
|
|
39
|
+
# Interactive agent mode
|
|
40
|
+
skannr-agent --root /path/to/repo
|
|
41
|
+
|
|
42
|
+
# Cache management
|
|
43
|
+
skannr --cache-stats
|
|
44
|
+
skannr --cache-clear
|
|
45
|
+
skannr --question "..." --skip-cache
|
|
46
|
+
|
|
47
|
+
# Output: human (default), markdown, or json
|
|
48
|
+
skannr --question "..." --root . --format markdown
|
|
49
|
+
skannr --question "..." --root . --format json
|
|
50
|
+
|
|
51
|
+
# Repository health report (JSON on stdout)
|
|
52
|
+
skannr --report --root .
|
|
53
|
+
|
|
54
|
+
# Re-run analysis when files change (debounced; uses fresh analysis each pass)
|
|
55
|
+
skannr --question "..." --root . --watch
|
|
56
|
+
```
|
|
57
|
+
|
|
58
|
+
### Watch mode (`--watch`)
|
|
59
|
+
|
|
60
|
+
Use `--watch` when you want Skannr to stay running and **re-analyze after relevant file changes** (large repos you edit often). Changes under common build/vendor dirs are ignored (`node_modules`, `.git`, `dist`, etc.). Press **Ctrl+C** to stop.
|
|
61
|
+
|
|
62
|
+
Each run bypasses the analysis cache so results reflect the tree as it is now.
|
|
63
|
+
|
|
64
|
+
### Anonymous telemetry (opt-in)
|
|
65
|
+
|
|
66
|
+
Telemetry is **off unless you enable it** (or accept deferred opt-in — see below). It sends **only which CLI flags were used** — never your question text, file paths, or code.
|
|
67
|
+
|
|
68
|
+
- Enable: `skannr --telemetry-on`
|
|
69
|
+
- Disable: `skannr --telemetry-off`
|
|
70
|
+
|
|
71
|
+
Settings are stored under `~/.skannr/config.json`. The first time you run an analyze command with no config yet, Skannr may show a short notice; you can opt in or out anytime with the flags above.
|
|
72
|
+
|
|
73
|
+
If you take no action, telemetry may turn on automatically **after 7 days** from that notice unless you explicitly disabled it with `--telemetry-off`.
|
|
74
|
+
|
|
75
|
+
## MCP Server
|
|
76
|
+
|
|
77
|
+
`skannr` ships with a built-in MCP server. One-time setup per AI tool:
|
|
78
|
+
|
|
79
|
+
### Cursor
|
|
80
|
+
|
|
81
|
+
`~/.cursor/mcp.json`:
|
|
82
|
+
|
|
83
|
+
```json
|
|
84
|
+
{
|
|
85
|
+
"mcpServers": {
|
|
86
|
+
"skannr": {
|
|
87
|
+
"command": "npx",
|
|
88
|
+
"args": ["-y", "skannr", "--mcp"]
|
|
89
|
+
}
|
|
90
|
+
}
|
|
91
|
+
}
|
|
92
|
+
```
|
|
93
|
+
|
|
94
|
+
### Claude Desktop / Claude Code
|
|
95
|
+
|
|
96
|
+
`~/Library/Application Support/Claude/claude_desktop_config.json`:
|
|
97
|
+
|
|
98
|
+
```json
|
|
99
|
+
{
|
|
100
|
+
"mcpServers": {
|
|
101
|
+
"skannr": {
|
|
102
|
+
"command": "npx",
|
|
103
|
+
"args": ["-y", "skannr", "--mcp"]
|
|
104
|
+
}
|
|
105
|
+
}
|
|
106
|
+
}
|
|
107
|
+
```
|
|
108
|
+
|
|
109
|
+
### Gemini CLI
|
|
110
|
+
|
|
111
|
+
`~/.gemini/config.json`:
|
|
112
|
+
|
|
113
|
+
```json
|
|
114
|
+
{
|
|
115
|
+
"mcpServers": {
|
|
116
|
+
"skannr": {
|
|
117
|
+
"command": "npx",
|
|
118
|
+
"args": ["-y", "skannr", "--mcp"]
|
|
119
|
+
}
|
|
120
|
+
}
|
|
121
|
+
}
|
|
122
|
+
```
|
|
123
|
+
|
|
124
|
+
Alternatively run the dedicated binary: `skannr-mcp` (same stdio server).
|
|
125
|
+
|
|
126
|
+
## Config File (optional)
|
|
127
|
+
|
|
128
|
+
Drop a `code-analyzer.config.json` in your repo root:
|
|
129
|
+
|
|
130
|
+
```json
|
|
131
|
+
{
|
|
132
|
+
"modules": {
|
|
133
|
+
"auth": ["src/auth", "lib/auth"],
|
|
134
|
+
"api": ["src/api", "src/routes"]
|
|
135
|
+
},
|
|
136
|
+
"exclude": ["**/generated/**", "**/migrations/**"],
|
|
137
|
+
"extensions": [".ts", ".js"],
|
|
138
|
+
"defaultLimit": 10
|
|
139
|
+
}
|
|
140
|
+
```
|
|
141
|
+
|
|
142
|
+
## Supported Languages
|
|
143
|
+
|
|
144
|
+
| Language | Skeleton Support |
|
|
145
|
+
|---|---|
|
|
146
|
+
| TypeScript / TSX | Full AST (ts-morph) |
|
|
147
|
+
| JavaScript / JSX | Full AST (ts-morph) |
|
|
148
|
+
| Python | Regex-based (signatures + types) |
|
|
149
|
+
| Others | First 50 lines (generic fallback) |
|
|
150
|
+
|
|
151
|
+
## Performance
|
|
152
|
+
|
|
153
|
+
Benchmarked on large TypeScript monorepo:
|
|
154
|
+
|
|
155
|
+
| Metric | Result |
|
|
156
|
+
|---|---|
|
|
157
|
+
| Token Reduction vs Full Scan | ~96.5% |
|
|
158
|
+
| Token Reduction vs Top-N | ~78.2% |
|
|
159
|
+
| Avg keyword coverage | ~75% |
|
|
160
|
+
| Directory diversity (top-5) | ~80% |
|
|
161
|
+
| Average execution time | ~1.2s |
|
|
162
|
+
|
|
163
|
+
## Interactive Agent Commands
|
|
164
|
+
|
|
165
|
+
```
|
|
166
|
+
/help Show all commands
|
|
167
|
+
/files List retrieved files
|
|
168
|
+
/symbols <query> Search for symbols
|
|
169
|
+
/symbol <id> Get full implementation
|
|
170
|
+
/deps <file> Show imports for a file
|
|
171
|
+
/refresh Re-analyze with new context
|
|
172
|
+
/stats Show mapping statistics
|
|
173
|
+
/exit Quit
|
|
174
|
+
```
|
|
175
|
+
|
|
176
|
+
## Blast Radius
|
|
177
|
+
|
|
178
|
+
Analyze the downstream impact and risk of a code change. Given a git diff,
|
|
179
|
+
blast-radius identifies which files are affected, how central they are in the
|
|
180
|
+
dependency graph, and whether they have test coverage.
|
|
181
|
+
|
|
182
|
+
**Limitation (v1):** Traversal is computed at file granularity — "file A
|
|
183
|
+
imports file B" — not at function-call level. Function-level resolution is
|
|
184
|
+
planned for a future version.
|
|
185
|
+
|
|
186
|
+
### CLI
|
|
187
|
+
|
|
188
|
+
```bash
|
|
189
|
+
# Analyze working tree changes vs HEAD (default)
|
|
190
|
+
skannr blast-radius --root .
|
|
191
|
+
|
|
192
|
+
# Analyze a specific diff file, 3 hops deep
|
|
193
|
+
skannr blast-radius --root . --diff changes.patch --hops 3
|
|
194
|
+
|
|
195
|
+
# JSON output for CI pipelines
|
|
196
|
+
skannr blast-radius --root . --json
|
|
197
|
+
```
|
|
198
|
+
|
|
199
|
+
Sample terminal output:
|
|
200
|
+
|
|
201
|
+
```
|
|
202
|
+
Blast Radius Analysis (2-hop traversal)
|
|
203
|
+
──────────────────────────────────────────────────
|
|
204
|
+
|
|
205
|
+
Risk Score: 5.8/10
|
|
206
|
+
Risk 5.8/10 (moderate): 1 file(s) changed, 4 downstream affected, 3 untested.
|
|
207
|
+
|
|
208
|
+
Changed files:
|
|
209
|
+
src/auth/session.ts
|
|
210
|
+
|
|
211
|
+
Changed symbols:
|
|
212
|
+
function validateToken (src/auth/session.ts)
|
|
213
|
+
|
|
214
|
+
Hop 1 (2 files):
|
|
215
|
+
src/middleware/auth-guard.ts centrality=0.85 [NO TEST]
|
|
216
|
+
src/api/login.ts centrality=0.60
|
|
217
|
+
|
|
218
|
+
Hop 2 (2 files):
|
|
219
|
+
src/routes/index.ts centrality=0.45 [NO TEST]
|
|
220
|
+
src/api/admin.ts centrality=0.30 [NO TEST]
|
|
221
|
+
|
|
222
|
+
Formula inputs:
|
|
223
|
+
affected_count (normalized): 0.080
|
|
224
|
+
avg_centrality: 0.550
|
|
225
|
+
untested_ratio: 0.750
|
|
226
|
+
hop_spread (normalized): 1.000
|
|
227
|
+
```
|
|
228
|
+
|
|
229
|
+
### MCP
|
|
230
|
+
|
|
231
|
+
The `blast_radius` tool is exposed via the same MCP server (`skannr --mcp`).
|
|
232
|
+
|
|
233
|
+
Input schema:
|
|
234
|
+
|
|
235
|
+
```json
|
|
236
|
+
{
|
|
237
|
+
"root": "/path/to/repo",
|
|
238
|
+
"diff": "<optional unified diff content>",
|
|
239
|
+
"hops": 2
|
|
240
|
+
}
|
|
241
|
+
```
|
|
242
|
+
|
|
243
|
+
If `diff` is omitted, the tool runs `git diff HEAD` in the given root.
|
|
244
|
+
The output is the same JSON structure as `skannr blast-radius --json`.
|
|
245
|
+
|
|
246
|
+
### Risk Score Formula
|
|
247
|
+
|
|
248
|
+
```
|
|
249
|
+
risk = 2.5 × normalizedAffectedCount
|
|
250
|
+
+ 2.5 × avgCentrality
|
|
251
|
+
+ 3.5 × untestedRatio
|
|
252
|
+
+ 1.5 × normalizedMaxHopSpread
|
|
253
|
+
```
|
|
254
|
+
|
|
255
|
+
| Input | Range | Meaning |
|
|
256
|
+
|-------|-------|---------|
|
|
257
|
+
| normalizedAffectedCount | 0–1 | Affected files / total project files |
|
|
258
|
+
| avgCentrality | 0–1 | Mean in-degree centrality of affected files |
|
|
259
|
+
| untestedRatio | 0–1 | Fraction of affected files with no test file |
|
|
260
|
+
| normalizedMaxHopSpread | 0–1 | Deepest hop reached / max configured hops |
|
package/dist/agent-cli.js
CHANGED
|
@@ -140,31 +140,31 @@ function parseArgs() {
|
|
|
140
140
|
* Print help message
|
|
141
141
|
*/
|
|
142
142
|
function printHelp() {
|
|
143
|
-
console.log(`
|
|
144
|
-
skannr-agent — AI-powered code analysis (Gemini)
|
|
145
|
-
|
|
146
|
-
Usage:
|
|
147
|
-
skannr-agent --question "<text>" [options]
|
|
148
|
-
skannr-agent --interactive [options]
|
|
149
|
-
|
|
150
|
-
Options:
|
|
151
|
-
--root <path> Project root directory (default: current directory)
|
|
152
|
-
--question "<text>" Question to analyze (required unless --interactive)
|
|
153
|
-
--limit <number> Number of top files to analyze (default: 10)
|
|
154
|
-
--api-key <key> Gemini API key (or set GEMINI_API_KEY env var)
|
|
155
|
-
--model <name> Gemini model name (default: gemini-2.0-flash-exp)
|
|
156
|
-
--interactive, -i Start interactive chat mode
|
|
157
|
-
--help, -h Show this help message
|
|
158
|
-
|
|
159
|
-
Examples:
|
|
160
|
-
skannr-agent --question "How does authentication work?"
|
|
161
|
-
skannr-agent --interactive --root ./my-project
|
|
162
|
-
skannr-agent --question "Find all API endpoints" --limit 15
|
|
163
|
-
|
|
164
|
-
Environment variables:
|
|
165
|
-
GEMINI_API_KEY Gemini API key (alternative to --api-key)
|
|
166
|
-
|
|
167
|
-
Docs: https://skannr-ten.vercel.app
|
|
143
|
+
console.log(`
|
|
144
|
+
skannr-agent — AI-powered code analysis (Gemini)
|
|
145
|
+
|
|
146
|
+
Usage:
|
|
147
|
+
skannr-agent --question "<text>" [options]
|
|
148
|
+
skannr-agent --interactive [options]
|
|
149
|
+
|
|
150
|
+
Options:
|
|
151
|
+
--root <path> Project root directory (default: current directory)
|
|
152
|
+
--question "<text>" Question to analyze (required unless --interactive)
|
|
153
|
+
--limit <number> Number of top files to analyze (default: 10)
|
|
154
|
+
--api-key <key> Gemini API key (or set GEMINI_API_KEY env var)
|
|
155
|
+
--model <name> Gemini model name (default: gemini-2.0-flash-exp)
|
|
156
|
+
--interactive, -i Start interactive chat mode
|
|
157
|
+
--help, -h Show this help message
|
|
158
|
+
|
|
159
|
+
Examples:
|
|
160
|
+
skannr-agent --question "How does authentication work?"
|
|
161
|
+
skannr-agent --interactive --root ./my-project
|
|
162
|
+
skannr-agent --question "Find all API endpoints" --limit 15
|
|
163
|
+
|
|
164
|
+
Environment variables:
|
|
165
|
+
GEMINI_API_KEY Gemini API key (alternative to --api-key)
|
|
166
|
+
|
|
167
|
+
Docs: https://skannr-ten.vercel.app
|
|
168
168
|
`);
|
|
169
169
|
}
|
|
170
170
|
/**
|
package/dist/agent.js
CHANGED
|
@@ -48,8 +48,8 @@ const path = __importStar(require("path"));
|
|
|
48
48
|
*/
|
|
49
49
|
exports.getSymbolDetailsTool = {
|
|
50
50
|
name: 'get_symbol_details',
|
|
51
|
-
description: `Retrieve the full implementation of a code symbol (function, method, class) from the original source file.
|
|
52
|
-
Use this when you need to see the actual implementation of a function or method that was marked with [SYMBOL:...] in the skeleton.
|
|
51
|
+
description: `Retrieve the full implementation of a code symbol (function, method, class) from the original source file.
|
|
52
|
+
Use this when you need to see the actual implementation of a function or method that was marked with [SYMBOL:...] in the skeleton.
|
|
53
53
|
The symbolId is in the format "ClassName.methodName" or "functionName" for top-level functions.`,
|
|
54
54
|
parameters: {
|
|
55
55
|
type: generative_ai_1.SchemaType.OBJECT,
|
|
@@ -67,7 +67,7 @@ The symbolId is in the format "ClassName.methodName" or "functionName" for top-l
|
|
|
67
67
|
*/
|
|
68
68
|
exports.searchSymbolsTool = {
|
|
69
69
|
name: 'search_symbols',
|
|
70
|
-
description: `Search for available symbols in the generated skeletons. Returns a list of matching symbols that can be retrieved using get_symbol_details.
|
|
70
|
+
description: `Search for available symbols in the generated skeletons. Returns a list of matching symbols that can be retrieved using get_symbol_details.
|
|
71
71
|
Use this to discover what functions/methods are available before requesting their full implementation.`,
|
|
72
72
|
parameters: {
|
|
73
73
|
type: generative_ai_1.SchemaType.OBJECT,
|
|
@@ -90,7 +90,7 @@ Use this to discover what functions/methods are available before requesting thei
|
|
|
90
90
|
*/
|
|
91
91
|
exports.analyzeFileDependenciesTool = {
|
|
92
92
|
name: 'analyze_file_dependencies',
|
|
93
|
-
description: `Analyze import/export relationships for a specific file from the skeleton.
|
|
93
|
+
description: `Analyze import/export relationships for a specific file from the skeleton.
|
|
94
94
|
Use this to understand what other files a given file depends on.`,
|
|
95
95
|
parameters: {
|
|
96
96
|
type: generative_ai_1.SchemaType.OBJECT,
|
|
@@ -0,0 +1,80 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Blast Radius: determines downstream impact and risk of a git diff.
|
|
3
|
+
*
|
|
4
|
+
* Pipeline: parse diff → identify changed files → traverse reverse dependency
|
|
5
|
+
* graph N hops → score affected nodes by centrality → flag untested nodes →
|
|
6
|
+
* compute aggregate risk score.
|
|
7
|
+
*
|
|
8
|
+
* Limitation (v1): graph traversal is file-level, not symbol-level.
|
|
9
|
+
* A changed file is treated as a unit; individual function-call edges are not
|
|
10
|
+
* tracked. Symbol extraction from diffs is used for reporting only.
|
|
11
|
+
*/
|
|
12
|
+
import type { Symbol } from './languages/LanguageAdapter';
|
|
13
|
+
/** A symbol touched by the diff within a single file. */
|
|
14
|
+
export interface ChangedSymbol {
|
|
15
|
+
name: string;
|
|
16
|
+
kind: Symbol['kind'];
|
|
17
|
+
file: string;
|
|
18
|
+
}
|
|
19
|
+
/** A downstream file affected by the change, with metadata. */
|
|
20
|
+
export interface AffectedNode {
|
|
21
|
+
/** Path relative to project root. */
|
|
22
|
+
file: string;
|
|
23
|
+
/** Number of hops from a changed file (1 = direct importer). */
|
|
24
|
+
hopDistance: number;
|
|
25
|
+
/** Normalized centrality score [0,1] — how many files depend on this one. */
|
|
26
|
+
centrality: number;
|
|
27
|
+
/** Whether a corresponding test file was found for this file. */
|
|
28
|
+
hasTest: boolean;
|
|
29
|
+
}
|
|
30
|
+
/** Full blast-radius analysis result (shared between CLI text and JSON output). */
|
|
31
|
+
export interface BlastRadiusResult {
|
|
32
|
+
/** Aggregate risk score (0–10). */
|
|
33
|
+
riskScore: number;
|
|
34
|
+
/** One-line human-readable summary. */
|
|
35
|
+
summary: string;
|
|
36
|
+
/** Files directly modified by the diff (relative paths). */
|
|
37
|
+
changedFiles: string[];
|
|
38
|
+
/** Symbols identified as changed within those files. */
|
|
39
|
+
changedSymbols: ChangedSymbol[];
|
|
40
|
+
/** All downstream affected files grouped by hop distance. */
|
|
41
|
+
affectedNodes: AffectedNode[];
|
|
42
|
+
/** Breakdown of the risk formula inputs (for transparency). */
|
|
43
|
+
formulaInputs: {
|
|
44
|
+
normalizedAffectedCount: number;
|
|
45
|
+
avgCentrality: number;
|
|
46
|
+
untestedRatio: number;
|
|
47
|
+
normalizedMaxHopSpread: number;
|
|
48
|
+
};
|
|
49
|
+
/** Max hops used for this analysis. */
|
|
50
|
+
hops: number;
|
|
51
|
+
}
|
|
52
|
+
/** Options accepted by computeBlastRadius. */
|
|
53
|
+
export interface BlastRadiusOptions {
|
|
54
|
+
/** Absolute path to project root. */
|
|
55
|
+
root: string;
|
|
56
|
+
/** Raw unified diff content. If omitted, working-tree diff against HEAD is used. */
|
|
57
|
+
diffContent?: string;
|
|
58
|
+
/** Path to a diff file on disk. Takes precedence over diffContent if both given. */
|
|
59
|
+
diffPath?: string;
|
|
60
|
+
/** Maximum hop distance for traversal (default: 2). */
|
|
61
|
+
hops?: number;
|
|
62
|
+
}
|
|
63
|
+
/** Compute the blast radius for a diff against a project. */
|
|
64
|
+
export declare function computeBlastRadius(options: BlastRadiusOptions): BlastRadiusResult;
|
|
65
|
+
/**
|
|
66
|
+
* Invert the forward graph (file → imports) into a reverse graph
|
|
67
|
+
* (file → files that import it).
|
|
68
|
+
*/
|
|
69
|
+
export declare function buildReverseGraph(forwardGraph: Map<string, string[]>): Map<string, string[]>;
|
|
70
|
+
/**
|
|
71
|
+
* BFS from changed files outward on the reverse graph, up to maxHops.
|
|
72
|
+
* Returns a map of affected file → hop distance (excluding the changed files
|
|
73
|
+
* themselves).
|
|
74
|
+
*/
|
|
75
|
+
export declare function traverseAffected(changedFiles: string[], reverseGraph: Map<string, string[]>, maxHops: number): Map<string, number>;
|
|
76
|
+
/** Plain-text report for terminal output. */
|
|
77
|
+
export declare function formatBlastRadiusText(result: BlastRadiusResult): string;
|
|
78
|
+
/** JSON output (for --json flag and MCP). */
|
|
79
|
+
export declare function formatBlastRadiusJson(result: BlastRadiusResult): string;
|
|
80
|
+
//# sourceMappingURL=blast-radius.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"blast-radius.d.ts","sourceRoot":"","sources":["../src/blast-radius.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AAUH,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,6BAA6B,CAAC;AAe1D,yDAAyD;AACzD,MAAM,WAAW,aAAa;IAC5B,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,MAAM,CAAC,MAAM,CAAC,CAAC;IACrB,IAAI,EAAE,MAAM,CAAC;CACd;AAED,+DAA+D;AAC/D,MAAM,WAAW,YAAY;IAC3B,qCAAqC;IACrC,IAAI,EAAE,MAAM,CAAC;IACb,gEAAgE;IAChE,WAAW,EAAE,MAAM,CAAC;IACpB,6EAA6E;IAC7E,UAAU,EAAE,MAAM,CAAC;IACnB,iEAAiE;IACjE,OAAO,EAAE,OAAO,CAAC;CAClB;AAED,mFAAmF;AACnF,MAAM,WAAW,iBAAiB;IAChC,mCAAmC;IACnC,SAAS,EAAE,MAAM,CAAC;IAClB,uCAAuC;IACvC,OAAO,EAAE,MAAM,CAAC;IAChB,4DAA4D;IAC5D,YAAY,EAAE,MAAM,EAAE,CAAC;IACvB,wDAAwD;IACxD,cAAc,EAAE,aAAa,EAAE,CAAC;IAChC,6DAA6D;IAC7D,aAAa,EAAE,YAAY,EAAE,CAAC;IAC9B,+DAA+D;IAC/D,aAAa,EAAE;QACb,uBAAuB,EAAE,MAAM,CAAC;QAChC,aAAa,EAAE,MAAM,CAAC;QACtB,aAAa,EAAE,MAAM,CAAC;QACtB,sBAAsB,EAAE,MAAM,CAAC;KAChC,CAAC;IACF,uCAAuC;IACvC,IAAI,EAAE,MAAM,CAAC;CACd;AAED,8CAA8C;AAC9C,MAAM,WAAW,kBAAkB;IACjC,qCAAqC;IACrC,IAAI,EAAE,MAAM,CAAC;IACb,oFAAoF;IACpF,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,oFAAoF;IACpF,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,uDAAuD;IACvD,IAAI,CAAC,EAAE,MAAM,CAAC;CACf;AAMD,6DAA6D;AAC7D,wBAAgB,kBAAkB,CAAC,OAAO,EAAE,kBAAkB,GAAG,iBAAiB,CA8CjF;AA6GD;;;GAGG;AACH,wBAAgB,iBAAiB,CAC/B,YAAY,EAAE,GAAG,CAAC,MAAM,EAAE,MAAM,EAAE,CAAC,GAClC,GAAG,CAAC,MAAM,EAAE,MAAM,EAAE,CAAC,CAcvB;AAMD;;;;GAIG;AACH,wBAAgB,gBAAgB,CAC9B,YAAY,EAAE,MAAM,EAAE,EACtB,YAAY,EAAE,GAAG,CAAC,MAAM,EAAE,MAAM,EAAE,CAAC,EACnC,OAAO,EAAE,MAAM,GACd,GAAG,CAAC,MAAM,EAAE,MAAM,CAAC,CA8BrB;AA4PD,6CAA6C;AAC7C,wBAAgB,qBAAqB,CAAC,MAAM,EAAE,iBAAiB,GAAG,MAAM,CAyDvE;AAED,6CAA6C;AAC7C,wBAAgB,qBAAqB,CAAC,MAAM,EAAE,iBAAiB,GAAG,MAAM,CAEvE"}
|