@thijshakkenberg/valkyrie-mom-mcp 1.0.0 → 1.2.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/.claude-plugin/marketplace.json +20 -0
- package/.claude-plugin/plugin.json +2 -3
- package/.mcp.json +1 -2
- package/README.md +81 -22
- package/dist/catalogs/catalog-store.d.ts +10 -0
- package/dist/catalogs/catalog-store.d.ts.map +1 -1
- package/dist/catalogs/catalog-store.js +31 -0
- package/dist/catalogs/catalog-store.js.map +1 -1
- package/dist/diagnostics/bug-report-builder.d.ts +5 -0
- package/dist/diagnostics/bug-report-builder.d.ts.map +1 -0
- package/dist/diagnostics/bug-report-builder.js +112 -0
- package/dist/diagnostics/bug-report-builder.js.map +1 -0
- package/dist/diagnostics/ring-buffer.d.ts +16 -0
- package/dist/diagnostics/ring-buffer.d.ts.map +1 -0
- package/dist/diagnostics/ring-buffer.js +41 -0
- package/dist/diagnostics/ring-buffer.js.map +1 -0
- package/dist/diagnostics/session-trace.d.ts +19 -0
- package/dist/diagnostics/session-trace.d.ts.map +1 -0
- package/dist/diagnostics/session-trace.js +40 -0
- package/dist/diagnostics/session-trace.js.map +1 -0
- package/dist/diagnostics/tool-interceptor.d.ts +11 -0
- package/dist/diagnostics/tool-interceptor.d.ts.map +1 -0
- package/dist/diagnostics/tool-interceptor.js +73 -0
- package/dist/diagnostics/tool-interceptor.js.map +1 -0
- package/dist/diagnostics/types.d.ts +51 -0
- package/dist/diagnostics/types.d.ts.map +1 -0
- package/dist/diagnostics/types.js +2 -0
- package/dist/diagnostics/types.js.map +1 -0
- package/dist/diagnostics/valkyrie-log-finder.d.ts +12 -0
- package/dist/diagnostics/valkyrie-log-finder.d.ts.map +1 -0
- package/dist/diagnostics/valkyrie-log-finder.js +46 -0
- package/dist/diagnostics/valkyrie-log-finder.js.map +1 -0
- package/dist/io/localization-io.d.ts.map +1 -1
- package/dist/io/localization-io.js +3 -1
- package/dist/io/localization-io.js.map +1 -1
- package/dist/model/component-types.d.ts +1 -0
- package/dist/model/component-types.d.ts.map +1 -1
- package/dist/model/component-types.js +3 -0
- package/dist/model/component-types.js.map +1 -1
- package/dist/model/scenario-model.d.ts.map +1 -1
- package/dist/model/scenario-model.js +1 -0
- package/dist/model/scenario-model.js.map +1 -1
- package/dist/resources/format-docs.d.ts +3 -3
- package/dist/resources/format-docs.d.ts.map +1 -1
- package/dist/resources/format-docs.js +22 -3
- package/dist/resources/format-docs.js.map +1 -1
- package/dist/server.d.ts.map +1 -1
- package/dist/server.js +23 -0
- package/dist/server.js.map +1 -1
- package/dist/tools/lifecycle.d.ts.map +1 -1
- package/dist/tools/lifecycle.js +49 -11
- package/dist/tools/lifecycle.js.map +1 -1
- package/dist/tools/upsert.d.ts.map +1 -1
- package/dist/tools/upsert.js +143 -3
- package/dist/tools/upsert.js.map +1 -1
- package/dist/validation/rules/catalog-references.d.ts.map +1 -1
- package/dist/validation/rules/catalog-references.js +34 -9
- package/dist/validation/rules/catalog-references.js.map +1 -1
- package/dist/validation/rules/format-rules.d.ts.map +1 -1
- package/dist/validation/rules/format-rules.js +19 -0
- package/dist/validation/rules/format-rules.js.map +1 -1
- package/dist/validation/rules/localization-completeness.d.ts.map +1 -1
- package/dist/validation/rules/localization-completeness.js +15 -0
- package/dist/validation/rules/localization-completeness.js.map +1 -1
- package/dist/validation/rules/token-event-wiring.d.ts +8 -0
- package/dist/validation/rules/token-event-wiring.d.ts.map +1 -0
- package/dist/validation/rules/token-event-wiring.js +25 -0
- package/dist/validation/rules/token-event-wiring.js.map +1 -0
- package/dist/validation/validator.d.ts.map +1 -1
- package/dist/validation/validator.js +2 -0
- package/dist/validation/validator.js.map +1 -1
- package/package.json +4 -1
- package/src/catalogs/catalog-store.ts +34 -0
- package/src/diagnostics/bug-report-builder.ts +142 -0
- package/src/diagnostics/ring-buffer.ts +44 -0
- package/src/diagnostics/session-trace.ts +51 -0
- package/src/diagnostics/tool-interceptor.ts +74 -0
- package/src/diagnostics/types.ts +53 -0
- package/src/diagnostics/valkyrie-log-finder.ts +47 -0
- package/src/io/localization-io.ts +3 -1
- package/src/model/component-types.ts +3 -0
- package/src/model/scenario-model.ts +1 -0
- package/src/resources/format-docs.ts +22 -3
- package/src/server.ts +32 -0
- package/src/tools/lifecycle.ts +47 -12
- package/src/tools/upsert.ts +168 -3
- package/src/validation/rules/catalog-references.ts +35 -8
- package/src/validation/rules/format-rules.ts +20 -0
- package/src/validation/rules/localization-completeness.ts +16 -0
- package/src/validation/rules/token-event-wiring.ts +30 -0
- package/src/validation/validator.ts +2 -0
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
{
|
|
2
|
+
"$schema": "https://anthropic.com/claude-code/marketplace.schema.json",
|
|
3
|
+
"name": "valkyrie-mom",
|
|
4
|
+
"description": "Valkyrie Mansions of Madness scenario editor plugin and MCP server",
|
|
5
|
+
"owner": {
|
|
6
|
+
"name": "Thijs Hakkenberg"
|
|
7
|
+
},
|
|
8
|
+
"plugins": [
|
|
9
|
+
{
|
|
10
|
+
"name": "valkyrie-mom",
|
|
11
|
+
"description": "AI-assisted Mansions of Madness scenario editor for Valkyrie — MCP server, 7 skills, and scenario designer agent",
|
|
12
|
+
"version": "1.0.1",
|
|
13
|
+
"author": {
|
|
14
|
+
"name": "Thijs Hakkenberg"
|
|
15
|
+
},
|
|
16
|
+
"source": "./",
|
|
17
|
+
"category": "development"
|
|
18
|
+
}
|
|
19
|
+
]
|
|
20
|
+
}
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "valkyrie-mom",
|
|
3
|
-
"version": "1.0.
|
|
3
|
+
"version": "1.0.1",
|
|
4
4
|
"description": "AI-assisted Mansions of Madness scenario editor for Valkyrie",
|
|
5
5
|
"author": {
|
|
6
6
|
"name": "Thijs Hakkenberg"
|
|
@@ -10,8 +10,7 @@
|
|
|
10
10
|
"mcpServers": {
|
|
11
11
|
"valkyrie-mom": {
|
|
12
12
|
"command": "npx",
|
|
13
|
-
"args": ["
|
|
14
|
-
"cwd": "${CLAUDE_PLUGIN_ROOT}"
|
|
13
|
+
"args": ["-y", "@thijshakkenberg/valkyrie-mom-mcp"]
|
|
15
14
|
}
|
|
16
15
|
}
|
|
17
16
|
}
|
package/.mcp.json
CHANGED
package/README.md
CHANGED
|
@@ -1,47 +1,79 @@
|
|
|
1
1
|
# valkyrie-mom-mcp
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
[](https://www.npmjs.com/package/@thijshakkenberg/valkyrie-mom-mcp)
|
|
4
|
+
|
|
5
|
+
MCP (Model Context Protocol) server and Claude Code plugin for AI-assisted Mansions of Madness 2nd Edition scenario creation with [Valkyrie](https://github.com/NPBruce/valkyrie).
|
|
4
6
|
|
|
5
7
|
## What it does
|
|
6
8
|
|
|
7
9
|
This server exposes Valkyrie scenario editing as MCP tools, enabling AI assistants (Claude, etc.) to create, modify, validate, and build complete MoM scenarios. It auto-detects the Valkyrie editor directory so scenarios appear directly in the app.
|
|
8
10
|
|
|
9
|
-
|
|
11
|
+
The plugin bundles 7 skills covering advanced patterns (event loops, mythos scaling, tile placement chains, custom puzzles, etc.) and an autonomous scenario designer agent.
|
|
10
12
|
|
|
11
|
-
|
|
12
|
-
- [Valkyrie](https://github.com/NPBruce/valkyrie) (optional, for playing built scenarios)
|
|
13
|
+
## Install
|
|
13
14
|
|
|
14
|
-
|
|
15
|
+
### As a Claude Code plugin (recommended)
|
|
15
16
|
|
|
16
17
|
```bash
|
|
17
|
-
|
|
18
|
+
claude plugin marketplace add thijs-hakkenberg/ValkyrieMCP
|
|
19
|
+
claude plugin install valkyrie-mom
|
|
18
20
|
```
|
|
19
21
|
|
|
20
|
-
|
|
22
|
+
This gives you:
|
|
23
|
+
- **MCP server** with 20 tools for scenario editing (auto-started)
|
|
24
|
+
- **7 skills**: `/scenario`, `/event-patterns`, `/tile-placement`, `/variables-and-mythos`, `/custom-monsters`, `/ui-and-puzzles`, `/items-and-distribution`
|
|
25
|
+
- **Scenario designer agent** for autonomous scenario creation
|
|
26
|
+
- **5 MCP resources** for format documentation
|
|
21
27
|
|
|
22
|
-
|
|
28
|
+
To update to the latest version:
|
|
29
|
+
```bash
|
|
30
|
+
claude plugin marketplace update valkyrie-mom
|
|
31
|
+
claude plugin update valkyrie-mom
|
|
32
|
+
```
|
|
33
|
+
|
|
34
|
+
To uninstall:
|
|
35
|
+
```bash
|
|
36
|
+
claude plugin uninstall valkyrie-mom
|
|
37
|
+
```
|
|
38
|
+
|
|
39
|
+
### As a standalone MCP server (Claude Desktop, other MCP clients)
|
|
40
|
+
|
|
41
|
+
Add to your MCP client config (e.g., `~/.claude/mcp.json` or Claude Desktop settings):
|
|
23
42
|
|
|
24
43
|
```json
|
|
25
44
|
{
|
|
26
45
|
"mcpServers": {
|
|
27
46
|
"valkyrie-mom": {
|
|
28
47
|
"command": "npx",
|
|
29
|
-
"args": ["
|
|
30
|
-
"cwd": "/path/to/valkyrie_mom_mcp"
|
|
48
|
+
"args": ["-y", "@thijshakkenberg/valkyrie-mom-mcp"]
|
|
31
49
|
}
|
|
32
50
|
}
|
|
33
51
|
}
|
|
34
52
|
```
|
|
35
53
|
|
|
36
|
-
|
|
54
|
+
This gives you the MCP tools and resources, but not the skills or agent (those require Claude Code).
|
|
55
|
+
|
|
56
|
+
### From source
|
|
37
57
|
|
|
38
58
|
```bash
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
npm
|
|
42
|
-
|
|
59
|
+
git clone https://github.com/thijs-hakkenberg/ValkyrieMCP.git
|
|
60
|
+
cd ValkyrieMCP
|
|
61
|
+
npm install
|
|
62
|
+
npx tsx src/index.ts # Run MCP server via stdio
|
|
43
63
|
```
|
|
44
64
|
|
|
65
|
+
## Skills
|
|
66
|
+
|
|
67
|
+
| Skill | Description |
|
|
68
|
+
|-------|-------------|
|
|
69
|
+
| `/scenario` | Guided end-to-end scenario creation workflow |
|
|
70
|
+
| `/event-patterns` | Event loops, multi-question dialogues, silent events, token swaps, random events, variable branching |
|
|
71
|
+
| `/tile-placement` | Standard placement chains, multi-entry tiles, naming conventions |
|
|
72
|
+
| `/variables-and-mythos` | Variable system, mythos scaling formula, random generation, hero detection, content pack gating |
|
|
73
|
+
| `/custom-monsters` | Custom activations, evade/horror events, round-based spawn triggering |
|
|
74
|
+
| `/ui-and-puzzles` | Prologues, interactive journals, combination locks, built-in puzzle types |
|
|
75
|
+
| `/items-and-distribution` | Random items, unique items, starting items, inspection events |
|
|
76
|
+
|
|
45
77
|
## MCP Tools
|
|
46
78
|
|
|
47
79
|
### Lifecycle
|
|
@@ -77,7 +109,12 @@ npm run build # Compile to dist/
|
|
|
77
109
|
### Reference
|
|
78
110
|
| Tool | Description |
|
|
79
111
|
|------|-------------|
|
|
80
|
-
| `search_game_content` | Search game content catalogs |
|
|
112
|
+
| `search_game_content` | Search game content catalogs (846 entries across tiles, monsters, items, audio) |
|
|
113
|
+
|
|
114
|
+
### Diagnostics
|
|
115
|
+
| Tool | Description |
|
|
116
|
+
|------|-------------|
|
|
117
|
+
| `export_bug_report` | Generate a ZIP bug report with session trace, scenario files, validation results, and Valkyrie logs |
|
|
81
118
|
|
|
82
119
|
## MCP Resources
|
|
83
120
|
|
|
@@ -86,6 +123,7 @@ npm run build # Compile to dist/
|
|
|
86
123
|
| Event format docs | `valkyrie://format/events` |
|
|
87
124
|
| Localization format docs | `valkyrie://format/localization` |
|
|
88
125
|
| Component format docs | `valkyrie://format/components` |
|
|
126
|
+
| Pattern reference | `valkyrie://format/patterns` |
|
|
89
127
|
| Current scenario state | `valkyrie://scenario/current` |
|
|
90
128
|
|
|
91
129
|
## MCP Prompts
|
|
@@ -122,25 +160,45 @@ Built scenarios are ZIP archives with a `.valkyrie` extension.
|
|
|
122
160
|
|
|
123
161
|
## Validation Rules
|
|
124
162
|
|
|
125
|
-
The server validates scenarios against
|
|
163
|
+
The server validates scenarios against 12 rule categories:
|
|
126
164
|
|
|
127
165
|
1. **Unique names** - No duplicate component names
|
|
128
166
|
2. **Required fields** - Tiles have `side`, displayed events have `buttons`
|
|
129
|
-
3. **Cross-references** - All referenced components exist
|
|
167
|
+
3. **Cross-references** - All referenced components exist
|
|
130
168
|
4. **Event graph** - `EventStart` trigger exists, no unreachable/dead-end events
|
|
131
|
-
5. **
|
|
132
|
-
6. **
|
|
169
|
+
5. **Event flow** - Buttons vs event-ref consistency, silent event rules
|
|
170
|
+
6. **Localization completeness** - Event text, button labels, quest metadata
|
|
171
|
+
7. **Format rules** - Valid format version, type=MoM, tile rotations
|
|
172
|
+
8. **Catalog references** - Tile sides, monster names, items match game content
|
|
173
|
+
9. **Tile connectivity** - Tiles are spatially connected
|
|
174
|
+
10. **Mythos structure** - Proper mythos trigger configuration
|
|
175
|
+
11. **Investigator token** - TokenInvestigators setup and removal
|
|
176
|
+
12. **Explore token** - Explore tokens linked to tile reveal events
|
|
177
|
+
|
|
178
|
+
## Development
|
|
179
|
+
|
|
180
|
+
```bash
|
|
181
|
+
npm test # Run all tests (1096 tests across 36 files)
|
|
182
|
+
npm run test:watch # Watch mode
|
|
183
|
+
npm run lint # Type check
|
|
184
|
+
npm run build # Compile to dist/
|
|
185
|
+
```
|
|
133
186
|
|
|
134
187
|
## Project Structure
|
|
135
188
|
|
|
136
189
|
```
|
|
190
|
+
.claude-plugin/ Plugin manifest
|
|
191
|
+
skills/ 7 skill SKILL.md files
|
|
192
|
+
agents/ Scenario designer agent
|
|
137
193
|
src/
|
|
138
194
|
io/ INI parser/writer, localization CSV, ZIP packager
|
|
139
195
|
model/ ScenarioModel, LocalizationStore, component types
|
|
140
|
-
validation/
|
|
196
|
+
validation/ 12 rules + orchestrator
|
|
141
197
|
rules/ Individual validation rule implementations
|
|
142
198
|
tools/ MCP tool implementations
|
|
143
199
|
resources/ Format documentation resources
|
|
200
|
+
catalogs/ 846-entry game content catalog
|
|
201
|
+
diagnostics/ Bug report builder, session trace, ring buffer
|
|
144
202
|
server.ts MCP server registration
|
|
145
203
|
index.ts Entry point (stdio transport)
|
|
146
204
|
tests/
|
|
@@ -149,6 +207,7 @@ tests/
|
|
|
149
207
|
model/ Model layer tests
|
|
150
208
|
tools/ Tool tests
|
|
151
209
|
validation/ Validation rule tests
|
|
210
|
+
diagnostics/ Diagnostics tests
|
|
152
211
|
golden.test.ts Round-trip integrity tests
|
|
153
212
|
integration.test.ts Full pipeline tests
|
|
154
213
|
```
|
|
@@ -161,4 +220,4 @@ tests/
|
|
|
161
220
|
|
|
162
221
|
## License
|
|
163
222
|
|
|
164
|
-
|
|
223
|
+
MIT
|
|
@@ -1,4 +1,8 @@
|
|
|
1
1
|
import type { CatalogEntry, CatalogType } from './catalog-types.js';
|
|
2
|
+
/** Maps lowercase catalog pack IDs to Valkyrie's case-sensitive pack IDs */
|
|
3
|
+
export declare const PACK_ID_MAP: Record<string, string>;
|
|
4
|
+
/** Convert a catalog pack ID (lowercase) to Valkyrie's case-sensitive pack ID */
|
|
5
|
+
export declare function getValkyriePackId(catalogPack: string): string;
|
|
2
6
|
export declare class CatalogStore {
|
|
3
7
|
private entries;
|
|
4
8
|
private byId;
|
|
@@ -15,6 +19,12 @@ export declare class CatalogStore {
|
|
|
15
19
|
getByType(type: CatalogType): CatalogEntry[];
|
|
16
20
|
/** Get a Set of all entry IDs, optionally filtered by type. */
|
|
17
21
|
getAllIds(type?: CatalogType): Set<string>;
|
|
22
|
+
/** Get the Valkyrie pack ID for a catalog pack string */
|
|
23
|
+
getPackId(catalogPack: string): string;
|
|
24
|
+
/** Look up a tile side's pack from catalog, return Valkyrie pack ID */
|
|
25
|
+
getPackForTileSide(tileId: string): string | undefined;
|
|
26
|
+
/** Look up a monster's pack from catalog, return Valkyrie pack ID */
|
|
27
|
+
getPackForMonster(monsterId: string): string | undefined;
|
|
18
28
|
}
|
|
19
29
|
export declare function getSharedCatalog(): CatalogStore;
|
|
20
30
|
//# sourceMappingURL=catalog-store.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"catalog-store.d.ts","sourceRoot":"","sources":["../../src/catalogs/catalog-store.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,YAAY,EAAE,WAAW,EAAE,MAAM,oBAAoB,CAAC;AAYpE,qBAAa,YAAY;IACvB,OAAO,CAAC,OAAO,CAAiB;IAChC,OAAO,CAAC,IAAI,CAA4B;IACxC,OAAO,CAAC,MAAM,CAAmC;;IAoCjD;;;OAGG;IACH,MAAM,CAAC,KAAK,EAAE,MAAM,EAAE,IAAI,CAAC,EAAE,WAAW,GAAG,YAAY,EAAE;IAazD,uCAAuC;IACvC,OAAO,CAAC,EAAE,EAAE,MAAM,GAAG,YAAY,GAAG,SAAS;IAI7C,uCAAuC;IACvC,SAAS,CAAC,IAAI,EAAE,WAAW,GAAG,YAAY,EAAE;IAI5C,+DAA+D;IAC/D,SAAS,CAAC,IAAI,CAAC,EAAE,WAAW,GAAG,GAAG,CAAC,MAAM,CAAC;
|
|
1
|
+
{"version":3,"file":"catalog-store.d.ts","sourceRoot":"","sources":["../../src/catalogs/catalog-store.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,YAAY,EAAE,WAAW,EAAE,MAAM,oBAAoB,CAAC;AAYpE,4EAA4E;AAC5E,eAAO,MAAM,WAAW,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAO9C,CAAC;AAEF,iFAAiF;AACjF,wBAAgB,iBAAiB,CAAC,WAAW,EAAE,MAAM,GAAG,MAAM,CAE7D;AAED,qBAAa,YAAY;IACvB,OAAO,CAAC,OAAO,CAAiB;IAChC,OAAO,CAAC,IAAI,CAA4B;IACxC,OAAO,CAAC,MAAM,CAAmC;;IAoCjD;;;OAGG;IACH,MAAM,CAAC,KAAK,EAAE,MAAM,EAAE,IAAI,CAAC,EAAE,WAAW,GAAG,YAAY,EAAE;IAazD,uCAAuC;IACvC,OAAO,CAAC,EAAE,EAAE,MAAM,GAAG,YAAY,GAAG,SAAS;IAI7C,uCAAuC;IACvC,SAAS,CAAC,IAAI,EAAE,WAAW,GAAG,YAAY,EAAE;IAI5C,+DAA+D;IAC/D,SAAS,CAAC,IAAI,CAAC,EAAE,WAAW,GAAG,GAAG,CAAC,MAAM,CAAC;IAK1C,yDAAyD;IACzD,SAAS,CAAC,WAAW,EAAE,MAAM,GAAG,MAAM;IAItC,uEAAuE;IACvE,kBAAkB,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM,GAAG,SAAS;IAMtD,qEAAqE;IACrE,iBAAiB,CAAC,SAAS,EAAE,MAAM,GAAG,MAAM,GAAG,SAAS;CAKzD;AAKD,wBAAgB,gBAAgB,IAAI,YAAY,CAK/C"}
|
|
@@ -1,5 +1,18 @@
|
|
|
1
1
|
import { MONSTERS, TILES, AUDIO, ITEMS, INVESTIGATORS, PUZZLES, TOKENS, } from './data/all-catalogs.js';
|
|
2
2
|
import { TILE_GEOMETRY } from './data/tile-geometry.js';
|
|
3
|
+
/** Maps lowercase catalog pack IDs to Valkyrie's case-sensitive pack IDs */
|
|
4
|
+
export const PACK_ID_MAP = {
|
|
5
|
+
base: 'MoMBase',
|
|
6
|
+
btt: 'BtT',
|
|
7
|
+
hj: 'HJ',
|
|
8
|
+
pots: 'PotS',
|
|
9
|
+
soa: 'SoA',
|
|
10
|
+
sot: 'SoT',
|
|
11
|
+
};
|
|
12
|
+
/** Convert a catalog pack ID (lowercase) to Valkyrie's case-sensitive pack ID */
|
|
13
|
+
export function getValkyriePackId(catalogPack) {
|
|
14
|
+
return PACK_ID_MAP[catalogPack] ?? catalogPack;
|
|
15
|
+
}
|
|
3
16
|
export class CatalogStore {
|
|
4
17
|
entries;
|
|
5
18
|
byId;
|
|
@@ -66,6 +79,24 @@ export class CatalogStore {
|
|
|
66
79
|
const source = type ? (this.byType.get(type) ?? []) : this.entries;
|
|
67
80
|
return new Set(source.map(e => e.id));
|
|
68
81
|
}
|
|
82
|
+
/** Get the Valkyrie pack ID for a catalog pack string */
|
|
83
|
+
getPackId(catalogPack) {
|
|
84
|
+
return getValkyriePackId(catalogPack);
|
|
85
|
+
}
|
|
86
|
+
/** Look up a tile side's pack from catalog, return Valkyrie pack ID */
|
|
87
|
+
getPackForTileSide(tileId) {
|
|
88
|
+
const entry = this.byId.get(tileId);
|
|
89
|
+
if (!entry || entry.type !== 'tile')
|
|
90
|
+
return undefined;
|
|
91
|
+
return getValkyriePackId(entry.pack);
|
|
92
|
+
}
|
|
93
|
+
/** Look up a monster's pack from catalog, return Valkyrie pack ID */
|
|
94
|
+
getPackForMonster(monsterId) {
|
|
95
|
+
const entry = this.byId.get(monsterId);
|
|
96
|
+
if (!entry || entry.type !== 'monster')
|
|
97
|
+
return undefined;
|
|
98
|
+
return getValkyriePackId(entry.pack);
|
|
99
|
+
}
|
|
69
100
|
}
|
|
70
101
|
/** Shared singleton instance — avoids re-indexing 846 entries multiple times */
|
|
71
102
|
let sharedInstance = null;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"catalog-store.js","sourceRoot":"","sources":["../../src/catalogs/catalog-store.ts"],"names":[],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"catalog-store.js","sourceRoot":"","sources":["../../src/catalogs/catalog-store.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
import type { SessionTrace } from './session-trace.js';
|
|
2
|
+
import type { ScenarioModel } from '../model/scenario-model.js';
|
|
3
|
+
import type { BugReportOptions, BugReportResult } from './types.js';
|
|
4
|
+
export declare function buildBugReport(trace: SessionTrace, model: ScenarioModel | null, options?: BugReportOptions): Promise<BugReportResult>;
|
|
5
|
+
//# sourceMappingURL=bug-report-builder.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"bug-report-builder.d.ts","sourceRoot":"","sources":["../../src/diagnostics/bug-report-builder.ts"],"names":[],"mappings":"AAIA,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,oBAAoB,CAAC;AACvD,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,4BAA4B,CAAC;AAChE,OAAO,KAAK,EAAE,gBAAgB,EAAE,eAAe,EAAE,MAAM,YAAY,CAAC;AAqBpE,wBAAsB,cAAc,CAClC,KAAK,EAAE,YAAY,EACnB,KAAK,EAAE,aAAa,GAAG,IAAI,EAC3B,OAAO,GAAE,gBAAqB,GAC7B,OAAO,CAAC,eAAe,CAAC,CA8G1B"}
|
|
@@ -0,0 +1,112 @@
|
|
|
1
|
+
import archiver from 'archiver';
|
|
2
|
+
import * as fs from 'node:fs';
|
|
3
|
+
import * as os from 'node:os';
|
|
4
|
+
import * as path from 'node:path';
|
|
5
|
+
import { validateScenario } from '../validation/validator.js';
|
|
6
|
+
import { getValkyrieLogPath, readLogTail } from './valkyrie-log-finder.js';
|
|
7
|
+
const README_TEXT = `Valkyrie MoM MCP - Bug Report
|
|
8
|
+
==============================
|
|
9
|
+
|
|
10
|
+
This ZIP was generated by the export_bug_report tool.
|
|
11
|
+
|
|
12
|
+
Contents:
|
|
13
|
+
report.json - Session metadata and trace of MCP tool calls
|
|
14
|
+
validation.json - Validation results at time of export
|
|
15
|
+
scenario/ - Scenario INI files (if a scenario was loaded)
|
|
16
|
+
valkyrie-logs/ - Valkyrie Player.log tail (if found)
|
|
17
|
+
|
|
18
|
+
How to file an issue:
|
|
19
|
+
1. Go to https://github.com/thijs-hakkenberg/ValkyrieMCP/issues/new
|
|
20
|
+
2. Paste the issue template from the tool output
|
|
21
|
+
3. Drag and drop this ZIP file into the issue
|
|
22
|
+
`;
|
|
23
|
+
export async function buildBugReport(trace, model, options = {}) {
|
|
24
|
+
const { outputDir = os.tmpdir(), includeScenario = true, includeValkyrieLog = true, } = options;
|
|
25
|
+
const timestamp = new Date().toISOString().replace(/[:.]/g, '-');
|
|
26
|
+
const zipName = `valkyrie-bug-report-${timestamp}.zip`;
|
|
27
|
+
const zipPath = path.join(outputDir, zipName);
|
|
28
|
+
// Build ZIP
|
|
29
|
+
const output = fs.createWriteStream(zipPath);
|
|
30
|
+
const archive = archiver('zip');
|
|
31
|
+
const done = new Promise((resolve, reject) => {
|
|
32
|
+
output.on('close', resolve);
|
|
33
|
+
archive.on('error', reject);
|
|
34
|
+
});
|
|
35
|
+
archive.pipe(output);
|
|
36
|
+
// report.json
|
|
37
|
+
const metadata = trace.getMetadata();
|
|
38
|
+
const entries = trace.getEntries();
|
|
39
|
+
const report = {
|
|
40
|
+
metadata,
|
|
41
|
+
traceEntries: entries,
|
|
42
|
+
exportedAt: new Date().toISOString(),
|
|
43
|
+
};
|
|
44
|
+
archive.append(JSON.stringify(report, null, 2), { name: 'report.json' });
|
|
45
|
+
// validation.json
|
|
46
|
+
let validationData = { errors: [], warnings: [], note: 'No scenario loaded' };
|
|
47
|
+
if (model) {
|
|
48
|
+
const results = validateScenario(model);
|
|
49
|
+
const errors = results.filter(r => r.severity === 'error');
|
|
50
|
+
const warnings = results.filter(r => r.severity === 'warning');
|
|
51
|
+
validationData = { errors, warnings };
|
|
52
|
+
}
|
|
53
|
+
archive.append(JSON.stringify(validationData, null, 2), { name: 'validation.json' });
|
|
54
|
+
// README.txt
|
|
55
|
+
archive.append(README_TEXT, { name: 'README.txt' });
|
|
56
|
+
// scenario/ directory
|
|
57
|
+
if (includeScenario && model?.scenarioDir && fs.existsSync(model.scenarioDir)) {
|
|
58
|
+
const scenarioFiles = fs.readdirSync(model.scenarioDir);
|
|
59
|
+
for (const file of scenarioFiles) {
|
|
60
|
+
const filePath = path.join(model.scenarioDir, file);
|
|
61
|
+
if (fs.statSync(filePath).isFile()) {
|
|
62
|
+
archive.file(filePath, { name: `scenario/${file}` });
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
// valkyrie-logs/
|
|
67
|
+
if (includeValkyrieLog) {
|
|
68
|
+
const logPath = getValkyrieLogPath();
|
|
69
|
+
if (logPath) {
|
|
70
|
+
const logContent = await readLogTail(logPath);
|
|
71
|
+
if (logContent) {
|
|
72
|
+
archive.append(logContent, { name: 'valkyrie-logs/Player.log' });
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
}
|
|
76
|
+
await archive.finalize();
|
|
77
|
+
await done;
|
|
78
|
+
// Build issue template
|
|
79
|
+
const errorEntries = trace.getErrorEntries();
|
|
80
|
+
const allEntries = trace.getEntries();
|
|
81
|
+
const errorCount = errorEntries.length;
|
|
82
|
+
const validationErrors = model ? validateScenario(model).filter(r => r.severity === 'error').length : 0;
|
|
83
|
+
const validationWarnings = model ? validateScenario(model).filter(r => r.severity === 'warning').length : 0;
|
|
84
|
+
const recentErrors = errorEntries.slice(-5).map(e => `- \`${e.tool}\` (${e.timestamp}): ${e.resultSummary.replace(/^Error:\s*/, '').slice(0, 100)}`).join('\n');
|
|
85
|
+
const issueTitle = `[Bug Report] MCP session with ${allEntries.length} tool calls, ${errorCount} errors`;
|
|
86
|
+
const issueBody = `## Bug Report
|
|
87
|
+
|
|
88
|
+
**Environment:**
|
|
89
|
+
- MCP Server: v${metadata.serverVersion}
|
|
90
|
+
- Node: ${metadata.nodeVersion}
|
|
91
|
+
- Platform: ${metadata.platform} ${metadata.arch}
|
|
92
|
+
|
|
93
|
+
**Session Summary:**
|
|
94
|
+
- Tool calls: ${allEntries.length}
|
|
95
|
+
- Errors: ${errorCount}
|
|
96
|
+
- Validation: ${validationErrors} errors, ${validationWarnings} warnings
|
|
97
|
+
|
|
98
|
+
## What happened?
|
|
99
|
+
<!-- Describe what you expected vs. what actually happened -->
|
|
100
|
+
|
|
101
|
+
## Steps to reproduce
|
|
102
|
+
<!-- The session trace is in the attached ZIP -->
|
|
103
|
+
|
|
104
|
+
${recentErrors ? `## Recent errors from session trace\n${recentErrors}\n` : ''}
|
|
105
|
+
## Attachments
|
|
106
|
+
<!-- Drag and drop the .zip bug report file here -->
|
|
107
|
+
`;
|
|
108
|
+
const escapedTitle = issueTitle.replace(/"/g, '\\"');
|
|
109
|
+
const ghCommand = `gh issue create --repo thijs-hakkenberg/ValkyrieMCP --title "${escapedTitle}" --body-file -`;
|
|
110
|
+
return { zipPath, issueTitle, issueBody, ghCommand };
|
|
111
|
+
}
|
|
112
|
+
//# sourceMappingURL=bug-report-builder.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"bug-report-builder.js","sourceRoot":"","sources":["../../src/diagnostics/bug-report-builder.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Fixed-capacity circular buffer. When full, new items overwrite the oldest.
|
|
3
|
+
*/
|
|
4
|
+
export declare class RingBuffer<T> {
|
|
5
|
+
private buffer;
|
|
6
|
+
private head;
|
|
7
|
+
private count;
|
|
8
|
+
private readonly capacity;
|
|
9
|
+
constructor(capacity: number);
|
|
10
|
+
push(item: T): void;
|
|
11
|
+
get size(): number;
|
|
12
|
+
/** Returns entries oldest-first */
|
|
13
|
+
toArray(): T[];
|
|
14
|
+
clear(): void;
|
|
15
|
+
}
|
|
16
|
+
//# sourceMappingURL=ring-buffer.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"ring-buffer.d.ts","sourceRoot":"","sources":["../../src/diagnostics/ring-buffer.ts"],"names":[],"mappings":"AAAA;;GAEG;AACH,qBAAa,UAAU,CAAC,CAAC;IACvB,OAAO,CAAC,MAAM,CAAuB;IACrC,OAAO,CAAC,IAAI,CAAK;IACjB,OAAO,CAAC,KAAK,CAAK;IAClB,OAAO,CAAC,QAAQ,CAAC,QAAQ,CAAS;gBAEtB,QAAQ,EAAE,MAAM;IAK5B,IAAI,CAAC,IAAI,EAAE,CAAC,GAAG,IAAI;IAQnB,IAAI,IAAI,IAAI,MAAM,CAEjB;IAED,mCAAmC;IACnC,OAAO,IAAI,CAAC,EAAE;IAWd,KAAK,IAAI,IAAI;CAKd"}
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Fixed-capacity circular buffer. When full, new items overwrite the oldest.
|
|
3
|
+
*/
|
|
4
|
+
export class RingBuffer {
|
|
5
|
+
buffer;
|
|
6
|
+
head = 0; // next write position
|
|
7
|
+
count = 0;
|
|
8
|
+
capacity;
|
|
9
|
+
constructor(capacity) {
|
|
10
|
+
this.capacity = capacity;
|
|
11
|
+
this.buffer = new Array(capacity);
|
|
12
|
+
}
|
|
13
|
+
push(item) {
|
|
14
|
+
this.buffer[this.head] = item;
|
|
15
|
+
this.head = (this.head + 1) % this.capacity;
|
|
16
|
+
if (this.count < this.capacity) {
|
|
17
|
+
this.count++;
|
|
18
|
+
}
|
|
19
|
+
}
|
|
20
|
+
get size() {
|
|
21
|
+
return this.count;
|
|
22
|
+
}
|
|
23
|
+
/** Returns entries oldest-first */
|
|
24
|
+
toArray() {
|
|
25
|
+
if (this.count === 0)
|
|
26
|
+
return [];
|
|
27
|
+
const result = [];
|
|
28
|
+
const start = this.count < this.capacity ? 0 : this.head;
|
|
29
|
+
for (let i = 0; i < this.count; i++) {
|
|
30
|
+
const idx = (start + i) % this.capacity;
|
|
31
|
+
result.push(this.buffer[idx]);
|
|
32
|
+
}
|
|
33
|
+
return result;
|
|
34
|
+
}
|
|
35
|
+
clear() {
|
|
36
|
+
this.buffer = new Array(this.capacity);
|
|
37
|
+
this.head = 0;
|
|
38
|
+
this.count = 0;
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
//# sourceMappingURL=ring-buffer.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"ring-buffer.js","sourceRoot":"","sources":["../../src/diagnostics/ring-buffer.ts"],"names":[],"mappings":"AAAA;;GAEG;AACH,MAAM,OAAO,UAAU;IACb,MAAM,CAAuB;IAC7B,IAAI,GAAG,CAAC,CAAC,CAAG,sBAAsB;IAClC,KAAK,GAAG,CAAC,CAAC;IACD,QAAQ,CAAS;IAElC,YAAY,QAAgB;QAC1B,IAAI,CAAC,QAAQ,GAAG,QAAQ,CAAC;QACzB,IAAI,CAAC,MAAM,GAAG,IAAI,KAAK,CAAgB,QAAQ,CAAC,CAAC;IACnD,CAAC;IAED,IAAI,CAAC,IAAO;QACV,IAAI,CAAC,MAAM,CAAC,IAAI,CAAC,IAAI,CAAC,GAAG,IAAI,CAAC;QAC9B,IAAI,CAAC,IAAI,GAAG,CAAC,IAAI,CAAC,IAAI,GAAG,CAAC,CAAC,GAAG,IAAI,CAAC,QAAQ,CAAC;QAC5C,IAAI,IAAI,CAAC,KAAK,GAAG,IAAI,CAAC,QAAQ,EAAE,CAAC;YAC/B,IAAI,CAAC,KAAK,EAAE,CAAC;QACf,CAAC;IACH,CAAC;IAED,IAAI,IAAI;QACN,OAAO,IAAI,CAAC,KAAK,CAAC;IACpB,CAAC;IAED,mCAAmC;IACnC,OAAO;QACL,IAAI,IAAI,CAAC,KAAK,KAAK,CAAC;YAAE,OAAO,EAAE,CAAC;QAChC,MAAM,MAAM,GAAQ,EAAE,CAAC;QACvB,MAAM,KAAK,GAAG,IAAI,CAAC,KAAK,GAAG,IAAI,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC;QACzD,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,IAAI,CAAC,KAAK,EAAE,CAAC,EAAE,EAAE,CAAC;YACpC,MAAM,GAAG,GAAG,CAAC,KAAK,GAAG,CAAC,CAAC,GAAG,IAAI,CAAC,QAAQ,CAAC;YACxC,MAAM,CAAC,IAAI,CAAC,IAAI,CAAC,MAAM,CAAC,GAAG,CAAM,CAAC,CAAC;QACrC,CAAC;QACD,OAAO,MAAM,CAAC;IAChB,CAAC;IAED,KAAK;QACH,IAAI,CAAC,MAAM,GAAG,IAAI,KAAK,CAAgB,IAAI,CAAC,QAAQ,CAAC,CAAC;QACtD,IAAI,CAAC,IAAI,GAAG,CAAC,CAAC;QACd,IAAI,CAAC,KAAK,GAAG,CAAC,CAAC;IACjB,CAAC;CACF"}
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import type { TraceEntry, SessionMetadata } from './types.js';
|
|
2
|
+
/** Omit timestamp — it's auto-filled by record() */
|
|
3
|
+
type TraceInput = Omit<TraceEntry, 'timestamp'>;
|
|
4
|
+
/**
|
|
5
|
+
* In-memory session trace. Records MCP tool calls in a ring buffer.
|
|
6
|
+
* Nothing is written to disk until explicitly exported.
|
|
7
|
+
*/
|
|
8
|
+
export declare class SessionTrace {
|
|
9
|
+
private buffer;
|
|
10
|
+
private metadata;
|
|
11
|
+
constructor(serverVersion: string, capacity?: number);
|
|
12
|
+
record(input: TraceInput): void;
|
|
13
|
+
getEntries(): TraceEntry[];
|
|
14
|
+
getErrorEntries(): TraceEntry[];
|
|
15
|
+
getMetadata(): SessionMetadata;
|
|
16
|
+
updateScenario(dir: string): void;
|
|
17
|
+
}
|
|
18
|
+
export {};
|
|
19
|
+
//# sourceMappingURL=session-trace.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"session-trace.d.ts","sourceRoot":"","sources":["../../src/diagnostics/session-trace.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,UAAU,EAAE,eAAe,EAAE,MAAM,YAAY,CAAC;AAI9D,oDAAoD;AACpD,KAAK,UAAU,GAAG,IAAI,CAAC,UAAU,EAAE,WAAW,CAAC,CAAC;AAEhD;;;GAGG;AACH,qBAAa,YAAY;IACvB,OAAO,CAAC,MAAM,CAAyB;IACvC,OAAO,CAAC,QAAQ,CAAkB;gBAEtB,aAAa,EAAE,MAAM,EAAE,QAAQ,SAAmB;IAW9D,MAAM,CAAC,KAAK,EAAE,UAAU,GAAG,IAAI;IAO/B,UAAU,IAAI,UAAU,EAAE;IAI1B,eAAe,IAAI,UAAU,EAAE;IAI/B,WAAW,IAAI,eAAe;IAI9B,cAAc,CAAC,GAAG,EAAE,MAAM,GAAG,IAAI;CAGlC"}
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
import * as os from 'node:os';
|
|
2
|
+
import { RingBuffer } from './ring-buffer.js';
|
|
3
|
+
const DEFAULT_CAPACITY = 200;
|
|
4
|
+
/**
|
|
5
|
+
* In-memory session trace. Records MCP tool calls in a ring buffer.
|
|
6
|
+
* Nothing is written to disk until explicitly exported.
|
|
7
|
+
*/
|
|
8
|
+
export class SessionTrace {
|
|
9
|
+
buffer;
|
|
10
|
+
metadata;
|
|
11
|
+
constructor(serverVersion, capacity = DEFAULT_CAPACITY) {
|
|
12
|
+
this.buffer = new RingBuffer(capacity);
|
|
13
|
+
this.metadata = {
|
|
14
|
+
serverVersion,
|
|
15
|
+
nodeVersion: process.version,
|
|
16
|
+
platform: os.platform(),
|
|
17
|
+
arch: os.arch(),
|
|
18
|
+
startedAt: new Date().toISOString(),
|
|
19
|
+
};
|
|
20
|
+
}
|
|
21
|
+
record(input) {
|
|
22
|
+
this.buffer.push({
|
|
23
|
+
...input,
|
|
24
|
+
timestamp: new Date().toISOString(),
|
|
25
|
+
});
|
|
26
|
+
}
|
|
27
|
+
getEntries() {
|
|
28
|
+
return this.buffer.toArray();
|
|
29
|
+
}
|
|
30
|
+
getErrorEntries() {
|
|
31
|
+
return this.buffer.toArray().filter(e => e.isError);
|
|
32
|
+
}
|
|
33
|
+
getMetadata() {
|
|
34
|
+
return { ...this.metadata };
|
|
35
|
+
}
|
|
36
|
+
updateScenario(dir) {
|
|
37
|
+
this.metadata.scenarioDir = dir;
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
//# sourceMappingURL=session-trace.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"session-trace.js","sourceRoot":"","sources":["../../src/diagnostics/session-trace.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,MAAM,SAAS,CAAC;AAC9B,OAAO,EAAE,UAAU,EAAE,MAAM,kBAAkB,CAAC;AAG9C,MAAM,gBAAgB,GAAG,GAAG,CAAC;AAK7B;;;GAGG;AACH,MAAM,OAAO,YAAY;IACf,MAAM,CAAyB;IAC/B,QAAQ,CAAkB;IAElC,YAAY,aAAqB,EAAE,QAAQ,GAAG,gBAAgB;QAC5D,IAAI,CAAC,MAAM,GAAG,IAAI,UAAU,CAAa,QAAQ,CAAC,CAAC;QACnD,IAAI,CAAC,QAAQ,GAAG;YACd,aAAa;YACb,WAAW,EAAE,OAAO,CAAC,OAAO;YAC5B,QAAQ,EAAE,EAAE,CAAC,QAAQ,EAAE;YACvB,IAAI,EAAE,EAAE,CAAC,IAAI,EAAE;YACf,SAAS,EAAE,IAAI,IAAI,EAAE,CAAC,WAAW,EAAE;SACpC,CAAC;IACJ,CAAC;IAED,MAAM,CAAC,KAAiB;QACtB,IAAI,CAAC,MAAM,CAAC,IAAI,CAAC;YACf,GAAG,KAAK;YACR,SAAS,EAAE,IAAI,IAAI,EAAE,CAAC,WAAW,EAAE;SACpC,CAAC,CAAC;IACL,CAAC;IAED,UAAU;QACR,OAAO,IAAI,CAAC,MAAM,CAAC,OAAO,EAAE,CAAC;IAC/B,CAAC;IAED,eAAe;QACb,OAAO,IAAI,CAAC,MAAM,CAAC,OAAO,EAAE,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC;IACtD,CAAC;IAED,WAAW;QACT,OAAO,EAAE,GAAG,IAAI,CAAC,QAAQ,EAAE,CAAC;IAC9B,CAAC;IAED,cAAc,CAAC,GAAW;QACxB,IAAI,CAAC,QAAQ,CAAC,WAAW,GAAG,GAAG,CAAC;IAClC,CAAC;CACF"}
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import type { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';
|
|
2
|
+
import type { SessionTrace } from './session-trace.js';
|
|
3
|
+
/** Truncate string values in args to prevent huge trace entries */
|
|
4
|
+
export declare function sanitizeArgs(args: Record<string, unknown> | undefined): Record<string, unknown>;
|
|
5
|
+
/**
|
|
6
|
+
* Wrap all registered tool handlers to record calls to the session trace.
|
|
7
|
+
* Must be called after all tools are registered. Skips `export_bug_report`
|
|
8
|
+
* to avoid circular recording.
|
|
9
|
+
*/
|
|
10
|
+
export declare function wrapAllTools(server: McpServer, trace: SessionTrace): void;
|
|
11
|
+
//# sourceMappingURL=tool-interceptor.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"tool-interceptor.d.ts","sourceRoot":"","sources":["../../src/diagnostics/tool-interceptor.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,yCAAyC,CAAC;AACzE,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,oBAAoB,CAAC;AAKvD,mEAAmE;AACnE,wBAAgB,YAAY,CAAC,IAAI,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,SAAS,GAAG,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAW/F;AAgBD;;;;GAIG;AACH,wBAAgB,YAAY,CAAC,MAAM,EAAE,SAAS,EAAE,KAAK,EAAE,YAAY,GAAG,IAAI,CAkCzE"}
|