@thijshakkenberg/valkyrie-mom-mcp 1.0.1 → 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.
Files changed (88) hide show
  1. package/README.md +9 -2
  2. package/dist/catalogs/catalog-store.d.ts +10 -0
  3. package/dist/catalogs/catalog-store.d.ts.map +1 -1
  4. package/dist/catalogs/catalog-store.js +31 -0
  5. package/dist/catalogs/catalog-store.js.map +1 -1
  6. package/dist/diagnostics/bug-report-builder.d.ts +5 -0
  7. package/dist/diagnostics/bug-report-builder.d.ts.map +1 -0
  8. package/dist/diagnostics/bug-report-builder.js +112 -0
  9. package/dist/diagnostics/bug-report-builder.js.map +1 -0
  10. package/dist/diagnostics/ring-buffer.d.ts +16 -0
  11. package/dist/diagnostics/ring-buffer.d.ts.map +1 -0
  12. package/dist/diagnostics/ring-buffer.js +41 -0
  13. package/dist/diagnostics/ring-buffer.js.map +1 -0
  14. package/dist/diagnostics/session-trace.d.ts +19 -0
  15. package/dist/diagnostics/session-trace.d.ts.map +1 -0
  16. package/dist/diagnostics/session-trace.js +40 -0
  17. package/dist/diagnostics/session-trace.js.map +1 -0
  18. package/dist/diagnostics/tool-interceptor.d.ts +11 -0
  19. package/dist/diagnostics/tool-interceptor.d.ts.map +1 -0
  20. package/dist/diagnostics/tool-interceptor.js +73 -0
  21. package/dist/diagnostics/tool-interceptor.js.map +1 -0
  22. package/dist/diagnostics/types.d.ts +51 -0
  23. package/dist/diagnostics/types.d.ts.map +1 -0
  24. package/dist/diagnostics/types.js +2 -0
  25. package/dist/diagnostics/types.js.map +1 -0
  26. package/dist/diagnostics/valkyrie-log-finder.d.ts +12 -0
  27. package/dist/diagnostics/valkyrie-log-finder.d.ts.map +1 -0
  28. package/dist/diagnostics/valkyrie-log-finder.js +46 -0
  29. package/dist/diagnostics/valkyrie-log-finder.js.map +1 -0
  30. package/dist/io/localization-io.d.ts.map +1 -1
  31. package/dist/io/localization-io.js +3 -1
  32. package/dist/io/localization-io.js.map +1 -1
  33. package/dist/model/component-types.d.ts +1 -0
  34. package/dist/model/component-types.d.ts.map +1 -1
  35. package/dist/model/component-types.js +3 -0
  36. package/dist/model/component-types.js.map +1 -1
  37. package/dist/model/scenario-model.d.ts.map +1 -1
  38. package/dist/model/scenario-model.js +1 -0
  39. package/dist/model/scenario-model.js.map +1 -1
  40. package/dist/resources/format-docs.d.ts +3 -3
  41. package/dist/resources/format-docs.d.ts.map +1 -1
  42. package/dist/resources/format-docs.js +22 -3
  43. package/dist/resources/format-docs.js.map +1 -1
  44. package/dist/server.d.ts.map +1 -1
  45. package/dist/server.js +23 -0
  46. package/dist/server.js.map +1 -1
  47. package/dist/tools/lifecycle.d.ts.map +1 -1
  48. package/dist/tools/lifecycle.js +49 -11
  49. package/dist/tools/lifecycle.js.map +1 -1
  50. package/dist/tools/upsert.d.ts.map +1 -1
  51. package/dist/tools/upsert.js +143 -3
  52. package/dist/tools/upsert.js.map +1 -1
  53. package/dist/validation/rules/catalog-references.d.ts.map +1 -1
  54. package/dist/validation/rules/catalog-references.js +34 -9
  55. package/dist/validation/rules/catalog-references.js.map +1 -1
  56. package/dist/validation/rules/format-rules.d.ts.map +1 -1
  57. package/dist/validation/rules/format-rules.js +19 -0
  58. package/dist/validation/rules/format-rules.js.map +1 -1
  59. package/dist/validation/rules/localization-completeness.d.ts.map +1 -1
  60. package/dist/validation/rules/localization-completeness.js +15 -0
  61. package/dist/validation/rules/localization-completeness.js.map +1 -1
  62. package/dist/validation/rules/token-event-wiring.d.ts +8 -0
  63. package/dist/validation/rules/token-event-wiring.d.ts.map +1 -0
  64. package/dist/validation/rules/token-event-wiring.js +25 -0
  65. package/dist/validation/rules/token-event-wiring.js.map +1 -0
  66. package/dist/validation/validator.d.ts.map +1 -1
  67. package/dist/validation/validator.js +2 -0
  68. package/dist/validation/validator.js.map +1 -1
  69. package/package.json +1 -1
  70. package/src/catalogs/catalog-store.ts +34 -0
  71. package/src/diagnostics/bug-report-builder.ts +142 -0
  72. package/src/diagnostics/ring-buffer.ts +44 -0
  73. package/src/diagnostics/session-trace.ts +51 -0
  74. package/src/diagnostics/tool-interceptor.ts +74 -0
  75. package/src/diagnostics/types.ts +53 -0
  76. package/src/diagnostics/valkyrie-log-finder.ts +47 -0
  77. package/src/io/localization-io.ts +3 -1
  78. package/src/model/component-types.ts +3 -0
  79. package/src/model/scenario-model.ts +1 -0
  80. package/src/resources/format-docs.ts +22 -3
  81. package/src/server.ts +32 -0
  82. package/src/tools/lifecycle.ts +47 -12
  83. package/src/tools/upsert.ts +168 -3
  84. package/src/validation/rules/catalog-references.ts +35 -8
  85. package/src/validation/rules/format-rules.ts +20 -0
  86. package/src/validation/rules/localization-completeness.ts +16 -0
  87. package/src/validation/rules/token-event-wiring.ts +30 -0
  88. package/src/validation/validator.ts +2 -0
