@thijshakkenberg/valkyrie-mom-mcp 1.0.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 (180) hide show
  1. package/.claude-plugin/plugin.json +17 -0
  2. package/.mcp.json +9 -0
  3. package/CLAUDE.md +73 -0
  4. package/LICENSE +21 -0
  5. package/README.md +164 -0
  6. package/agents/scenario-designer.md +114 -0
  7. package/dist/catalogs/catalog-store.d.ts +20 -0
  8. package/dist/catalogs/catalog-store.d.ts.map +1 -0
  9. package/dist/catalogs/catalog-store.js +78 -0
  10. package/dist/catalogs/catalog-store.js.map +1 -0
  11. package/dist/catalogs/catalog-types.d.ts +10 -0
  12. package/dist/catalogs/catalog-types.d.ts.map +1 -0
  13. package/dist/catalogs/catalog-types.js +2 -0
  14. package/dist/catalogs/catalog-types.js.map +1 -0
  15. package/dist/catalogs/data/all-catalogs.d.ts +9 -0
  16. package/dist/catalogs/data/all-catalogs.d.ts.map +1 -0
  17. package/dist/catalogs/data/all-catalogs.js +8383 -0
  18. package/dist/catalogs/data/all-catalogs.js.map +1 -0
  19. package/dist/catalogs/data/tile-geometry.d.ts +12 -0
  20. package/dist/catalogs/data/tile-geometry.d.ts.map +1 -0
  21. package/dist/catalogs/data/tile-geometry.js +183 -0
  22. package/dist/catalogs/data/tile-geometry.js.map +1 -0
  23. package/dist/catalogs/extract-catalogs.d.ts +12 -0
  24. package/dist/catalogs/extract-catalogs.d.ts.map +1 -0
  25. package/dist/catalogs/extract-catalogs.js +128 -0
  26. package/dist/catalogs/extract-catalogs.js.map +1 -0
  27. package/dist/index.d.ts +3 -0
  28. package/dist/index.d.ts.map +1 -0
  29. package/dist/index.js +13 -0
  30. package/dist/index.js.map +1 -0
  31. package/dist/io/ini-parser.d.ts +6 -0
  32. package/dist/io/ini-parser.d.ts.map +1 -0
  33. package/dist/io/ini-parser.js +42 -0
  34. package/dist/io/ini-parser.js.map +1 -0
  35. package/dist/io/ini-writer.d.ts +2 -0
  36. package/dist/io/ini-writer.d.ts.map +1 -0
  37. package/dist/io/ini-writer.js +36 -0
  38. package/dist/io/ini-writer.js.map +1 -0
  39. package/dist/io/localization-io.d.ts +21 -0
  40. package/dist/io/localization-io.d.ts.map +1 -0
  41. package/dist/io/localization-io.js +51 -0
  42. package/dist/io/localization-io.js.map +1 -0
  43. package/dist/io/package-builder.d.ts +2 -0
  44. package/dist/io/package-builder.d.ts.map +1 -0
  45. package/dist/io/package-builder.js +22 -0
  46. package/dist/io/package-builder.js.map +1 -0
  47. package/dist/model/component-types.d.ts +61 -0
  48. package/dist/model/component-types.d.ts.map +1 -0
  49. package/dist/model/component-types.js +71 -0
  50. package/dist/model/component-types.js.map +1 -0
  51. package/dist/model/localization-store.d.ts +15 -0
  52. package/dist/model/localization-store.d.ts.map +1 -0
  53. package/dist/model/localization-store.js +42 -0
  54. package/dist/model/localization-store.js.map +1 -0
  55. package/dist/model/scenario-model.d.ts +27 -0
  56. package/dist/model/scenario-model.d.ts.map +1 -0
  57. package/dist/model/scenario-model.js +151 -0
  58. package/dist/model/scenario-model.js.map +1 -0
  59. package/dist/resources/format-docs.d.ts +6 -0
  60. package/dist/resources/format-docs.d.ts.map +1 -0
  61. package/dist/resources/format-docs.js +261 -0
  62. package/dist/resources/format-docs.js.map +1 -0
  63. package/dist/server.d.ts +3 -0
  64. package/dist/server.d.ts.map +1 -0
  65. package/dist/server.js +206 -0
  66. package/dist/server.js.map +1 -0
  67. package/dist/tools/lifecycle.d.ts +37 -0
  68. package/dist/tools/lifecycle.d.ts.map +1 -0
  69. package/dist/tools/lifecycle.js +146 -0
  70. package/dist/tools/lifecycle.js.map +1 -0
  71. package/dist/tools/map.d.ts +14 -0
  72. package/dist/tools/map.d.ts.map +1 -0
  73. package/dist/tools/map.js +98 -0
  74. package/dist/tools/map.js.map +1 -0
  75. package/dist/tools/reference.d.ts +4 -0
  76. package/dist/tools/reference.d.ts.map +1 -0
  77. package/dist/tools/reference.js +6 -0
  78. package/dist/tools/reference.js.map +1 -0
  79. package/dist/tools/shared.d.ts +10 -0
  80. package/dist/tools/shared.d.ts.map +1 -0
  81. package/dist/tools/shared.js +22 -0
  82. package/dist/tools/shared.js.map +1 -0
  83. package/dist/tools/upsert.d.ts +15 -0
  84. package/dist/tools/upsert.d.ts.map +1 -0
  85. package/dist/tools/upsert.js +91 -0
  86. package/dist/tools/upsert.js.map +1 -0
  87. package/dist/validation/rules/catalog-references.d.ts +14 -0
  88. package/dist/validation/rules/catalog-references.d.ts.map +1 -0
  89. package/dist/validation/rules/catalog-references.js +90 -0
  90. package/dist/validation/rules/catalog-references.js.map +1 -0
  91. package/dist/validation/rules/cross-references.d.ts +9 -0
  92. package/dist/validation/rules/cross-references.d.ts.map +1 -0
  93. package/dist/validation/rules/cross-references.js +37 -0
  94. package/dist/validation/rules/cross-references.js.map +1 -0
  95. package/dist/validation/rules/event-chain-utils.d.ts +8 -0
  96. package/dist/validation/rules/event-chain-utils.d.ts.map +1 -0
  97. package/dist/validation/rules/event-chain-utils.js +30 -0
  98. package/dist/validation/rules/event-chain-utils.js.map +1 -0
  99. package/dist/validation/rules/event-flow.d.ts +14 -0
  100. package/dist/validation/rules/event-flow.d.ts.map +1 -0
  101. package/dist/validation/rules/event-flow.js +83 -0
  102. package/dist/validation/rules/event-flow.js.map +1 -0
  103. package/dist/validation/rules/event-graph.d.ts +10 -0
  104. package/dist/validation/rules/event-graph.d.ts.map +1 -0
  105. package/dist/validation/rules/event-graph.js +51 -0
  106. package/dist/validation/rules/event-graph.js.map +1 -0
  107. package/dist/validation/rules/explore-token-pattern.d.ts +10 -0
  108. package/dist/validation/rules/explore-token-pattern.d.ts.map +1 -0
  109. package/dist/validation/rules/explore-token-pattern.js +70 -0
  110. package/dist/validation/rules/explore-token-pattern.js.map +1 -0
  111. package/dist/validation/rules/format-rules.d.ts +10 -0
  112. package/dist/validation/rules/format-rules.d.ts.map +1 -0
  113. package/dist/validation/rules/format-rules.js +61 -0
  114. package/dist/validation/rules/format-rules.js.map +1 -0
  115. package/dist/validation/rules/investigator-token-pattern.d.ts +9 -0
  116. package/dist/validation/rules/investigator-token-pattern.d.ts.map +1 -0
  117. package/dist/validation/rules/investigator-token-pattern.js +39 -0
  118. package/dist/validation/rules/investigator-token-pattern.js.map +1 -0
  119. package/dist/validation/rules/localization-completeness.d.ts +11 -0
  120. package/dist/validation/rules/localization-completeness.d.ts.map +1 -0
  121. package/dist/validation/rules/localization-completeness.js +83 -0
  122. package/dist/validation/rules/localization-completeness.js.map +1 -0
  123. package/dist/validation/rules/mythos-structure.d.ts +10 -0
  124. package/dist/validation/rules/mythos-structure.d.ts.map +1 -0
  125. package/dist/validation/rules/mythos-structure.js +57 -0
  126. package/dist/validation/rules/mythos-structure.js.map +1 -0
  127. package/dist/validation/rules/required-fields.d.ts +9 -0
  128. package/dist/validation/rules/required-fields.d.ts.map +1 -0
  129. package/dist/validation/rules/required-fields.js +38 -0
  130. package/dist/validation/rules/required-fields.js.map +1 -0
  131. package/dist/validation/rules/tile-connectivity.d.ts +9 -0
  132. package/dist/validation/rules/tile-connectivity.d.ts.map +1 -0
  133. package/dist/validation/rules/tile-connectivity.js +125 -0
  134. package/dist/validation/rules/tile-connectivity.js.map +1 -0
  135. package/dist/validation/validator.d.ts +7 -0
  136. package/dist/validation/validator.d.ts.map +1 -0
  137. package/dist/validation/validator.js +35 -0
  138. package/dist/validation/validator.js.map +1 -0
  139. package/package.json +59 -0
  140. package/skills/custom-monsters/SKILL.md +228 -0
  141. package/skills/event-patterns/SKILL.md +268 -0
  142. package/skills/items-and-distribution/SKILL.md +193 -0
  143. package/skills/scenario/SKILL.md +105 -0
  144. package/skills/tile-placement/SKILL.md +163 -0
  145. package/skills/ui-and-puzzles/SKILL.md +347 -0
  146. package/skills/variables-and-mythos/SKILL.md +285 -0
  147. package/src/catalogs/catalog-store.ts +94 -0
  148. package/src/catalogs/catalog-types.ts +10 -0
  149. package/src/catalogs/data/all-catalogs.ts +8391 -0
  150. package/src/catalogs/data/tile-geometry.ts +188 -0
  151. package/src/catalogs/extract-catalogs.ts +172 -0
  152. package/src/index.ts +14 -0
  153. package/src/io/ini-parser.ts +52 -0
  154. package/src/io/ini-writer.ts +51 -0
  155. package/src/io/localization-io.ts +62 -0
  156. package/src/io/package-builder.ts +26 -0
  157. package/src/model/component-types.ts +124 -0
  158. package/src/model/localization-store.ts +52 -0
  159. package/src/model/scenario-model.ts +177 -0
  160. package/src/resources/format-docs.ts +264 -0
  161. package/src/server.ts +336 -0
  162. package/src/tools/lifecycle.ts +183 -0
  163. package/src/tools/map.ts +125 -0
  164. package/src/tools/reference.ts +7 -0
  165. package/src/tools/shared.ts +34 -0
  166. package/src/tools/upsert.ts +133 -0
  167. package/src/validation/rules/catalog-references.ts +95 -0
  168. package/src/validation/rules/cross-references.ts +42 -0
  169. package/src/validation/rules/event-chain-utils.ts +31 -0
  170. package/src/validation/rules/event-flow.ts +93 -0
  171. package/src/validation/rules/event-graph.ts +62 -0
  172. package/src/validation/rules/explore-token-pattern.ts +77 -0
  173. package/src/validation/rules/format-rules.ts +69 -0
  174. package/src/validation/rules/investigator-token-pattern.ts +47 -0
  175. package/src/validation/rules/localization-completeness.ts +93 -0
  176. package/src/validation/rules/mythos-structure.ts +64 -0
  177. package/src/validation/rules/required-fields.ts +43 -0
  178. package/src/validation/rules/tile-connectivity.ts +148 -0
  179. package/src/validation/validator.ts +38 -0
  180. package/tsconfig.json +20 -0