package/README.md CHANGED
@@ -20,7 +20,7 @@ claude plugin install valkyrie-mom
20
20
  ```
21
21
 
22
22
  This gives you:
23
- - **MCP server** with 16 tools for scenario editing (auto-started)
23
+ - **MCP server** with 20 tools for scenario editing (auto-started)
24
24
  - **7 skills**: `/scenario`, `/event-patterns`, `/tile-placement`, `/variables-and-mythos`, `/custom-monsters`, `/ui-and-puzzles`, `/items-and-distribution`
25
25
  - **Scenario designer agent** for autonomous scenario creation
26
26
  - **5 MCP resources** for format documentation
@@ -111,6 +111,11 @@ npx tsx src/index.ts # Run MCP server via stdio
111
111
  |------|-------------|
112
112
  | `search_game_content` | Search game content catalogs (846 entries across tiles, monsters, items, audio) |
113
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 |
118
+
114
119
  ## MCP Resources
115
120
 
116
121
  | Resource | URI |
@@ -173,7 +178,7 @@ The server validates scenarios against 12 rule categories:
173
178
  ## Development
174
179
 
175
180
  ```bash
176
- npm test # Run all tests (1015 tests across 30 files)
181
+ npm test # Run all tests (1096 tests across 36 files)
177
182
  npm run test:watch # Watch mode
178
183
  npm run lint # Type check
179
184
  npm run build # Compile to dist/
@@ -193,6 +198,7 @@ src/
193
198
  tools/ MCP tool implementations
194
199
  resources/ Format documentation resources
195
200
  catalogs/ 846-entry game content catalog
201
+ diagnostics/ Bug report builder, session trace, ring buffer
196
202
  server.ts MCP server registration
197
203
  index.ts Entry point (stdio transport)
198
204
  tests/
@@ -201,6 +207,7 @@ tests/
201
207
  model/ Model layer tests
202
208
  tools/ Tool tests
203
209
  validation/ Validation rule tests
210
+ diagnostics/ Diagnostics tests
204
211
  golden.test.ts Round-trip integrity tests
205
212
  integration.test.ts Full pipeline tests