@@ -0,0 +1 @@
1
+ {"version":3,"file":"upsert.d.ts","sourceRoot":"","sources":["../../src/tools/upsert.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,aAAa,EAAE,MAAM,4BAA4B,CAAC;AAC3D,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,6BAA6B,CAAC;AAEpE,MAAM,WAAW,YAAY;IAC3B,OAAO,EAAE,OAAO,CAAC;IACjB,QAAQ,EAAE,gBAAgB,EAAE,CAAC;IAC7B,MAAM,EAAE,gBAAgB,EAAE,CAAC;CAC5B;AAmGD,wBAAgB,WAAW,CAAC,KAAK,EAAE,aAAa,EAAE,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,GAAG,YAAY,CAE1G;AAED,wBAAgB,UAAU,CAAC,KAAK,EAAE,aAAa,EAAE,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,GAAG,YAAY,CAEzG;AAED,wBAAgB,WAAW,CAAC,KAAK,EAAE,aAAa,EAAE,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,GAAG,YAAY,CAE1G;AAED,wBAAgB,WAAW,CAAC,KAAK,EAAE,aAAa,EAAE,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,GAAG,YAAY,CAE1G;AAED,wBAAgB,UAAU,CAAC,KAAK,EAAE,aAAa,EAAE,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,GAAG,YAAY,CAEzG;AAED,wBAAgB,YAAY,CAAC,KAAK,EAAE,aAAa,EAAE,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,GAAG,YAAY,CAE3G;AAED,wBAAgB,QAAQ,CAAC,KAAK,EAAE,aAAa,EAAE,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,GAAG,YAAY,CAEvG"}
@@ -0,0 +1,91 @@
1
+ const COMPONENT_CONFIGS = {
2
+ Event: { prefix: 'Event', checkLocalization: true },
3
+ Tile: { prefix: 'Tile', requiredFields: ['side'] },
4
+ Token: { prefix: 'Token', requiredFields: ['type'] },
5
+ Spawn: { prefix: 'Spawn' },
6
+ QItem: { prefix: 'QItem' },
7
+ Puzzle: { prefix: 'Puzzle' },
8
+ UI: { prefix: 'UI' },
9
+ };
10
+ function prefixError(name, expected) {
11
+ return {
12
+ rule: 'prefix',
13
+ severity: 'error',
14
+ message: `Name "${name}" must start with "${expected}"`,
15
+ component: name,
16
+ };
17
+ }
18
+ function requiredFieldError(name, field) {
19
+ return {
20
+ rule: 'required_field',
21
+ severity: 'error',
22
+ message: `Field "${field}" is required for ${name}`,
23
+ component: name,
24
+ field,
25
+ };
26
+ }
27
+ function localizationWarning(name, key) {
28
+ return {
29
+ rule: 'localization',
30
+ severity: 'warning',
31
+ message: `Missing localization key "${key}" for ${name}`,
32
+ component: name,
33
+ };
34
+ }
35
+ function checkEventLocalization(model, name, data) {
36
+ const warnings = [];
37
+ const merged = model.get(name);
38
+ const display = data.display ?? merged?.data.display;
39
+ if (display === 'false')
40
+ return warnings;
41
+ const textKey = `${name}.text`;
42
+ if (!model.localization.has(textKey)) {
43
+ warnings.push(localizationWarning(name, textKey));
44
+ }
45
+ return warnings;
46
+ }
47
+ function upsertGeneric(model, name, data, config) {
48
+ const errors = [];
49
+ const warnings = [];
50
+ if (!name.startsWith(config.prefix)) {
51
+ errors.push(prefixError(name, config.prefix));
52
+ return { success: false, warnings, errors };
53
+ }
54
+ if (config.requiredFields) {
55
+ for (const field of config.requiredFields) {
56
+ const existing = model.get(name);
57
+ const mergedValue = data[field] ?? existing?.data[field];
58
+ if (!mergedValue) {
59
+ errors.push(requiredFieldError(name, field));
60
+ return { success: false, warnings, errors };
61
+ }
62
+ }
63
+ }
64
+ model.upsert(name, data);
65
+ if (config.checkLocalization) {
66
+ warnings.push(...checkEventLocalization(model, name, data));
67
+ }
68
+ return { success: true, warnings, errors };
69
+ }
70
+ export function upsertEvent(model, name, data) {
71
+ return upsertGeneric(model, name, data, COMPONENT_CONFIGS.Event);
72
+ }
73
+ export function upsertTile(model, name, data) {
74
+ return upsertGeneric(model, name, data, COMPONENT_CONFIGS.Tile);
75
+ }
76
+ export function upsertToken(model, name, data) {
77
+ return upsertGeneric(model, name, data, COMPONENT_CONFIGS.Token);
78
+ }
79
+ export function upsertSpawn(model, name, data) {
80
+ return upsertGeneric(model, name, data, COMPONENT_CONFIGS.Spawn);
81
+ }
82
+ export function upsertItem(model, name, data) {
83
+ return upsertGeneric(model, name, data, COMPONENT_CONFIGS.QItem);
84
+ }
85
+ export function upsertPuzzle(model, name, data) {
86
+ return upsertGeneric(model, name, data, COMPONENT_CONFIGS.Puzzle);
87
+ }
88
+ export function upsertUI(model, name, data) {
89
+ return upsertGeneric(model, name, data, COMPONENT_CONFIGS.UI);
90
+ }
91
+ //# sourceMappingURL=upsert.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"upsert.js","sourceRoot":"","sources":["../../src/tools/upsert.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,14 @@
1
+ import type { ValidationResult } from '../../model/component-types.js';
2
+ import type { ScenarioModel } from '../../model/scenario-model.js';
3
+ /**
4
+ * Checks that game content references exist in the catalog.
5
+ * - Tile `side` field -> must be a valid TileSide ID
6
+ * - Spawn `monster` field -> must be a valid Monster ID (or a CustomMonster defined in the scenario)
7
+ * - Any component `audio` field -> must be a valid Audio ID
8
+ *
9
+ * All issues are **warnings** (not errors) because custom scenarios may define
10
+ * their own content names that aren't in the standard catalogs.
11
+ * Exception: invalid tile sides are **errors** because they crash Valkyrie.
12
+ */
13
+ export declare function checkCatalogReferences(model: ScenarioModel): ValidationResult[];
14
+ //# sourceMappingURL=catalog-references.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"catalog-references.d.ts","sourceRoot":"","sources":["../../../src/validation/rules/catalog-references.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,gCAAgC,CAAC;AAEvE,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,+BAA+B,CAAC;AAGnE;;;;;;;;;GASG;AACH,wBAAgB,sBAAsB,CAAC,KAAK,EAAE,aAAa,GAAG,gBAAgB,EAAE,CA+E/E"}
@@ -0,0 +1,90 @@
1
+ import { parseRefList } from '../../model/component-types.js';
2
+ import { getSharedCatalog } from '../../catalogs/catalog-store.js';
3
+ /**
4
+ * Checks that game content references exist in the catalog.
5
+ * - Tile `side` field -> must be a valid TileSide ID
6
+ * - Spawn `monster` field -> must be a valid Monster ID (or a CustomMonster defined in the scenario)
7
+ * - Any component `audio` field -> must be a valid Audio ID
8
+ *
9
+ * All issues are **warnings** (not errors) because custom scenarios may define
10
+ * their own content names that aren't in the standard catalogs.
11
+ * Exception: invalid tile sides are **errors** because they crash Valkyrie.
12
+ */
13
+ export function checkCatalogReferences(model) {
14
+ const results = [];
15
+ const catalog = getSharedCatalog();
16
+ const tileIds = catalog.getAllIds('tile');
17
+ const monsterIds = catalog.getAllIds('monster');
18
+ const audioIds = catalog.getAllIds('audio');
19
+ const itemIds = catalog.getAllIds('item');
20
+ // Collect CustomMonster names defined in the scenario
21
+ const customMonsterNames = new Set(model.getByType('CustomMonster').map(c => c.name));
22
+ // Check tile side fields
23
+ for (const comp of model.getByType('Tile')) {
24
+ const side = comp.data.side;
25
+ if (!side)
26
+ continue;
27
+ if (!tileIds.has(side)) {
28
+ results.push({
29
+ rule: 'catalog-references',
30
+ severity: 'error',
31
+ message: `Tile "${comp.name}" references unknown tile side "${side}" — invalid sides crash Valkyrie`,
32
+ component: comp.name,
33
+ field: 'side',
34
+ });
35
+ }
36
+ }
37
+ // Check spawn monster fields (space-separated list)
38
+ for (const comp of model.getByType('Spawn')) {
39
+ const monsterField = comp.data.monster;
40
+ if (!monsterField)
41
+ continue;
42
+ for (const name of parseRefList(monsterField)) {
43
+ if (monsterIds.has(name))
44
+ continue;
45
+ if (customMonsterNames.has(name))
46
+ continue;
47
+ results.push({
48
+ rule: 'catalog-references',
49
+ severity: 'warning',
50
+ message: `Spawn "${comp.name}" references unknown monster "${name}"`,
51
+ component: comp.name,
52
+ field: 'monster',
53
+ });
54
+ }
55
+ }
56
+ // Check audio fields on all components
57
+ for (const comp of model.getAll()) {
58
+ const audio = comp.data.audio;
59
+ if (!audio)
60
+ continue;
61
+ if (!audioIds.has(audio)) {
62
+ results.push({
63
+ rule: 'catalog-references',
64
+ severity: 'warning',
65
+ message: `Component "${comp.name}" references unknown audio "${audio}"`,
66
+ component: comp.name,
67
+ field: 'audio',
68
+ });
69
+ }
70
+ }
71
+ // Check QItem itemname fields (space-separated list of item catalog IDs)
72
+ for (const comp of model.getByType('QItem')) {
73
+ const itemname = comp.data.itemname;
74
+ if (!itemname)
75
+ continue;
76
+ for (const name of parseRefList(itemname)) {
77
+ if (!itemIds.has(name)) {
78
+ results.push({
79
+ rule: 'catalog-references',
80
+ severity: 'warning',
81
+ message: `Item "${comp.name}" references unknown itemname "${name}" — use catalog IDs like ItemCommonKnife, ItemCommonKeroseneLantern`,
82
+ component: comp.name,
83
+ field: 'itemname',
84
+ });
85
+ }
86
+ }
87
+ }
88
+ return results;
89
+ }
90
+ //# sourceMappingURL=catalog-references.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"catalog-references.js","sourceRoot":"","sources":["../../../src/validation/rules/catalog-references.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,9 @@
1
+ import type { ValidationResult } from '../../model/component-types.js';
2
+ import type { ScenarioModel } from '../../model/scenario-model.js';
3
+ /**
4
+ * Checks that all component references point to existing components.
5
+ * Space-separated values are split and each ref checked individually.
6
+ * References to built-in game content (Monster*, Audio*, TileSide*) are skipped.
7
+ */
8
+ export declare function checkCrossReferences(model: ScenarioModel): ValidationResult[];
9
+ //# sourceMappingURL=cross-references.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"cross-references.d.ts","sourceRoot":"","sources":["../../../src/validation/rules/cross-references.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,gCAAgC,CAAC;AAEvE,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,+BAA+B,CAAC;AASnE;;;;GAIG;AACH,wBAAgB,oBAAoB,CAAC,KAAK,EAAE,aAAa,GAAG,gBAAgB,EAAE,CAyB7E"}
@@ -0,0 +1,37 @@
1
+ import { REFERENCE_FIELDS, parseRefList } from '../../model/component-types.js';
2
+ /** Prefixes for built-in game content that should not be flagged as missing */
3
+ const BUILTIN_PREFIXES = ['Monster', 'Audio', 'TileSide'];
4
+ function isBuiltin(ref) {
5
+ return BUILTIN_PREFIXES.some(prefix => ref.startsWith(prefix));
6
+ }
7
+ /**
8
+ * Checks that all component references point to existing components.
9
+ * Space-separated values are split and each ref checked individually.
10
+ * References to built-in game content (Monster*, Audio*, TileSide*) are skipped.
11
+ */
12
+ export function checkCrossReferences(model) {
13
+ const results = [];
14
+ for (const comp of model.getAll()) {
15
+ for (const field of REFERENCE_FIELDS) {
16
+ const value = comp.data[field];
17
+ if (value === undefined || value.trim() === '')
18
+ continue;
19
+ const refs = parseRefList(value);
20
+ for (const ref of refs) {
21
+ if (isBuiltin(ref))
22
+ continue;
23
+ if (!model.get(ref)) {
24
+ results.push({
25
+ rule: 'cross-references',
26
+ severity: 'error',
27
+ message: `"${comp.name}" field "${field}" references non-existent component "${ref}"`,
28
+ component: comp.name,
29
+ field,
30
+ });
31
+ }
32
+ }
33
+ }
34
+ }
35
+ return results;
36
+ }
37
+ //# sourceMappingURL=cross-references.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"cross-references.js","sourceRoot":"","sources":["../../../src/validation/rules/cross-references.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,gBAAgB,EAAE,YAAY,EAAE,MAAM,gCAAgC,CAAC;AAGhF,+EAA+E;AAC/E,MAAM,gBAAgB,GAAG,CAAC,SAAS,EAAE,OAAO,EAAE,UAAU,CAAC,CAAC;AAE1D,SAAS,SAAS,CAAC,GAAW;IAC5B,OAAO,gBAAgB,CAAC,IAAI,CAAC,MAAM,CAAC,EAAE,CAAC,GAAG,CAAC,UAAU,CAAC,MAAM,CAAC,CAAC,CAAC;AACjE,CAAC;AAED;;;;GAIG;AACH,MAAM,UAAU,oBAAoB,CAAC,KAAoB;IACvD,MAAM,OAAO,GAAuB,EAAE,CAAC;IAEvC,KAAK,MAAM,IAAI,IAAI,KAAK,CAAC,MAAM,EAAE,EAAE,CAAC;QAClC,KAAK,MAAM,KAAK,IAAI,gBAAgB,EAAE,CAAC;YACrC,MAAM,KAAK,GAAG,IAAI,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;YAC/B,IAAI,KAAK,KAAK,SAAS,IAAI,KAAK,CAAC,IAAI,EAAE,KAAK,EAAE;gBAAE,SAAS;YAEzD,MAAM,IAAI,GAAG,YAAY,CAAC,KAAK,CAAC,CAAC;YACjC,KAAK,MAAM,GAAG,IAAI,IAAI,EAAE,CAAC;gBACvB,IAAI,SAAS,CAAC,GAAG,CAAC;oBAAE,SAAS;gBAC7B,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,GAAG,CAAC,EAAE,CAAC;oBACpB,OAAO,CAAC,IAAI,CAAC;wBACX,IAAI,EAAE,kBAAkB;wBACxB,QAAQ,EAAE,OAAO;wBACjB,OAAO,EAAE,IAAI,IAAI,CAAC,IAAI,YAAY,KAAK,wCAAwC,GAAG,GAAG;wBACrF,SAAS,EAAE,IAAI,CAAC,IAAI;wBACpB,KAAK;qBACN,CAAC,CAAC;gBACL,CAAC;YACH,CAAC;QACH,CAAC;IACH,CAAC;IAED,OAAO,OAAO,CAAC;AACjB,CAAC"}
@@ -0,0 +1,8 @@
1
+ import type { ScenarioModel } from '../../model/scenario-model.js';
2
+ /**
3
+ * Walk the event chain from a starting event, collecting all events reachable
4
+ * via event1..event6 references (BFS). Stops after visiting maxNodes to prevent
5
+ * infinite loops in cyclic graphs.
6
+ */
7
+ export declare function collectEventChain(model: ScenarioModel, startEventName: string, maxNodes?: number): string[];
8
+ //# sourceMappingURL=event-chain-utils.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"event-chain-utils.d.ts","sourceRoot":"","sources":["../../../src/validation/rules/event-chain-utils.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,+BAA+B,CAAC;AAEnE;;;;GAIG;AACH,wBAAgB,iBAAiB,CAAC,KAAK,EAAE,aAAa,EAAE,cAAc,EAAE,MAAM,EAAE,QAAQ,SAAK,GAAG,MAAM,EAAE,CAsBvG"}
@@ -0,0 +1,30 @@
1
+ import { EVENT_FIELDS, parseRefList } from '../../model/component-types.js';
2
+ /**
3
+ * Walk the event chain from a starting event, collecting all events reachable
4
+ * via event1..event6 references (BFS). Stops after visiting maxNodes to prevent
5
+ * infinite loops in cyclic graphs.
6
+ */
7
+ export function collectEventChain(model, startEventName, maxNodes = 10) {
8
+ const visited = new Set();
9
+ const queue = [startEventName];
10
+ while (queue.length > 0 && visited.size < maxNodes) {
11
+ const current = queue.shift();
12
+ if (visited.has(current))
13
+ continue;
14
+ visited.add(current);
15
+ const comp = model.get(current);
16
+ if (!comp)
17
+ continue;
18
+ for (const field of EVENT_FIELDS) {
19
+ const val = comp.data[field];
20
+ if (!val)
21
+ continue;
22
+ for (const ref of parseRefList(val)) {
23
+ if (!visited.has(ref))
24
+ queue.push(ref);
25
+ }
26
+ }
27
+ }
28
+ return [...visited];
29
+ }
30
+ //# sourceMappingURL=event-chain-utils.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"event-chain-utils.js","sourceRoot":"","sources":["../../../src/validation/rules/event-chain-utils.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,YAAY,EAAE,YAAY,EAAE,MAAM,gCAAgC,CAAC;AAG5E;;;;GAIG;AACH,MAAM,UAAU,iBAAiB,CAAC,KAAoB,EAAE,cAAsB,EAAE,QAAQ,GAAG,EAAE;IAC3F,MAAM,OAAO,GAAG,IAAI,GAAG,EAAU,CAAC;IAClC,MAAM,KAAK,GAAG,CAAC,cAAc,CAAC,CAAC;IAE/B,OAAO,KAAK,CAAC,MAAM,GAAG,CAAC,IAAI,OAAO,CAAC,IAAI,GAAG,QAAQ,EAAE,CAAC;QACnD,MAAM,OAAO,GAAG,KAAK,CAAC,KAAK,EAAG,CAAC;QAC/B,IAAI,OAAO,CAAC,GAAG,CAAC,OAAO,CAAC;YAAE,SAAS;QACnC,OAAO,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC;QAErB,MAAM,IAAI,GAAG,KAAK,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC;QAChC,IAAI,CAAC,IAAI;YAAE,SAAS;QAEpB,KAAK,MAAM,KAAK,IAAI,YAAY,EAAE,CAAC;YACjC,MAAM,GAAG,GAAG,IAAI,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;YAC7B,IAAI,CAAC,GAAG;gBAAE,SAAS;YACnB,KAAK,MAAM,GAAG,IAAI,YAAY,CAAC,GAAG,CAAC,EAAE,CAAC;gBACpC,IAAI,CAAC,OAAO,CAAC,GAAG,CAAC,GAAG,CAAC;oBAAE,KAAK,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;YACzC,CAAC;QACH,CAAC;IACH,CAAC;IAED,OAAO,CAAC,GAAG,OAAO,CAAC,CAAC;AACtB,CAAC"}
@@ -0,0 +1,14 @@
1
+ import type { ValidationResult } from '../../model/component-types.js';
2
+ import type { ScenarioModel } from '../../model/scenario-model.js';
3
+ /**
4
+ * Checks that the event chain from EventStart doesn't lead to a
5
+ * non-display dead-end where the player would be stuck with no
6
+ * visible interaction.
7
+ *
8
+ * Walks the "default path": follows event1 when no vartests,
9
+ * follows event2 (else/default branch) when vartests are present.
10
+ * Warns if the chain terminates at a display:false event with no
11
+ * outgoing event refs and no $end operation.
12
+ */
13
+ export declare function checkEventFlow(model: ScenarioModel): ValidationResult[];
14
+ //# sourceMappingURL=event-flow.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"event-flow.d.ts","sourceRoot":"","sources":["../../../src/validation/rules/event-flow.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,gCAAgC,CAAC;AAEvE,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,+BAA+B,CAAC;AAEnE;;;;;;;;;GASG;AACH,wBAAgB,cAAc,CAAC,KAAK,EAAE,aAAa,GAAG,gBAAgB,EAAE,CA8EvE"}
@@ -0,0 +1,83 @@
1
+ import { parseRefList } from '../../model/component-types.js';
2
+ /**
3
+ * Checks that the event chain from EventStart doesn't lead to a
4
+ * non-display dead-end where the player would be stuck with no
5
+ * visible interaction.
6
+ *
7
+ * Walks the "default path": follows event1 when no vartests,
8
+ * follows event2 (else/default branch) when vartests are present.
9
+ * Warns if the chain terminates at a display:false event with no
10
+ * outgoing event refs and no $end operation.
11
+ */
12
+ export function checkEventFlow(model) {
13
+ const results = [];
14
+ // Find the event with trigger=EventStart
15
+ const startComp = model.getAll().find(c => c.data.trigger === 'EventStart');
16
+ if (!startComp)
17
+ return results; // No start trigger — already caught by event-graph rule
18
+ const visited = new Set();
19
+ let current = startComp.name;
20
+ while (current && !visited.has(current)) {
21
+ visited.add(current);
22
+ const comp = model.get(current);
23
+ if (!comp)
24
+ break;
25
+ const hasEnd = comp.data.operations?.includes('$end');
26
+ if (hasEnd)
27
+ return results; // Scenario ends intentionally
28
+ const display = comp.data.display;
29
+ const isDisplayTrue = display === undefined || display.toLowerCase() !== 'false';
30
+ // Determine next event on the default path
31
+ let nextEvent = null;
32
+ if (comp.data.vartests) {
33
+ // When vartests present, event2 is the else/default path
34
+ const event2 = comp.data.event2;
35
+ if (event2) {
36
+ const refs = parseRefList(event2);
37
+ nextEvent = refs.length > 0 ? refs[0] : null;
38
+ }
39
+ }
40
+ else {
41
+ // No vartests — follow event1
42
+ const event1 = comp.data.event1;
43
+ if (event1) {
44
+ const refs = parseRefList(event1);
45
+ nextEvent = refs.length > 0 ? refs[0] : null;
46
+ }
47
+ }
48
+ if (!nextEvent) {
49
+ // Chain ends here
50
+ if (!isDisplayTrue) {
51
+ results.push({
52
+ rule: 'event-flow',
53
+ severity: 'warning',
54
+ message: `Event chain from start reaches "${comp.name}" which is a non-display dead-end — player may be stuck with no visible interaction`,
55
+ component: comp.name,
56
+ });
57
+ }
58
+ return results;
59
+ }
60
+ current = nextEvent;
61
+ }
62
+ // If we exited due to a cycle, check if we ever reached a display:true event
63
+ // Walk through visited events to see if any were display:true
64
+ if (current && visited.has(current)) {
65
+ // We hit a cycle — check the last event before the cycle
66
+ // The cycle itself means the player is stuck in a loop of non-display events
67
+ const comp = model.get(current);
68
+ if (comp) {
69
+ const display = comp.data.display;
70
+ const isDisplayTrue = display === undefined || display.toLowerCase() !== 'false';
71
+ if (!isDisplayTrue) {
72
+ results.push({
73
+ rule: 'event-flow',
74
+ severity: 'warning',
75
+ message: `Event chain from start reaches "${comp.name}" which is a non-display dead-end — player may be stuck with no visible interaction`,
76
+ component: comp.name,
77
+ });
78
+ }
79
+ }
80
+ }
81
+ return results;
82
+ }
83
+ //# sourceMappingURL=event-flow.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"event-flow.js","sourceRoot":"","sources":["../../../src/validation/rules/event-flow.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,10 @@
1
+ import type { ValidationResult } from '../../model/component-types.js';
2
+ import type { ScenarioModel } from '../../model/scenario-model.js';
3
+ /**
4
+ * Checks the event graph for structural issues:
5
+ * - Error: No component with trigger=EventStart
6
+ * - Warning: Unreachable events (no incoming refs and no trigger)
7
+ * - Warning: Dead-end events (no next-event refs and no $end operation)
8
+ */
9
+ export declare function checkEventGraph(model: ScenarioModel): ValidationResult[];
10
+ //# sourceMappingURL=event-graph.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"event-graph.d.ts","sourceRoot":"","sources":["../../../src/validation/rules/event-graph.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,gCAAgC,CAAC;AAEvE,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,+BAA+B,CAAC;AAEnE;;;;;GAKG;AACH,wBAAgB,eAAe,CAAC,KAAK,EAAE,aAAa,GAAG,gBAAgB,EAAE,CAmDxE"}
@@ -0,0 +1,51 @@
1
+ import { EVENT_FIELDS } from '../../model/component-types.js';
2
+ /**
3
+ * Checks the event graph for structural issues:
4
+ * - Error: No component with trigger=EventStart
5
+ * - Warning: Unreachable events (no incoming refs and no trigger)
6
+ * - Warning: Dead-end events (no next-event refs and no $end operation)
7
+ */
8
+ export function checkEventGraph(model) {
9
+ const results = [];
10
+ const allComponents = model.getAll();
11
+ // Check for EventStart trigger
12
+ const hasEventStart = allComponents.some(c => c.data.trigger === 'EventStart');
13
+ if (!hasEventStart) {
14
+ results.push({
15
+ rule: 'event-graph',
16
+ severity: 'error',
17
+ message: 'No component has trigger=EventStart; scenario cannot begin',
18
+ });
19
+ }
20
+ // Only check Event and Spawn components for graph analysis
21
+ const eventLikeComponents = allComponents.filter(c => c.name.startsWith('Event') || c.name.startsWith('Spawn'));
22
+ for (const comp of eventLikeComponents) {
23
+ // Check unreachable: no incoming refs AND no trigger
24
+ if (!comp.data.trigger) {
25
+ const incomingRefs = model.getReferencesTo(comp.name);
26
+ if (incomingRefs.length === 0) {
27
+ results.push({
28
+ rule: 'event-graph',
29
+ severity: 'warning',
30
+ message: `"${comp.name}" is unreachable: no incoming references and no trigger`,
31
+ component: comp.name,
32
+ });
33
+ }
34
+ }
35
+ // Check dead-end: only for Event components (not Spawn)
36
+ if (comp.name.startsWith('Event')) {
37
+ const hasEnd = comp.data.operations?.includes('$end');
38
+ const hasAnyEventField = EVENT_FIELDS.some(f => comp.data[f] !== undefined);
39
+ if (!hasEnd && !hasAnyEventField) {
40
+ results.push({
41
+ rule: 'event-graph',
42
+ severity: 'warning',
43
+ message: `"${comp.name}" is a dead-end: no next-event references and no $end operation`,
44
+ component: comp.name,
45
+ });
46
+ }
47
+ }
48
+ }
49
+ return results;
50
+ }
51
+ //# sourceMappingURL=event-graph.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"event-graph.js","sourceRoot":"","sources":["../../../src/validation/rules/event-graph.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,YAAY,EAAE,MAAM,gCAAgC,CAAC;AAG9D;;;;;GAKG;AACH,MAAM,UAAU,eAAe,CAAC,KAAoB;IAClD,MAAM,OAAO,GAAuB,EAAE,CAAC;IAEvC,MAAM,aAAa,GAAG,KAAK,CAAC,MAAM,EAAE,CAAC;IAErC,+BAA+B;IAC/B,MAAM,aAAa,GAAG,aAAa,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC,OAAO,KAAK,YAAY,CAAC,CAAC;IAC/E,IAAI,CAAC,aAAa,EAAE,CAAC;QACnB,OAAO,CAAC,IAAI,CAAC;YACX,IAAI,EAAE,aAAa;YACnB,QAAQ,EAAE,OAAO;YACjB,OAAO,EAAE,4DAA4D;SACtE,CAAC,CAAC;IACL,CAAC;IAED,2DAA2D;IAC3D,MAAM,mBAAmB,GAAG,aAAa,CAAC,MAAM,CAC9C,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC,UAAU,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC,IAAI,CAAC,UAAU,CAAC,OAAO,CAAC,CAC9D,CAAC;IAEF,KAAK,MAAM,IAAI,IAAI,mBAAmB,EAAE,CAAC;QACvC,qDAAqD;QACrD,IAAI,CAAC,IAAI,CAAC,IAAI,CAAC,OAAO,EAAE,CAAC;YACvB,MAAM,YAAY,GAAG,KAAK,CAAC,eAAe,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;YACtD,IAAI,YAAY,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;gBAC9B,OAAO,CAAC,IAAI,CAAC;oBACX,IAAI,EAAE,aAAa;oBACnB,QAAQ,EAAE,SAAS;oBACnB,OAAO,EAAE,IAAI,IAAI,CAAC,IAAI,yDAAyD;oBAC/E,SAAS,EAAE,IAAI,CAAC,IAAI;iBACrB,CAAC,CAAC;YACL,CAAC;QACH,CAAC;QAED,wDAAwD;QACxD,IAAI,IAAI,CAAC,IAAI,CAAC,UAAU,CAAC,OAAO,CAAC,EAAE,CAAC;YAClC,MAAM,MAAM,GAAG,IAAI,CAAC,IAAI,CAAC,UAAU,EAAE,QAAQ,CAAC,MAAM,CAAC,CAAC;YACtD,MAAM,gBAAgB,GAAG,YAAY,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,CAAC,KAAK,SAAS,CAAC,CAAC;YAE5E,IAAI,CAAC,MAAM,IAAI,CAAC,gBAAgB,EAAE,CAAC;gBACjC,OAAO,CAAC,IAAI,CAAC;oBACX,IAAI,EAAE,aAAa;oBACnB,QAAQ,EAAE,SAAS;oBACnB,OAAO,EAAE,IAAI,IAAI,CAAC,IAAI,iEAAiE;oBACvF,SAAS,EAAE,IAAI,CAAC,IAAI;iBACrB,CAAC,CAAC;YACL,CAAC;QACH,CAAC;IACH,CAAC;IAED,OAAO,OAAO,CAAC;AACjB,CAAC"}
@@ -0,0 +1,10 @@
1
+ import type { ValidationResult } from '../../model/component-types.js';
2
+ import type { ScenarioModel } from '../../model/scenario-model.js';
3
+ /**
4
+ * Checks explore token conventions from the MoM rulebook:
5
+ * - Warning: Explore token without event1
6
+ * - Warning: Explore token's event chain doesn't remove the token itself
7
+ * - Warning: Explore token's event chain doesn't add any Tile component
8
+ */
9
+ export declare function checkExploreTokenPattern(model: ScenarioModel): ValidationResult[];
10
+ //# sourceMappingURL=explore-token-pattern.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"explore-token-pattern.d.ts","sourceRoot":"","sources":["../../../src/validation/rules/explore-token-pattern.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,gCAAgC,CAAC;AAEvE,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,+BAA+B,CAAC;AAGnE;;;;;GAKG;AACH,wBAAgB,wBAAwB,CAAC,KAAK,EAAE,aAAa,GAAG,gBAAgB,EAAE,CAiEjF"}
@@ -0,0 +1,70 @@
1
+ import { parseRefList } from '../../model/component-types.js';
2
+ import { collectEventChain } from './event-chain-utils.js';
3
+ /**
4
+ * Checks explore token conventions from the MoM rulebook:
5
+ * - Warning: Explore token without event1
6
+ * - Warning: Explore token's event chain doesn't remove the token itself
7
+ * - Warning: Explore token's event chain doesn't add any Tile component
8
+ */
9
+ export function checkExploreTokenPattern(model) {
10
+ const results = [];
11
+ const tokens = model.getAll().filter(c => c.name.startsWith('Token') && c.data.type === 'TokenExplore');
12
+ for (const token of tokens) {
13
+ const event1 = token.data.event1;
14
+ // Check: explore token must have event1
15
+ if (!event1) {
16
+ results.push({
17
+ rule: 'explore-token-pattern',
18
+ severity: 'warning',
19
+ message: `"${token.name}" is an explore token without event1 — nothing happens on exploration`,
20
+ component: token.name,
21
+ field: 'event1',
22
+ });
23
+ continue;
24
+ }
25
+ // Walk the event chain from event1
26
+ const chain = collectEventChain(model, event1);
27
+ // Check: event chain should remove the token itself
28
+ let removesToken = false;
29
+ for (const eventName of chain) {
30
+ const comp = model.get(eventName);
31
+ if (!comp)
32
+ continue;
33
+ if (parseRefList(comp.data.remove ?? '').includes(token.name)) {
34
+ removesToken = true;
35
+ break;
36
+ }
37
+ }
38
+ if (!removesToken) {
39
+ results.push({
40
+ rule: 'explore-token-pattern',
41
+ severity: 'warning',
42
+ message: `"${token.name}" explore event chain does not remove the token — token stays after exploration`,
43
+ component: token.name,
44
+ field: 'remove',
45
+ });
46
+ }
47
+ // Check: event chain should add at least one Tile
48
+ let addsTile = false;
49
+ for (const eventName of chain) {
50
+ const comp = model.get(eventName);
51
+ if (!comp)
52
+ continue;
53
+ if (parseRefList(comp.data.add ?? '').some(r => r.startsWith('Tile'))) {
54
+ addsTile = true;
55
+ break;
56
+ }
57
+ }
58
+ if (!addsTile) {
59
+ results.push({
60
+ rule: 'explore-token-pattern',
61
+ severity: 'warning',
62
+ message: `"${token.name}" explore event chain does not add any Tile — explore tokens typically reveal new tiles`,
63
+ component: token.name,
64
+ field: 'add',
65
+ });
66
+ }
67
+ }
68
+ return results;
69
+ }
70
+ //# sourceMappingURL=explore-token-pattern.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"explore-token-pattern.js","sourceRoot":"","sources":["../../../src/validation/rules/explore-token-pattern.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,YAAY,EAAE,MAAM,gCAAgC,CAAC;AAE9D,OAAO,EAAE,iBAAiB,EAAE,MAAM,wBAAwB,CAAC;AAE3D;;;;;GAKG;AACH,MAAM,UAAU,wBAAwB,CAAC,KAAoB;IAC3D,MAAM,OAAO,GAAuB,EAAE,CAAC;IAEvC,MAAM,MAAM,GAAG,KAAK,CAAC,MAAM,EAAE,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC,UAAU,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC,IAAI,CAAC,IAAI,KAAK,cAAc,CAAC,CAAC;IAExG,KAAK,MAAM,KAAK,IAAI,MAAM,EAAE,CAAC;QAC3B,MAAM,MAAM,GAAG,KAAK,CAAC,IAAI,CAAC,MAAM,CAAC;QAEjC,wCAAwC;QACxC,IAAI,CAAC,MAAM,EAAE,CAAC;YACZ,OAAO,CAAC,IAAI,CAAC;gBACX,IAAI,EAAE,uBAAuB;gBAC7B,QAAQ,EAAE,SAAS;gBACnB,OAAO,EAAE,IAAI,KAAK,CAAC,IAAI,uEAAuE;gBAC9F,SAAS,EAAE,KAAK,CAAC,IAAI;gBACrB,KAAK,EAAE,QAAQ;aAChB,CAAC,CAAC;YACH,SAAS;QACX,CAAC;QAED,mCAAmC;QACnC,MAAM,KAAK,GAAG,iBAAiB,CAAC,KAAK,EAAE,MAAM,CAAC,CAAC;QAE/C,oDAAoD;QACpD,IAAI,YAAY,GAAG,KAAK,CAAC;QACzB,KAAK,MAAM,SAAS,IAAI,KAAK,EAAE,CAAC;YAC9B,MAAM,IAAI,GAAG,KAAK,CAAC,GAAG,CAAC,SAAS,CAAC,CAAC;YAClC,IAAI,CAAC,IAAI;gBAAE,SAAS;YACpB,IAAI,YAAY,CAAC,IAAI,CAAC,IAAI,CAAC,MAAM,IAAI,EAAE,CAAC,CAAC,QAAQ,CAAC,KAAK,CAAC,IAAI,CAAC,EAAE,CAAC;gBAC9D,YAAY,GAAG,IAAI,CAAC;gBACpB,MAAM;YACR,CAAC;QACH,CAAC;QACD,IAAI,CAAC,YAAY,EAAE,CAAC;YAClB,OAAO,CAAC,IAAI,CAAC;gBACX,IAAI,EAAE,uBAAuB;gBAC7B,QAAQ,EAAE,SAAS;gBACnB,OAAO,EAAE,IAAI,KAAK,CAAC,IAAI,iFAAiF;gBACxG,SAAS,EAAE,KAAK,CAAC,IAAI;gBACrB,KAAK,EAAE,QAAQ;aAChB,CAAC,CAAC;QACL,CAAC;QAED,kDAAkD;QAClD,IAAI,QAAQ,GAAG,KAAK,CAAC;QACrB,KAAK,MAAM,SAAS,IAAI,KAAK,EAAE,CAAC;YAC9B,MAAM,IAAI,GAAG,KAAK,CAAC,GAAG,CAAC,SAAS,CAAC,CAAC;YAClC,IAAI,CAAC,IAAI;gBAAE,SAAS;YACpB,IAAI,YAAY,CAAC,IAAI,CAAC,IAAI,CAAC,GAAG,IAAI,EAAE,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,UAAU,CAAC,MAAM,CAAC,CAAC,EAAE,CAAC;gBACtE,QAAQ,GAAG,IAAI,CAAC;gBAChB,MAAM;YACR,CAAC;QACH,CAAC;QACD,IAAI,CAAC,QAAQ,EAAE,CAAC;YACd,OAAO,CAAC,IAAI,CAAC;gBACX,IAAI,EAAE,uBAAuB;gBAC7B,QAAQ,EAAE,SAAS;gBACnB,OAAO,EAAE,IAAI,KAAK,CAAC,IAAI,yFAAyF;gBAChH,SAAS,EAAE,KAAK,CAAC,IAAI;gBACrB,KAAK,EAAE,KAAK;aACb,CAAC,CAAC;QACL,CAAC;IACH,CAAC;IAED,OAAO,OAAO,CAAC;AACjB,CAAC"}
@@ -0,0 +1,10 @@
1
+ import type { ValidationResult } from '../../model/component-types.js';
2
+ import type { ScenarioModel } from '../../model/scenario-model.js';
3
+ /**
4
+ * Checks format-level rules:
5
+ * - format must be in range 4-19
6
+ * - type must be 'MoM'
7
+ * - tile rotation must be in {0, 90, 180, 270}
8
+ */
9
+ export declare function checkFormatRules(model: ScenarioModel): ValidationResult[];
10
+ //# sourceMappingURL=format-rules.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"format-rules.d.ts","sourceRoot":"","sources":["../../../src/validation/rules/format-rules.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,gCAAgC,CAAC;AACvE,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,+BAA+B,CAAC;AAInE;;;;;GAKG;AACH,wBAAgB,gBAAgB,CAAC,KAAK,EAAE,aAAa,GAAG,gBAAgB,EAAE,CAyDzE"}