206
213
  ```
@@ -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;CAI3C;AAKD,wBAAgB,gBAAgB,IAAI,YAAY,CAK/C"}
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"}
@@ -0,0 +1,73 @@
1
+ const MAX_ARG_LENGTH = 200;
2
+ const MAX_RESULT_LENGTH = 500;
3
+ /** Truncate string values in args to prevent huge trace entries */
4
+ export function sanitizeArgs(args) {
5
+ if (!args || typeof args !== 'object')
6
+ return {};
7
+ const result = {};
8
+ for (const [key, value] of Object.entries(args)) {
9
+ if (typeof value === 'string' && value.length > MAX_ARG_LENGTH) {
10
+ result[key] = value.slice(0, MAX_ARG_LENGTH) + '...';
11
+ }
12
+ else {
13
+ result[key] = value;
14
+ }
15
+ }
16
+ return result;
17
+ }
18
+ function summarizeResult(result) {
19
+ try {
20
+ const text = result?.content?.[0]?.text;
21
+ if (typeof text === 'string') {
22
+ return text.length > MAX_RESULT_LENGTH
23
+ ? text.slice(0, MAX_RESULT_LENGTH) + '...'
24
+ : text;
25
+ }
26
+ return JSON.stringify(result).slice(0, MAX_RESULT_LENGTH);
27
+ }
28
+ catch {
29
+ return '[unserializable]';
30
+ }
31
+ }
32
+ /**
33
+ * Wrap all registered tool handlers to record calls to the session trace.
34
+ * Must be called after all tools are registered. Skips `export_bug_report`
35
+ * to avoid circular recording.
36
+ */
37
+ export function wrapAllTools(server, trace) {
38
+ const tools = server._registeredTools;
39
+ if (!tools || typeof tools !== 'object')
40
+ return;
41
+ for (const [name, entry] of Object.entries(tools)) {
42
+ if (name === 'export_bug_report')
43
+ continue;
44
+ const originalHandler = entry.handler;
45
+ entry.handler = async (...handlerArgs) => {
46
+ const start = Date.now();
47
+ try {
48
+ const result = await originalHandler(...handlerArgs);
49
+ const durationMs = Date.now() - start;
50
+ trace.record({
51
+ tool: name,
52
+ args: sanitizeArgs(handlerArgs[0]),
53
+ resultSummary: summarizeResult(result),
54
+ isError: !!result?.isError,
55
+ durationMs,
56
+ });
57
+ return result;
58
+ }
59
+ catch (err) {
60
+ const durationMs = Date.now() - start;
61
+ trace.record({
62
+ tool: name,
63
+ args: sanitizeArgs(handlerArgs[0]),
64
+ resultSummary: `Error: ${err?.message ?? String(err)}`,
65
+ isError: true,
66
+ durationMs,
67
+ });
68
+ throw err;
69
+ }
70
+ };
71
+ }
72
+ }
73
+ //# sourceMappingURL=tool-interceptor.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"tool-interceptor.js","sourceRoot":"","sources":["../../src/diagnostics/tool-interceptor.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,51 @@
1
+ /** A single trace entry recording one MCP tool call */
2
+ export interface TraceEntry {
3
+ /** Tool name that was called */
4
+ tool: string;
5
+ /** Sanitized arguments (long strings truncated) */
6
+ args: Record<string, unknown>;
7
+ /** Result summary (truncated) */
8
+ resultSummary: string;
9
+ /** Whether the call resulted in an error */
10
+ isError: boolean;
11
+ /** Duration in milliseconds */
12
+ durationMs: number;
13
+ /** ISO 8601 timestamp */
14
+ timestamp: string;
15
+ }
16
+ /** Session-level metadata captured at startup */
17
+ export interface SessionMetadata {
18
+ /** MCP server version */
19
+ serverVersion: string;
20
+ /** Node.js version */
21
+ nodeVersion: string;
22
+ /** OS platform */
23
+ platform: string;
24
+ /** OS architecture */
25
+ arch: string;
26
+ /** Session start time (ISO 8601) */
27
+ startedAt: string;
28
+ /** Currently loaded scenario directory, if any */
29
+ scenarioDir?: string;
30
+ }
31
+ /** Options for building a bug report */
32
+ export interface BugReportOptions {
33
+ /** Directory to write the ZIP file to (defaults to os.tmpdir()) */
34
+ outputDir?: string;
35
+ /** Include scenario INI files in the ZIP (default true) */
36
+ includeScenario?: boolean;
37
+ /** Include Valkyrie Player.log in the ZIP (default true) */
38
+ includeValkyrieLog?: boolean;
39
+ }
40
+ /** Result returned by buildBugReport */
41
+ export interface BugReportResult {
42
+ /** Absolute path to the generated ZIP file */
43
+ zipPath: string;
44
+ /** Suggested GitHub issue title */
45
+ issueTitle: string;
46
+ /** Pre-filled GitHub issue body (markdown) */
47
+ issueBody: string;
48
+ /** Ready-to-run gh CLI command */
49
+ ghCommand: string;
50
+ }
51
+ //# sourceMappingURL=types.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../src/diagnostics/types.ts"],"names":[],"mappings":"AAAA,uDAAuD;AACvD,MAAM,WAAW,UAAU;IACzB,gCAAgC;IAChC,IAAI,EAAE,MAAM,CAAC;IACb,mDAAmD;IACnD,IAAI,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IAC9B,iCAAiC;IACjC,aAAa,EAAE,MAAM,CAAC;IACtB,4CAA4C;IAC5C,OAAO,EAAE,OAAO,CAAC;IACjB,+BAA+B;IAC/B,UAAU,EAAE,MAAM,CAAC;IACnB,yBAAyB;IACzB,SAAS,EAAE,MAAM,CAAC;CACnB;AAED,iDAAiD;AACjD,MAAM,WAAW,eAAe;IAC9B,yBAAyB;IACzB,aAAa,EAAE,MAAM,CAAC;IACtB,sBAAsB;IACtB,WAAW,EAAE,MAAM,CAAC;IACpB,kBAAkB;IAClB,QAAQ,EAAE,MAAM,CAAC;IACjB,sBAAsB;IACtB,IAAI,EAAE,MAAM,CAAC;IACb,oCAAoC;IACpC,SAAS,EAAE,MAAM,CAAC;IAClB,kDAAkD;IAClD,WAAW,CAAC,EAAE,MAAM,CAAC;CACtB;AAED,wCAAwC;AACxC,MAAM,WAAW,gBAAgB;IAC/B,mEAAmE;IACnE,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,2DAA2D;IAC3D,eAAe,CAAC,EAAE,OAAO,CAAC;IAC1B,4DAA4D;IAC5D,kBAAkB,CAAC,EAAE,OAAO,CAAC;CAC9B;AAED,wCAAwC;AACxC,MAAM,WAAW,eAAe;IAC9B,8CAA8C;IAC9C,OAAO,EAAE,MAAM,CAAC;IAChB,mCAAmC;IACnC,UAAU,EAAE,MAAM,CAAC;IACnB,8CAA8C;IAC9C,SAAS,EAAE,MAAM,CAAC;IAClB,kCAAkC;IAClC,SAAS,EAAE,MAAM,CAAC;CACnB"}
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=types.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types.js","sourceRoot":"","sources":["../../src/diagnostics/types.ts"],"names":[],"mappings":""}
@@ -0,0 +1,12 @@
1
+ /**
2
+ * Get the expected Valkyrie Player.log path for a given platform.
3
+ * Mirrors Unity's log locations with Company=NA, Product=Valkyrie.
4
+ */
5
+ export declare function getValkyrieLogPath(platform?: string): string | undefined;
6
+ /**
7
+ * Read the tail of a log file. Returns undefined if the file doesn't exist.
8
+ * @param logPath Absolute path to the log file
9
+ * @param maxBytes Maximum bytes to read from the end (default 1MB)
10
+ */
11
+ export declare function readLogTail(logPath: string, maxBytes?: number): Promise<string | undefined>;
12
+ //# sourceMappingURL=valkyrie-log-finder.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"valkyrie-log-finder.d.ts","sourceRoot":"","sources":["../../src/diagnostics/valkyrie-log-finder.ts"],"names":[],"mappings":"AAIA;;;GAGG;AACH,wBAAgB,kBAAkB,CAAC,QAAQ,CAAC,EAAE,MAAM,GAAG,MAAM,GAAG,SAAS,CAgBxE;AAED;;;;GAIG;AACH,wBAAsB,WAAW,CAAC,OAAO,EAAE,MAAM,EAAE,QAAQ,SAAc,GAAG,OAAO,CAAC,MAAM,GAAG,SAAS,CAAC,CAetG"}
@@ -0,0 +1,46 @@
1
+ import * as fs from 'node:fs';
2
+ import * as os from 'node:os';
3
+ import * as path from 'node:path';
4
+ /**
5
+ * Get the expected Valkyrie Player.log path for a given platform.
6
+ * Mirrors Unity's log locations with Company=NA, Product=Valkyrie.
7
+ */
8
+ export function getValkyrieLogPath(platform) {
9
+ const p = platform ?? os.platform();
10
+ const home = os.homedir();
11
+ switch (p) {
12
+ case 'darwin':
13
+ return path.join(home, 'Library', 'Logs', 'Unity', 'Player.log');
14
+ case 'win32': {
15
+ const localAppData = process.env.LOCALAPPDATA ?? path.join(home, 'AppData', 'Local');
16
+ return path.join(localAppData, '..', 'LocalLow', 'NA', 'Valkyrie', 'Player.log');
17
+ }
18
+ case 'linux':
19
+ return path.join(home, '.config', 'unity3d', 'NA', 'Valkyrie', 'Player.log');
20
+ default:
21
+ return undefined;
22
+ }
23
+ }
24
+ /**
25
+ * Read the tail of a log file. Returns undefined if the file doesn't exist.
26
+ * @param logPath Absolute path to the log file
27
+ * @param maxBytes Maximum bytes to read from the end (default 1MB)
28
+ */
29
+ export async function readLogTail(logPath, maxBytes = 1024 * 1024) {
30
+ try {
31
+ const stat = fs.statSync(logPath);
32
+ if (stat.size <= maxBytes) {
33
+ return fs.readFileSync(logPath, 'utf-8');
34
+ }
35
+ // Read last maxBytes from file
36
+ const fd = fs.openSync(logPath, 'r');
37
+ const buffer = Buffer.alloc(maxBytes);
38
+ fs.readSync(fd, buffer, 0, maxBytes, stat.size - maxBytes);
39
+ fs.closeSync(fd);
40
+ return buffer.toString('utf-8');
41
+ }
42
+ catch {
43
+ return undefined;
44
+ }
45
+ }
46
+ //# sourceMappingURL=valkyrie-log-finder.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"valkyrie-log-finder.js","sourceRoot":"","sources":["../../src/diagnostics/valkyrie-log-finder.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,MAAM,SAAS,CAAC;AAC9B,OAAO,KAAK,EAAE,MAAM,SAAS,CAAC;AAC9B,OAAO,KAAK,IAAI,MAAM,WAAW,CAAC;AAElC;;;GAGG;AACH,MAAM,UAAU,kBAAkB,CAAC,QAAiB;IAClD,MAAM,CAAC,GAAG,QAAQ,IAAI,EAAE,CAAC,QAAQ,EAAE,CAAC;IACpC,MAAM,IAAI,GAAG,EAAE,CAAC,OAAO,EAAE,CAAC;IAE1B,QAAQ,CAAC,EAAE,CAAC;QACV,KAAK,QAAQ;YACX,OAAO,IAAI,CAAC,IAAI,CAAC,IAAI,EAAE,SAAS,EAAE,MAAM,EAAE,OAAO,EAAE,YAAY,CAAC,CAAC;QACnE,KAAK,OAAO,CAAC,CAAC,CAAC;YACb,MAAM,YAAY,GAAG,OAAO,CAAC,GAAG,CAAC,YAAY,IAAI,IAAI,CAAC,IAAI,CAAC,IAAI,EAAE,SAAS,EAAE,OAAO,CAAC,CAAC;YACrF,OAAO,IAAI,CAAC,IAAI,CAAC,YAAY,EAAE,IAAI,EAAE,UAAU,EAAE,IAAI,EAAE,UAAU,EAAE,YAAY,CAAC,CAAC;QACnF,CAAC;QACD,KAAK,OAAO;YACV,OAAO,IAAI,CAAC,IAAI,CAAC,IAAI,EAAE,SAAS,EAAE,SAAS,EAAE,IAAI,EAAE,UAAU,EAAE,YAAY,CAAC,CAAC;QAC/E;YACE,OAAO,SAAS,CAAC;IACrB,CAAC;AACH,CAAC;AAED;;;;GAIG;AACH,MAAM,CAAC,KAAK,UAAU,WAAW,CAAC,OAAe,EAAE,QAAQ,GAAG,IAAI,GAAG,IAAI;IACvE,IAAI,CAAC;QACH,MAAM,IAAI,GAAG,EAAE,CAAC,QAAQ,CAAC,OAAO,CAAC,CAAC;QAClC,IAAI,IAAI,CAAC,IAAI,IAAI,QAAQ,EAAE,CAAC;YAC1B,OAAO,EAAE,CAAC,YAAY,CAAC,OAAO,EAAE,OAAO,CAAC,CAAC;QAC3C,CAAC;QACD,+BAA+B;QAC/B,MAAM,EAAE,GAAG,EAAE,CAAC,QAAQ,CAAC,OAAO,EAAE,GAAG,CAAC,CAAC;QACrC,MAAM,MAAM,GAAG,MAAM,CAAC,KAAK,CAAC,QAAQ,CAAC,CAAC;QACtC,EAAE,CAAC,QAAQ,CAAC,EAAE,EAAE,MAAM,EAAE,CAAC,EAAE,QAAQ,EAAE,IAAI,CAAC,IAAI,GAAG,QAAQ,CAAC,CAAC;QAC3D,EAAE,CAAC,SAAS,CAAC,EAAE,CAAC,CAAC;QACjB,OAAO,MAAM,CAAC,QAAQ,CAAC,OAAO,CAAC,CAAC;IAClC,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,SAAS,CAAC;IACnB,CAAC;AACH,CAAC"}