hoi4-agent-tools 3.10.0 → 4.0.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (163) hide show
  1. package/CHANGELOG.md +131 -0
  2. package/README.md +91 -147
  3. package/dist/bin/http.js +10 -0
  4. package/dist/bin/setup.js +3 -2
  5. package/dist/bin/stdio.js +10 -0
  6. package/dist/hoi4_agent_tools/core/artifacts.js +40 -5
  7. package/dist/hoi4_agent_tools/core/canonical.js +18 -4
  8. package/dist/hoi4_agent_tools/core/condition-evaluator.js +18 -0
  9. package/dist/hoi4_agent_tools/core/configuration.js +7 -0
  10. package/dist/hoi4_agent_tools/core/domain-scan-patterns.js +12 -0
  11. package/dist/hoi4_agent_tools/core/domain-tools.js +65 -0
  12. package/dist/hoi4_agent_tools/core/domain-validation.js +5 -2
  13. package/dist/hoi4_agent_tools/core/engine.js +29 -2
  14. package/dist/hoi4_agent_tools/core/index.js +2 -2
  15. package/dist/hoi4_agent_tools/core/job-executor.js +14 -1
  16. package/dist/hoi4_agent_tools/core/job-operation-registration.js +15 -7
  17. package/dist/hoi4_agent_tools/core/job-store.js +78 -5
  18. package/dist/hoi4_agent_tools/core/job-transactions.js +31 -2
  19. package/dist/hoi4_agent_tools/core/job-worker-host.js +314 -127
  20. package/dist/hoi4_agent_tools/core/job-worker.js +96 -37
  21. package/dist/hoi4_agent_tools/core/operation-result.js +123 -10
  22. package/dist/hoi4_agent_tools/core/operation-tasks.js +49 -89
  23. package/dist/hoi4_agent_tools/core/persistent-analysis-cache.js +25 -21
  24. package/dist/hoi4_agent_tools/core/server-registry.js +22 -5
  25. package/dist/hoi4_agent_tools/core/shared-request-capacity.js +26 -1
  26. package/dist/hoi4_agent_tools/core/source/cache.js +20 -10
  27. package/dist/hoi4_agent_tools/core/source/lexer.js +11 -3
  28. package/dist/hoi4_agent_tools/core/temporary-directories.js +293 -0
  29. package/dist/hoi4_agent_tools/core/transactions.js +114 -23
  30. package/dist/hoi4_agent_tools/core/worker-exit.js +80 -0
  31. package/dist/hoi4_agent_tools/core/workspace.js +84 -8
  32. package/dist/hoi4_agent_tools/decision/ai.js +1 -1
  33. package/dist/hoi4_agent_tools/decision/service.js +28 -0
  34. package/dist/hoi4_agent_tools/decision/source-inventory.js +7 -5
  35. package/dist/hoi4_agent_tools/event/job-operations.js +9 -5
  36. package/dist/hoi4_agent_tools/event/operations.js +14 -1
  37. package/dist/hoi4_agent_tools/focus/job-operations.js +1 -2
  38. package/dist/hoi4_agent_tools/focus/tool-operations.js +1 -1
  39. package/dist/hoi4_agent_tools/gui/assets.js +3 -0
  40. package/dist/hoi4_agent_tools/gui/dds.js +8 -4
  41. package/dist/hoi4_agent_tools/gui/layout.js +45 -5
  42. package/dist/hoi4_agent_tools/gui/native-state.js +244 -0
  43. package/dist/hoi4_agent_tools/gui/renderer.js +12 -7
  44. package/dist/hoi4_agent_tools/gui/source-graph.js +17 -4
  45. package/dist/hoi4_agent_tools/gui/studio.js +33 -21
  46. package/dist/hoi4_agent_tools/gui/validators.js +8 -6
  47. package/dist/hoi4_agent_tools/map/bmp.js +1 -1
  48. package/dist/hoi4_agent_tools/map/derived.js +748 -0
  49. package/dist/hoi4_agent_tools/map/job-operations.js +7 -3
  50. package/dist/hoi4_agent_tools/map/model.js +103 -0
  51. package/dist/hoi4_agent_tools/map/operations.js +427 -58
  52. package/dist/hoi4_agent_tools/map/references.js +483 -0
  53. package/dist/hoi4_agent_tools/map/service.js +136 -61
  54. package/dist/hoi4_agent_tools/map/tool-operations.js +2 -1
  55. package/dist/hoi4_agent_tools/map/validation.js +3 -0
  56. package/dist/hoi4_agent_tools/map/world.js +1280 -0
  57. package/dist/hoi4_agent_tools/mcp/prompts/probability.js +2 -2
  58. package/dist/hoi4_agent_tools/mcp/server/argument-errors.js +72 -0
  59. package/dist/hoi4_agent_tools/mcp/server/create-modern-operations.js +23 -5
  60. package/dist/hoi4_agent_tools/mcp/server/create.js +7 -0
  61. package/dist/hoi4_agent_tools/mcp/server/instructions.js +1 -1
  62. package/dist/hoi4_agent_tools/mcp/server/request-lifecycle.js +24 -30
  63. package/dist/hoi4_agent_tools/mcp/server/tool-listing.js +45 -0
  64. package/dist/hoi4_agent_tools/mcp/tools/analysis.js +28 -8
  65. package/dist/hoi4_agent_tools/mcp/tools/event.js +19 -30
  66. package/dist/hoi4_agent_tools/mcp/tools/focus.js +5 -13
  67. package/dist/hoi4_agent_tools/mcp/tools/gui.js +6 -6
  68. package/dist/hoi4_agent_tools/mcp/tools/job.js +4 -4
  69. package/dist/hoi4_agent_tools/mcp/tools/map.js +15 -18
  70. package/dist/hoi4_agent_tools/mcp/tools/probability.js +42 -48
  71. package/dist/hoi4_agent_tools/mcp/tools/reference.js +26 -9
  72. package/dist/hoi4_agent_tools/mcp/tools/technology.js +17 -30
  73. package/dist/hoi4_agent_tools/mcp/transports/http.js +28 -4
  74. package/dist/hoi4_agent_tools/mcp/transports/stdio-lifetime.js +31 -8
  75. package/dist/hoi4_agent_tools/probability/job-operations.js +4 -9
  76. package/dist/hoi4_agent_tools/probability/operations.js +175 -13
  77. package/dist/hoi4_agent_tools/probability/source-analysis.js +24 -1
  78. package/dist/hoi4_agent_tools/reference/error-log.js +359 -0
  79. package/dist/hoi4_agent_tools/reference/known-mistakes.js +307 -0
  80. package/dist/hoi4_agent_tools/reference/known-mistakes.json +154 -0
  81. package/dist/hoi4_agent_tools/reference/mod-index.js +101 -0
  82. package/dist/hoi4_agent_tools/reference/operations.js +88 -19
  83. package/dist/hoi4_agent_tools/reference/player-text.js +4 -3
  84. package/dist/hoi4_agent_tools/reference/script-validation.js +19 -1
  85. package/dist/hoi4_agent_tools/reference/service.js +6 -0
  86. package/dist/hoi4_agent_tools/runtime.js +14 -1
  87. package/dist/hoi4_agent_tools/schemas/event.js +78 -19
  88. package/dist/hoi4_agent_tools/schemas/focus-requests.js +10 -0
  89. package/dist/hoi4_agent_tools/schemas/lenient-arguments.js +266 -0
  90. package/dist/hoi4_agent_tools/schemas/map-requests.js +63 -20
  91. package/dist/hoi4_agent_tools/schemas/map.js +122 -3
  92. package/dist/hoi4_agent_tools/schemas/mod-tools.js +181 -0
  93. package/dist/hoi4_agent_tools/schemas/probability-requests.js +119 -9
  94. package/dist/hoi4_agent_tools/schemas/reference.js +13 -0
  95. package/dist/hoi4_agent_tools/schemas/scenarios.js +1 -3
  96. package/dist/hoi4_agent_tools/schemas/script-validation.js +13 -6
  97. package/dist/hoi4_agent_tools/schemas/technology.js +79 -21
  98. package/dist/hoi4_agent_tools/technology/job-operations.js +3 -4
  99. package/dist/hoi4_agent_tools/technology/operations.js +14 -1
  100. package/dist/hoi4_agent_tools/version.js +1 -1
  101. package/docs/README.md +7 -4
  102. package/docs/analysis.md +15 -2
  103. package/docs/configuration.md +281 -0
  104. package/docs/development.md +26 -2
  105. package/docs/events.md +29 -6
  106. package/docs/examples.md +13 -28
  107. package/docs/focus.md +127 -5
  108. package/docs/gui.md +105 -21
  109. package/docs/helper-expansion.md +9 -9
  110. package/docs/http.md +3 -1
  111. package/docs/jobs.md +23 -14
  112. package/docs/map.md +199 -7
  113. package/docs/mechanics.md +6 -2
  114. package/docs/probability.md +46 -16
  115. package/docs/reference.md +73 -5
  116. package/docs/setup.md +45 -14
  117. package/docs/technology.md +28 -4
  118. package/docs/third-party-notices.md +11 -0
  119. package/docs/tools.md +150 -42
  120. package/docs/troubleshooting.md +61 -0
  121. package/examples/clients/codex-config.toml +5 -2
  122. package/examples/clients/generic.json +2 -2
  123. package/examples/config/config.json +7 -0
  124. package/npm-shrinkwrap.json +151 -156
  125. package/package.json +13 -8
  126. package/schemas/configuration.schema.json +144 -128
  127. package/schemas/continuous-focus-palette.schema.json +1 -1
  128. package/schemas/custom-weighted-pool.schema.json +1 -1
  129. package/schemas/decision-inspect-input.schema.json +1 -1
  130. package/schemas/error-log-input.schema.json +55 -0
  131. package/schemas/event-feature-manifest.schema.json +1 -1
  132. package/schemas/focus-plan.schema.json +1 -1
  133. package/schemas/focus-planning-sidecar.schema.json +1 -1
  134. package/schemas/gui-animation-source.schema.json +1 -1
  135. package/schemas/gui-helper.schema.json +1 -1
  136. package/schemas/gui-scenario.schema.json +1 -1
  137. package/schemas/helper-expansion-request.schema.json +1 -1
  138. package/schemas/helper-expansion-summary.schema.json +1 -1
  139. package/schemas/impact-inspect-input.schema.json +1 -1
  140. package/schemas/map-operation.schema.json +597 -126
  141. package/schemas/mechanic-test-input.schema.json +1 -1
  142. package/schemas/mod-index-input.schema.json +51 -0
  143. package/schemas/operation-result.schema.json +2 -2
  144. package/schemas/package-check-input.schema.json +1 -1
  145. package/schemas/package-manifest.schema.json +1 -1
  146. package/schemas/probability-analysis-result.schema.json +1 -1
  147. package/schemas/probability-compare-input.schema.json +1 -1
  148. package/schemas/probability-evaluate-input.schema.json +1 -1
  149. package/schemas/probability-inspect-input.schema.json +1 -1
  150. package/schemas/probability-render-input.schema.json +1 -1
  151. package/schemas/probability-scenario-set.schema.json +1 -1
  152. package/schemas/probability-sequence-input.schema.json +1 -1
  153. package/schemas/probability-simulate-input.schema.json +1 -1
  154. package/schemas/probability-sweep-input.schema.json +1 -1
  155. package/schemas/reference-context-input.schema.json +1 -1
  156. package/schemas/reference-read-input.schema.json +1 -1
  157. package/schemas/reference-search-input.schema.json +1 -1
  158. package/schemas/scenario-suite.schema.json +3 -5
  159. package/schemas/scenario-test-input.schema.json +3 -5
  160. package/schemas/script-validate-input.schema.json +1 -1
  161. package/schemas/shared-scenario.schema.json +1 -1
  162. package/schemas/source-lookup-input.schema.json +1 -1
  163. package/server.json +3 -3
package/docs/focus.md CHANGED
@@ -1,10 +1,11 @@
1
1
  # Focus trees
2
2
 
3
- Use `hoi4.focus_inspect`, `hoi4.focus_render`, `hoi4.focus_raster`, and `hoi4.focus_rewrite` for national focus trees and continuous focus palettes.
3
+ Build focus trees, arrange branches and preview the result.
4
+ Use `hoi4.focus_inspect`, `hoi4.focus_render` and `hoi4.focus_rewrite` for national focus trees and continuous-focus palettes.
4
5
 
5
6
  ## Create a tree
6
7
 
7
- A complete plan should include:
8
+ The agent assembles the tree from your request. For a direct API call, the `plan` argument should include:
8
9
 
9
10
  - tree ID and country assignment;
10
11
  - branch and lane groups;
@@ -14,7 +15,108 @@ A complete plan should include:
14
15
  - focus positions, convergence points, and shared support branches;
15
16
  - titles, descriptions, icons, filters, and AI behavior.
16
17
 
17
- For a missing target, call `hoi4.focus_rewrite` with `createIfMissing: true`. Review the proposed and final artifacts returned by the rewrite, then inspect and render the result. Call `hoi4.focus_raster` when the review needs decoded source icons and a deterministic PNG. Do not call a tree complete with placeholder rewards, missing localisation, missing icons, or absent AI choices.
18
+ The `plan` argument of `hoi4.focus_rewrite` follows [focus-plan.schema.json](../schemas/focus-plan.schema.json).
19
+ The easiest starting point for an existing tree is the imported plan in the `plans` array of the JSON artifact returned by `hoi4.focus_inspect`.
20
+ A minimal plan that creates a two-focus tree looks like this:
21
+
22
+ ```json
23
+ {
24
+ "relativePath": "common/national_focus/my_focus_tree.txt",
25
+ "treeId": "my_focus_tree",
26
+ "createIfMissing": true,
27
+ "plan": {
28
+ "schemaVersion": 1,
29
+ "id": "my_focus_tree",
30
+ "countryAssignment": {
31
+ "raw": {
32
+ "text": "{ factor = 0 modifier = { add = 10 tag = AAA } }",
33
+ "referencedFocusIds": []
34
+ },
35
+ "countryTags": ["AAA"]
36
+ },
37
+ "default": false,
38
+ "branchGroups": [],
39
+ "laneGroups": [],
40
+ "entryFocusIds": ["my_root_focus"],
41
+ "focuses": [
42
+ {
43
+ "id": "my_root_focus",
44
+ "label": "Root focus",
45
+ "prerequisites": { "operator": "and", "groups": [] },
46
+ "mutuallyExclusive": [],
47
+ "routeLocks": [],
48
+ "position": { "mode": "fixed", "x": 0, "y": 0, "pinned": false },
49
+ "visibility": "normal",
50
+ "convergence": false,
51
+ "sharedSupport": false,
52
+ "icons": [{ "kind": "static", "sprite": "GFX_goal_generic_political_pressure" }],
53
+ "localisation": { "titleKey": "my_root_focus", "descriptionKey": "my_root_focus_desc" },
54
+ "ai": {
55
+ "raw": { "text": "{ factor = 1 }", "referencedFocusIds": [] },
56
+ "majorRoute": false,
57
+ "strategyIds": []
58
+ },
59
+ "filters": ["FOCUS_FILTER_POLITICAL"],
60
+ "links": [],
61
+ "cost": 10,
62
+ "completionReward": { "text": "{ add_political_power = 50 }", "referencedFocusIds": [] },
63
+ "rawPassthrough": []
64
+ },
65
+ {
66
+ "id": "my_second_focus",
67
+ "label": "Second focus",
68
+ "prerequisites": {
69
+ "operator": "and",
70
+ "groups": [{ "operator": "or", "focusIds": ["my_root_focus"], "rawPassthrough": [] }]
71
+ },
72
+ "mutuallyExclusive": [],
73
+ "routeLocks": [],
74
+ "position": {
75
+ "mode": "relative",
76
+ "x": 0,
77
+ "y": 1,
78
+ "relativeTo": "my_root_focus",
79
+ "pinned": false
80
+ },
81
+ "visibility": "normal",
82
+ "convergence": false,
83
+ "sharedSupport": false,
84
+ "icons": [{ "kind": "static", "sprite": "GFX_goal_generic_construct_civ_factory" }],
85
+ "localisation": { "titleKey": "my_second_focus", "descriptionKey": "my_second_focus_desc" },
86
+ "ai": {
87
+ "raw": { "text": "{ factor = 1 }", "referencedFocusIds": [] },
88
+ "majorRoute": false,
89
+ "strategyIds": []
90
+ },
91
+ "filters": ["FOCUS_FILTER_INDUSTRY"],
92
+ "links": [],
93
+ "cost": 10,
94
+ "completionReward": {
95
+ "text": "{ add_tech_bonus = { bonus = 0.5 uses = 1 category = industry } }",
96
+ "referencedFocusIds": []
97
+ },
98
+ "rawPassthrough": []
99
+ }
100
+ ],
101
+ "sharedFocusIds": [],
102
+ "continuousFocusPaletteIds": [],
103
+ "continuousFocusIds": [],
104
+ "rawPassthrough": [],
105
+ "provenance": {
106
+ "sourcePath": "plan:my_focus_tree",
107
+ "sourceHash": "0000000000000000000000000000000000000000000000000000000000000000",
108
+ "importedPlanHash": "0000000000000000000000000000000000000000000000000000000000000000"
109
+ }
110
+ }
111
+ }
112
+ ```
113
+
114
+ Raw blocks such as `countryAssignment.raw`, `ai.raw`, and `completionReward` hold the Clausewitz block text including its braces; the rewrite writes it after the matching key.
115
+ Each `prerequisites.groups` entry is one `prerequisite` block whose `focusIds` are alternatives.
116
+ `provenance` must be present: an imported plan carries the hashes of the source it came from, and a plan for a new tree may use 64-character hexadecimal placeholders as shown.
117
+ When `treeId` is also supplied, it must equal `plan.id`.
118
+
119
+ For a missing target, call `hoi4.focus_rewrite` with `createIfMissing: true`. Review the proposed and final artifacts returned by the rewrite, then inspect and render the result. `hoi4.focus_render` returns a deterministic PNG with decoded source icons. Do not call a tree complete with placeholder rewards, missing localisation, missing icons, or absent AI choices.
18
120
 
19
121
  ## Clean an existing tree
20
122
 
@@ -28,6 +130,11 @@ For a layout-only cleanup of an existing national tree, call `hoi4.focus_rewrite
28
130
  }
29
131
  ```
30
132
 
133
+ A plan-free call is accepted only in national mode with `layoutMode: "compact"`.
134
+ It requires `treeId`, works on an existing focus source, and rejects `createIfMissing: true`.
135
+ Every other national rewrite requires a `plan`.
136
+ `compactFocusIds` (1 to 10,000 IDs), `pinnedFocusIds` (up to 10,000 IDs), and `symmetryGroups` (up to 64 groups) are accepted only with `layoutMode: "compact"`.
137
+
31
138
  Compact mode imports the tree, resets authored presentation coordinates and lane bounds, and performs a deterministic reflow in the same rewrite call. It keeps prerequisites, mutual exclusions, availability, bypasses, rewards, icons, localisation, AI behavior, and route/lane membership unchanged.
32
139
 
33
140
  The rewrite measures canvas bounds, same-row spacing, the same curved connector paths used by the renderer, connector lengths, connector-node intersections, branch balance, overall centering, and topology-aware fake-complexity patterns. Compact mode evaluates preservation, occupied-row repair, prerequisite-depth reflow, linear-chain repair, sibling balancing, and combined compression strategies, then chooses the cleanest valid result. Equivalent branches are aligned by dependency depth even when their authored rows differ, and connector shape is prioritized before raw canvas dimensions so a shorter canvas cannot win by introducing unnecessary horizontal detours. Sparse direct sibling fan-outs are packed around their parent at the minimum readable spacing, with each exclusive descendant branch moving as a unit and shared convergence focuses staying centered. Dense branches remain wider only when their contents need the room. It refuses invalid geometry such as overlapping or cramped focuses, bad parent order, rendered crossings, connectors through unrelated focuses, or an off-center canvas. Long connectors, fake detours, staircase or zigzag chains, and avoidable sibling imbalance are optimization priorities instead of independent rejection budgets.
@@ -40,6 +147,21 @@ Pass `symmetryGroups` with a `centerFocusId` and one or more `{ "leftFocusId": "
40
147
 
41
148
  A cleanup should not change gameplay relationships to improve the picture. One `prerequisite` block containing several focus IDs is an OR group; several prerequisite blocks are AND requirements.
42
149
 
150
+ ## Continuous focus palettes
151
+
152
+ Set `mode: "continuous"` on `hoi4.focus_inspect`, `hoi4.focus_render`, or `hoi4.focus_rewrite` to work with a `continuous_focus_palette` instead of a national tree; the default mode is `national`.
153
+
154
+ - `hoi4.focus_inspect` and `hoi4.focus_render` select one palette with `paletteId`.
155
+ Without it, inspection includes every palette in the selected source, and rendering requires the source to contain exactly one palette.
156
+ The inspection JSON artifact lists the imported palette plans in `continuousFocusPalettes`.
157
+ - `treeId` is rejected in continuous mode.
158
+ Inspection also rejects `previous`, `laneSpacing`, `nodeSpacing`, and `scenario`, and rendering rejects `horizontalSpacing`, `verticalSpacing`, `reviewScale`, and `cropFocusIds`.
159
+ - Rendering accepts `columns` (1 to 12) only in continuous mode, and continuous `padding` must be at least 24 pixels.
160
+ - `hoi4.focus_rewrite` requires a `plan` that matches [continuous-focus-palette.schema.json](../schemas/continuous-focus-palette.schema.json); the palette is identified by `plan.id`, and the rewrite has no `paletteId` field.
161
+ `layoutMode` must stay `authored`, and `horizontalSpacing`, `verticalSpacing`, `padding`, and `reviewScale` are rejected.
162
+ - A palette needs a mod-owned source.
163
+ Creating a palette with `createIfMissing: true` requires a new source file, so an unrelated existing file is never repurposed.
164
+
43
165
  ## Layout metadata and unsupported script
44
166
 
45
167
  Branch names, lane assignments, working labels, and other planning-only data may be stored in a `.focus-plan.json` file beside the focus source. HOI4 does not load that file.
@@ -52,10 +174,10 @@ Inspection and rendering can report missing references, invalid prerequisite str
52
174
 
53
175
  For a named tree, pass `scenario: { "completedFocusIds": ["my_route_root"] }` to `hoi4.focus_inspect`. The linked inspection artifact records each focus's prerequisite groups, route locks, exclusive choices, and unresolved runtime fields against that completed set. The inline tree summary counts completed, blocked, unresolved, and structural candidate focuses, plus contradictory completed choices. A structural candidate still requires runtime trigger evaluation before an agent can call it playable.
54
176
 
55
- Pass up to 16 `cropFocusIds` to `hoi4.focus_raster` for source-linked problem crops around specific focuses. Each crop uses the same rendered pixels as the full tree; a JSON manifest records the focus ID, crop bounds, image hash, and diagnostics. An unknown focus ID is reported explicitly.
177
+ Pass up to 16 `cropFocusIds` to `hoi4.focus_render` for source-linked problem crops around specific focuses. Each crop uses the same rendered pixels as the full tree; a JSON manifest records the focus ID, crop bounds, image hash, and diagnostics. An unknown focus ID is reported explicitly.
56
178
 
57
179
  The layout JSON reports horizontal, vertical, and Manhattan grid spans for every prerequisite connector in `layout.connectorMeasurements`.
58
180
 
59
- `hoi4.focus_render` is the normal structural view and writes complete HTML, SVG, JSON, and source-map artifacts without decoding every icon or creating a PNG. `hoi4.focus_raster` adds decoded icons and the high-fidelity PNG. National trees with 200 or more focuses raster at half scale by default; pass `reviewScale` from `0.25` through `1` when a different PNG size is needed.
181
+ `hoi4.focus_render` writes complete HTML, SVG, JSON and source-map artifacts and a high-fidelity PNG with decoded icons. Pass `png: false` for the faster structural view without decoding icons. National trees with 200 or more focuses raster at half scale by default; pass `reviewScale` from `0.25` through `1` when a different PNG size is needed.
60
182
 
61
183
  The public workflow is regression-tested with 1,024-focus creation, compact rewrites, deterministic repeat runs, inspection, vector rendering, and raster rendering. A separate 1,024-icon test decodes a distinct texture for every focus. Large source diffs use the same deterministic review-artifact path instead of blocking at the quadratic matrix size.
package/docs/gui.md CHANGED
@@ -1,12 +1,11 @@
1
1
  # Scripted GUIs
2
2
 
3
- Use `hoi4.gui_inspect`, `hoi4.gui_render`, and `hoi4.gui_rewrite` for `.gui`, `.gfx`, `common/scripted_guis`, localisation, sprites, fonts, and linked decision entry points.
3
+ Build and edit windows, preview their states and find layout problems.
4
+ Use `hoi4.gui_inspect`, `hoi4.gui_render` and `hoi4.gui_rewrite` for `.gui`, `.gfx`, `common/scripted_guis`, localisation, sprites, fonts and linked decisions.
4
5
 
5
6
  ## Start with a preview
6
7
 
7
- > Render this window at 100% and 125% UI scale. Show its control regions and list the state inputs needed to establish visibility and availability.
8
-
9
- The [interface examples](gui-comparisons.md) show real vanilla and Chaos Redux windows.
8
+ The [interface examples](https://github.com/klimPaskov/hoi4-agent-tools/blob/main/docs/gui-comparisons.md) show real vanilla and mod windows.
10
9
  Cyan click regions have confirmed availability under the supplied scenario.
11
10
  Dashed amber regions are potential controls with unresolved visibility or enabling conditions; they do not count as confirmed branch coverage.
12
11
  The scene retains the reason so the agent can supply the missing facts instead of guessing.
@@ -27,7 +26,7 @@ The preview does not establish native automatic positioning, frame composition,
27
26
 
28
27
  ## Create a GUI
29
28
 
30
- `hoi4.gui_rewrite` can work from supported source, targeted patches, or structured helpers. Source and helper rewrites may include one bounded text package: the main `.gui` plus additional interface `.gui`/`.gfx`, configured GFX `.gfx`, `common/scripted_guis/*.txt`, and localisation `.yml` files. The package is path-checked, parsed, linked, rendered, validated, and applied together in one rewrite. Existing text encodings are retained, while localisation is always written as UTF-8 with BOM.
29
+ `hoi4.gui_rewrite` can work from supported source, targeted patches, or structured helpers. Source and helper rewrites may include one bounded text package: the main `.gui` plus additional interface `.gui`/`.gfx`, configured GFX `.gfx`, `common/scripted_guis/*.txt`, and localisation `.yml` files. The related files are written together. Existing text encodings are retained, while localisation is always written as UTF-8 with BOM.
31
30
 
32
31
  A package may contain at most 32 text files and 16 MiB of encoded source in total. Paths are compared portably, so aliases that differ only by letter case are rejected.
33
32
 
@@ -103,6 +102,10 @@ For native country-flag controls, bind `element_name.countryTag` and `element_na
103
102
  Only valid bounded tag tokens enter asset discovery; an invalid tag is reported, not converted into a different country's identifier or a filesystem path.
104
103
  An unrelated global country value does not turn every native icon into a flag.
105
104
 
105
+ Some vanilla windows are not scripted: the game itself shows one branch of the window and picks an icon frame from the player's country. `countrypoliticsview` is modelled this way. Its `no_faction`, `original_in_faction` (faction leader), `in_faction` (faction member) and `power_balance_button` branches are shown only when they apply, and `pol_faction_icon` shows the frame of the ruling ideology (fascism, communism, democratic or neutrality) instead of its static `frame = 1`.
106
+ The facts come from `scenario.country`: `tag`, `ideology`, `faction` (`none`, `member` or `leader`) and `balanceOfPower` (boolean). A fact the scenario does not set is read from `history/countries` at the scenario `date` (default 1936.1.1): `set_politics`, `create_faction`, `add_to_faction` in other countries' histories, and `set_power_balance`, with dated blocks later than the scenario date ignored and DLC-conditioned blocks treated as owned. With no country at all, the window shows a country in no faction without a balance of power and reports the approximation. Explicit `visibility`, `values` (`name.visible`, `name.frame`) and `selectedFrames` always win. Every decision is listed under `modelled` as `native_window_state`.
107
+ Source visibility accepts `visible`, `show`, `hide` and `hidden`. Scenario visibility values may be booleans, `yes`/`no`, `true`/`false`, `visible`/`hidden`, or 1/0.
108
+
106
109
  `hoi4.gui_inspect` and `hoi4.gui_render` generate a seeded exploratory preview by default. The generator follows the complete `parent_scripted_gui` surface, discovers numeric and text tokens, fills meters within their declared ranges, and populates dynamic lists with coherent rows. Scripted-localisation text and sprite branches use the same structured condition evaluator as probability analysis, including compound conditions, inclusive comparisons, constants, declared scopes, and scripted triggers. An unknown earlier condition leaves the token unresolved instead of guessing a branch. The scenario's `conditionResults` records checked choices and missing inputs. Explicit values remain authoritative; generated inputs are not verified campaign state. Normal controls and animation frames remain stable unless variation is requested. Every explicit `relatedScenarios` entry is rendered beside the generated view.
107
110
 
108
111
  Declare scoped facts with `scopes`, for example `"scopes": { "FROM": { "id": "target", "actor": "FRA", "state": { "support": 10 } } }`. Existing flat values such as `FROM.support` remain usable. Seeded pane and active/idle selection is exploratory layout sampling, not proof that every visibility branch is reachable.
@@ -112,7 +115,7 @@ Generation is reproducible. Set `generatedScenarios.seed` to any stable string f
112
115
  ```json
113
116
  {
114
117
  "generatedScenarios": {
115
- "seed": "chaos-meter-review",
118
+ "seed": "status-panel-review",
116
119
  "count": 3,
117
120
  "numericMinimum": 0,
118
121
  "numericMaximum": 100,
@@ -164,7 +167,10 @@ Broad inspection indexes localisation actually referenced by GUI source and retu
164
167
 
165
168
  GUI rewrites keep complete validation evidence in a linked JSON resource and retain the highest-priority findings in the transaction result. Large surrounding interface inventories therefore do not turn a small scalar patch into a transaction structure-limit error.
166
169
 
167
- Large inspections, renders, and rewrites send periodic MCP progress heartbeats while a service stage is still running. Clients that request progress can reset their idle request timer from these notifications; there is no 180-second GUI operation limit in the server, and cancellation still follows the request signal.
170
+ Large inspections, renders, and rewrites send periodic MCP progress heartbeats while a service stage is still running.
171
+ Clients that request progress can reset their idle request timer from these notifications, and cancellation follows the request signal.
172
+ A read-only `hoi4.gui_inspect` or `hoi4.gui_render` job still running after the configurable `jobDeadlineSeconds` (default 1,800) is stopped with `JOB_DEADLINE_EXCEEDED`; a `hoi4.gui_rewrite` job is not stopped by that deadline.
173
+ See [persistent jobs and MCP tasks](jobs.md#cancellation-and-recovery).
168
174
 
169
175
  ## Source-backed button shading
170
176
 
@@ -186,20 +192,48 @@ The renderer does not run the game engine. Each render includes a fidelity repor
186
192
 
187
193
  ### Scenario fields
188
194
 
189
- Every `scenario` needs an `id`, a short label such as `"usa_1936"`. The other fields describe the game state the window is drawn under:
190
-
191
- | Field | Meaning |
192
- | -------------------------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
193
- | `date` | Game date, `"1936.1.1"`. |
194
- | `controls` | State controllers, `{"64": "GER"}`. |
195
- | `flags` | Flags on the viewing country, `{"show_settings_page": true}`. |
196
- | `closedFlags` | `true` treats every flag not listed in `flags` as unset, as on a country that never received it. Without it, an undeclared flag is unknown and every condition that reads it stays unresolved. |
197
- | `variables` | Variables on the viewing country, `{"settings_page": 1}`. |
198
- | `values` | Exact runtime values for localisation tokens and scripted GUI properties, keyed as they appear in source. |
199
- | `visibility` | Forced visibility by element or scripted GUI name, `{"settings_page_events": false}`; it overrides evaluated triggers. |
200
- | `scopes` | Named scope bindings such as `FROM` with their own state. |
201
- | `resolution`, `uiScale`, `state`, `language` | Screen size, in-game UI scale, preview element state, and localisation language. |
202
- | `background` | `"transparent"` renders without the preview backdrop, so pixels the window does not cover are fully transparent in every PNG. |
195
+ Every `scenario` needs an `id`, a short label such as `"usa_1936"`.
196
+ The other fields describe the game state the window is drawn under and how the preview is produced.
197
+ Unknown fields are rejected.
198
+ The complete schema is [gui-scenario.schema.json](../schemas/gui-scenario.schema.json); `relatedScenarios` entries and `comparisonScenario` use the same shape.
199
+
200
+ | Field | Type | Default and limits | Meaning |
201
+ | ---------------------- | --------------------------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
202
+ | `id` | string | Required; 1–128 characters matching `^[A-Za-z0-9][A-Za-z0-9._-]*$`. | Scenario label used in artifact names and reports. |
203
+ | `description` | string | Optional; at most 500 characters. | Free-text note about the scenario. |
204
+ | `date` | string | Optional; a valid calendar date as `YYYY.M.D` or `YYYY-MM-DD`, at most 16 characters. | Game date, `"1936.1.1"`, for date conditions. |
205
+ | `country` | map of name → string, number, or boolean | Optional. | Viewing-country values for `[ROOT.GetName]`-style text; `tag`, `countryTag`, or `GetTag` names the actor country for conditions and for country flags, and `ideology` selects the flag variant. |
206
+ | `controls` | map of state ID → country tag | Optional; state IDs are positive integers without leading zeros, tags are three `A-Z` or `0-9` characters, at most 2,048 entries. | State controllers, `{"64": "GER"}`, for `controls_state` and `is_controlled_by`. |
207
+ | `flags` | map of flag name → boolean | `{}`. | Flags on the viewing country, `{"show_settings_page": true}`. |
208
+ | `closedFlags` | boolean | Optional; absent means `false`. | `true` treats every flag not listed in `flags` as unset, as on a country that never received it. Without it, an undeclared flag is unknown and every condition that reads it stays unresolved. |
209
+ | `variables` | map of name → number | `{}`. | Variables on the viewing country, `{"settings_page": 1}`. |
210
+ | `values` | map of key → string, number, or boolean | `{}`; strings at most 16,384 characters. | Exact runtime values for localisation tokens, scripted-GUI properties, and element keys such as `element.visible`, `element.enabled`, `element.frame`, `element.x`, `container.scrollY`, or `element.width`. |
211
+ | `stateValues` | map of key → string, number, or boolean | Optional. | Additional condition state for the viewing country; `variables` and `values` override the same key. |
212
+ | `conditionResults` | array of condition records | Optional; at most 10,000 records of `{ token, sourcePath, state, localisationKey?, unresolved }`, where `state` is `true`, `false`, or `unresolved`. | Written by the scenario generator to record checked scripted-localisation choices and missing inputs. It is accepted on input so a returned scenario can be sent back unchanged; it does not decide any condition. |
213
+ | `visibility` | map of element or scripted-GUI name → boolean | `{}`. | Forced visibility, `{"settings_page_events": false}`; it overrides evaluated triggers. |
214
+ | `scopes` | map of scope name → scope binding | Optional; names at most 256 characters. | Named scope bindings such as `FROM`. A binding has `id` (1–256 characters) and optional `type`, `actor`, `state`, `flags` (an array of names), `eventTargets`, and `weight`. |
215
+ | `lists` | map of list name → array of row objects | `{}`; at most 256 list names and 10,000 rows across all lists. | Dynamic and native list rows. Each row is a map of scalars, such as `id`, `label`, `countryScope`, `entryContainer`, `countryTag`, `ideology`, and row-scoped element values. |
216
+ | `localisation` | map of key → text | `{}`. | Per-scenario localisation overrides; a key here replaces the installed text for that key. |
217
+ | `scriptedGui` | map of key → string, number, or boolean | `{}`. | Scripted-GUI property and token values, including exact `[!element_action]`-style tooltip tokens; `values` takes precedence for the same key. |
218
+ | `elementStates` | map of element name → preview state | `{}`; states as listed for `state`. | Per-element preview state that overrides `state` for that element. |
219
+ | `selectedFrames` | map of element or sprite name → integer | `{}`; integers of at least 0. | Zero-based frame index for a frame sprite, clamped to the last frame. It takes precedence over `.frame` values, which are one-based as in HOI4 source. |
220
+ | `scrollOffsets` | map of container name → number | `{}`; numbers of at least 0. | Vertical scroll offset shorthand in native UI pixels, including names with row-instance suffixes. |
221
+ | `guiCosts` | map of key → number | `{}`. | Cost shown by the GUI for a key. |
222
+ | `scriptCosts` | map of key → number | `{}`. | Cost charged by script for the same key; a different `guiCosts` value for that key reports `GUI_COST_MISMATCH`. |
223
+ | `expectations` | object | `{ "visible": [], "hidden": [], "containedBy": {}, "centeredOn": {} }`; each list holds at most 10,000 selectors. | Layout assertions: `visible` and `hidden` list selectors, `containedBy` maps a selector to its intended background or panel, and `centeredOn` maps a label to the control it should be centred on. |
224
+ | `tooltip` | object | Optional; `target` (1–256 characters), `x`, `y`, `width`, and `padding` are all required. `x`, `y`, and `padding` are at least 0, `width` is greater than 0 and at most 16,384, and `padding * 2` must be less than `width`. | Immediate tooltip preview for one element, as described in [Preview immediate tooltip text](#preview-immediate-tooltip-text). |
225
+ | `resolution` | `{ width, height }` | `{ "width": 1920, "height": 1080 }`; integers, width 320–16,384 and height 200–16,384, within the render pixel budget. | Screen size in pixels. |
226
+ | `uiScale` | number | `1`; 0.25–4. | In-game UI scale. It changes layout geometry and is not an output-image zoom. |
227
+ | `state` | string | `"normal"`; one of `normal`, `hover`, `selected`, `locked`, `disabled`, `warning`, `active`, `completed`, `empty-list`, `full-list`, `minimum-value`, `maximum-value`, `long-text`, `missing-localisation`. | Preview state applied to every element without an `elementStates` entry. |
228
+ | `language` | string | `"l_english"`; matches `^l_[a-z_]+$`. | Localisation language, which also selects language-specific fonts. |
229
+ | `background` | string | Optional; `scene` or `transparent`. Absent means `scene`. | `"transparent"` renders without the preview backdrop, so pixels the window does not cover are fully transparent in every PNG. |
230
+ | `animationTimeSeconds` | number | `0`; 0–86,400. | Elapsed time for frame animation and button-state shading; `0` represents entry into the state. |
231
+ | `visibleTimeSeconds` | number | Optional; 0–86,400. | Elapsed time since the window became visible, used by frame animations that play on show; absent means `animationTimeSeconds`. |
232
+
233
+ A whole scenario may hold at most 100,000 object keys and 1,000,000 string characters in total.
234
+
235
+ GUI `flags` is a `{ "name": true }` map.
236
+ Decision scenarios (`hoi4.decision_inspect`) and probability scenarios take `flags` as an array of flag names, such as `["relief_open"]`, and so do scope bindings in every tool, including GUI `scopes`.
203
237
 
204
238
  A scripted GUI `visible` or `<element>_visible` trigger that the scenario decides hides or shows its element exactly.
205
239
  For compositing, each visible element is its own `<g>` group in the full SVG, with an `id` that matches the element in `layout.json`, which also records every element's box.
@@ -212,3 +246,53 @@ Scripted localisation (`defined_text`) used by the window resolves to its first
212
246
  The generated primary view replaces discovered numeric and text runtime tokens with plausible values. Set `generatedScenarios.preservePlaceholder` to `true`, or disable generation, when the same run should also show unresolved numeric values such as `[?variable|format]` as `[X]` and unresolved text-returning scripted or scoped localisation such as `[GetStatusText]`, `[FROM.GetName]`, and `[?leader_scope.GetName]` as `[dynamic_loc]`. Put `variable` or `GetStatusText` in the supplied scenario's `values` object when an exact value matters; explicit values always take precedence over generated ones and can drive the related meter or state-dependent controls. Supported HOI4 `§` localisation colour controls use the active font's palette and `§!` restores the face colour.
213
247
 
214
248
  A rewrite stops if malformed or unsupported GUI script makes the requested change ambiguous. Frame-sheet animation, nine-slice tiling, progress composition, masking, and the primary and secondary textures referenced by vanilla GFX definitions render offline. Font selection follows mod/game load order and preview language, accepts Paradox hex and numeric color declarations, and uses the supplied HOI4 bitmap or outline font assets without requiring host font installation. Shader operations outside the supported colour subset, hardcoded controls, and dynamic values that are not supplied by a scenario remain fidelity-report entries; an unexecuted shader never hides its resolved base texture.
249
+
250
+ ### Generated scenarios
251
+
252
+ `generatedScenarios` configures the seeded exploratory scenarios that `hoi4.gui_inspect` and `hoi4.gui_render` build from the supplied scenario.
253
+ It requires a window `scenario`, and unknown fields are rejected.
254
+
255
+ | Field | Default and limits | Meaning |
256
+ | --------------------- | --------------------------------------------------------------------------------------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
257
+ | `enabled` | `true` | `false` renders only the supplied scenario and its related scenarios. |
258
+ | `count` | `1`; 1–16. | Number of generated scenarios. |
259
+ | `seed` | `"auto"`; 1–256 characters. | `"auto"` derives the seed from the window name, scenario `id`, and source-graph hash, so unchanged source reproduces the same output; any other string is used as the seed. |
260
+ | `idPrefix` | `"generated"`; 1–64 characters matching `^[A-Za-z0-9][A-Za-z0-9._-]*$`. | Generated scenario IDs are `<scenario id>-<idPrefix>-<n>`. |
261
+ | `preservePlaceholder` | `false` | `true` also renders the supplied scenario, with unresolved tokens shown as `[X]` and `[dynamic_loc]`. |
262
+ | `numericMinimum` | `0`; −1,000,000,000 to 1,000,000,000. | Lower bound for generated numbers. |
263
+ | `numericMaximum` | `100`; −1,000,000,000 to 1,000,000,000, and at least `numericMinimum`. | Upper bound for generated numbers. |
264
+ | `integerValues` | `true` | `false` allows decimal values. |
265
+ | `listRowsMinimum` | `1`; 0–100. | Fewest generated rows per list. |
266
+ | `listRowsMaximum` | `5`; 0–100, and at least `listRowsMinimum`. | Most generated rows per list. |
267
+ | `trueProbability` | `0.7`; 0–1. | Probability that a generated Boolean is `true`. |
268
+ | `visibility` | `"varied"`; `show-all` or `varied`. | `show-all` shows every scripted GUI that has a visibility trigger; `varied` samples which of them are shown. Explicit `visibility` entries are kept in both modes. |
269
+ | `elementStates` | `"normal"`; `normal` or `varied`. | `varied` samples per-element preview states; `normal` keeps controls in their normal state. |
270
+ | `textSamples` | `["Operational", "Ready", "Stable", "Available", "In Progress"]`; 1–64 strings of 1–128 characters. | Strings used for generated text values. |
271
+
272
+ ### Request fields
273
+
274
+ Every request accepts `workspaceId`, which defaults to `"current"`.
275
+ `windowName` is 1–256 characters, and `scenario` follows the scenario fields above.
276
+
277
+ | Field | Tools | Limits | Meaning |
278
+ | -------------------- | ------------------------ | -------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
279
+ | `windowName` | inspect, render, rewrite | Required for render and rewrite; inspect requires it exactly when `scenario` is present. | Root window to inspect, render, or validate. An inspect call without `windowName` and `scenario` inspects the workspace GUI graph. |
280
+ | `scenario` | inspect, render, rewrite | Required for render and rewrite. | Primary scenario. |
281
+ | `relatedScenarios` | inspect, render | At most 32; requires `scenario`. | Additional explicit scenarios rendered beside the primary and generated views. |
282
+ | `generatedScenarios` | inspect, render | Requires `scenario`. | Generator options from the table above. |
283
+ | `states` | render | At most 14 values of the `state` enumeration; defaults to all 14. | Preview states in the state gallery. |
284
+ | `resolutions` | render | 1–16 entries of `{ width, height, uiScale? }`, with the same size limits as `resolution` and `uiScale` 0.25–4. | Resolution gallery. The default is 1280×720, 1920×1080, and 2560×1440 at UI scale 1, plus 1920×1080 at UI scale 1.25. An entry without `uiScale` uses the scenario's `uiScale`. |
285
+ | `comparisonScenario` | render | Same shape as `scenario`. | Second scenario compared against the primary scenario on the current source. |
286
+ | `sourceBaseline` | render | `{ relativePath, source }`; `source` at most 32 MiB. | Previous mod-owned `.gui` text rendered with the same scenario for a source comparison. |
287
+ | `mode` | rewrite | Required; `source`, `helpers`, or `patches`. | Rewrite input form. |
288
+ | `relativePath` | rewrite | Required workspace-relative path. | Main `.gui` file to write. |
289
+ | `source` | rewrite | Required in `source` mode and rejected in the other modes; at most 32 MiB. | Complete replacement `.gui` source. |
290
+ | `helper` | rewrite | Required in `helpers` mode and rejected in the other modes. | Structured helper document; see [gui-helper.schema.json](../schemas/gui-helper.schema.json). |
291
+ | `additionalFiles` | rewrite | At most 31 entries of `{ relativePath, source }`, each `source` at most 32 MiB; rejected in `patches` mode. | Other files in the same text package, as described in [Create a GUI](#create-a-gui). |
292
+ | `expectedSourceHash` | rewrite | Required in `patches` mode and rejected otherwise; 64 lowercase hexadecimal characters. | SHA-256 of the current file bytes; a different current file fails with `GUI_SOURCE_STALE`. |
293
+ | `patches` | rewrite | Required in `patches` mode and rejected otherwise; 1–1,000 entries. | Targeted replacements of `{ start, end, expectedText, text, description }`. |
294
+ | `requestKey` | rewrite | 1–256 characters. | Caller-stable key for native background rewrites and their retries; see [rewrite request keys](jobs.md#rewrite-request-keys). |
295
+
296
+ Each patch replaces the source text between offsets `start` and `end`, which are integers of at least 0.
297
+ The current text in that range must equal `expectedText`; otherwise the rewrite stops with `GUI_PATCH_PRECONDITION_FAILED`.
298
+ `expectedText` and `text` are at most 5,000,000 characters each, and `description` is 1–1,000 characters.
@@ -1,7 +1,7 @@
1
1
  # Bounded helper expansion
2
2
 
3
3
  `hoi4.event_inspect` and `hoi4.tech_inspect` accept `mode: "helper_expansion"`.
4
- This is a read-only stream of source-linked helper paths, not a source rewrite or runtime simulation.
4
+ Follow helper calls back to their source and see where analysis could not resolve them.
5
5
  It avoids materializing the whole helper closure before returning its first page.
6
6
 
7
7
  Start either tool with:
@@ -33,13 +33,13 @@ To analyze edited source or use a different depth, start a new request without t
33
33
 
34
34
  `helperExpansion` has these optional fields:
35
35
 
36
- | Field | Contract |
37
- | ----------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
38
- | `rootIds` | Up to 2,000 exact structural helper-call root IDs; omitted means all recognized non-helper callers. Obtain IDs from a page's `rootId` or the linked ordinary scan graph. |
39
- | `maxDepth` | 1–256 helper calls, default 64. |
40
- | `maxRecords` | 1–5,000 records per page, default 250. |
41
- | `maxWork` | 1–100,000 traversal transitions per page, default 5,000. |
42
- | `continuationUri` | Opaque sibling resource returned in the prior tool result. Do not edit or construct it. |
36
+ | Field | Contract |
37
+ | ----------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
38
+ | `rootIds` | 1 to 2,000 exact structural helper-call root IDs; an empty array is rejected, and omitting the field selects all recognized non-helper callers. Obtain IDs from a page's `rootId` or the linked ordinary scan graph. |
39
+ | `maxDepth` | 1–256 helper calls, default 64. |
40
+ | `maxRecords` | 1–5,000 records per page, default 250. |
41
+ | `maxWork` | 1–100,000 traversal transitions per page, default 5,000. |
42
+ | `continuationUri` | Opaque sibling resource returned in the prior tool result. Do not edit or construct it. |
43
43
 
44
44
  Other inspection filters such as top-level `maxDepth`, `selector`, and `technologyId` are rejected in this mode rather than silently ignored.
45
45
  The shared dependency inventory is limited to one million edges; source, parser, and artifact byte limits also remain enforced.
@@ -69,7 +69,7 @@ This is not permanent storage of every historical page.
69
69
 
70
70
  ## Compatibility and boundaries
71
71
 
72
- This opt-in mode and optional result summary are additive in 3.1.0.
72
+ The `helper_expansion` mode and its `data.helperExpansion` result summary are opt-in; other inspection modes neither accept `helperExpansion` nor return the summary.
73
73
  Existing inspection modes retain their own ordering, representative-path policy, and materialization limits.
74
74
  A depth- or projection-truncated materialized graph reports incomplete coverage.
75
75
  The paged edge-path stream must not be mistaken for the deduplicated projections in those graphs.
package/docs/http.md CHANGED
@@ -41,7 +41,7 @@ Add an HTTP section to a config created by setup:
41
41
  }
42
42
  ```
43
43
 
44
- Set `HOI4_AGENT_HTTP_TOKEN` to a random value of at least 32 characters, then run `hoi4-agent-tools-http --config PATH`. `allowDiscoveredMods` grants that principal only the mod IDs created by discovery beneath `modRoots`; it never grants unrelated explicit workspaces. For narrower remote access, define the permitted mods as explicit `workspaces`, list those IDs in `workspaceIds`, and omit `allowDiscoveredMods`.
44
+ Set `HOI4_AGENT_HTTP_TOKEN` to a random value of at least 32 characters, then run `hoi4-agent-tools-http --config PATH`. `allowDiscoveredMods` grants that principal only the mod IDs created by discovery beneath `modRoots`; it never grants unrelated explicit workspaces. A static token always grants both `hoi4:read` and `hoi4:write`, so its holder can run the rewrite tools that change mod source. For narrower remote access, define the permitted mods as explicit `workspaces`, list those IDs in `workspaceIds`, and omit `allowDiscoveredMods`.
45
45
 
46
46
  ## Shared or remote access
47
47
 
@@ -54,6 +54,8 @@ A non-loopback deployment needs:
54
54
  - narrow mounted mod and game paths;
55
55
  - request, connection, and session limits.
56
56
 
57
+ The `http.oauth` block (`issuer`, `jwksUri`, `audience`, `requiredScopes`, `algorithms`) validates tokens; an OAuth principal receives only the scopes in its token, and `requiredScopes` defaults to `["hoi4:read"]`, so grant `hoi4:write` only to principals that may edit mods. `publicUrl`, `trustedProxyAddresses`, the timeouts, and the connection, session, event-stream and rate limits are listed in the [configuration reference](configuration.md#http).
58
+
57
59
  Do not expose a developer home directory or a whole game library. The installed game and dependencies should be mounted read-only. Use separate server instances for teams that should not share operating-system access.
58
60
 
59
61
  The server never launches Hearts of Iron IV and does not need a desktop or Steam session. See the repository [Security Policy](../SECURITY.md) before exposing HTTP beyond loopback.
package/docs/jobs.md CHANGED
@@ -1,10 +1,11 @@
1
1
  # Persistent jobs and MCP tasks
2
2
 
3
- Long-running domain operations support optional MCP tasks while preserving the ordinary tool-call contract.
3
+ Let a large preview or analysis run in the background, check its progress or stop it.
4
+ Long-running operations support optional MCP tasks and ordinary tool calls.
4
5
  Clients that negotiate task support can request a task, disconnect, reconnect with the same authorized identity, inspect or cancel it, and retrieve the original tool result after completion.
5
- Clients that do not request a task continue to receive the same synchronous tool result as before.
6
+ Clients that do not request a task receive the ordinary synchronous tool result.
6
7
 
7
- Version 3.1.0 routes 2025-era clients through the existing stateful adapter and 2026-07-28 clients through the [modern operation/task adapter](adr/0031-modern-mcp-task-adapter.md) on both stdio and HTTP.
8
+ The server routes 2025-era clients through the stateful adapter and 2026-07-28 clients through the [modern operation/task adapter](https://github.com/klimPaskov/hoi4-agent-tools/blob/main/docs/adr/0031-modern-mcp-task-adapter.md) on both stdio and HTTP.
8
9
  Modern requests independently negotiate the Tasks extension, use authenticated flat handles, and receive terminal results in `tasks/get`.
9
10
 
10
11
  Clients can request ordinary-call progress with a progress token.
@@ -14,15 +15,21 @@ A modern native task handoff ends that request's heartbeat without declaring the
14
15
 
15
16
  ## Supported tools
16
17
 
17
- Optional tasks are available for every read-only event, impact, decision, technology, probability, map, GUI, and focus operation, and for the three rewrite tools:
18
+ Optional tasks are available for all 19 domain tools; the 7 reference tools and the 2 job tools always answer in the foreground.
18
19
 
19
- - `hoi4.event_inspect`, `hoi4.event_render`, and `hoi4.event_compare`
20
- - `hoi4.impact_inspect` and `hoi4.decision_inspect`
21
- - `hoi4.tech_inspect`, `hoi4.tech_render`, and `hoi4.tech_compare`
22
- - `hoi4.probability_inspect`, `hoi4.probability_evaluate`, `hoi4.probability_sweep`, `hoi4.probability_simulate`, `hoi4.probability_sequence`, `hoi4.probability_compare`, and `hoi4.probability_render`
23
- - `hoi4.map_inspect`, `hoi4.map_render`, and `hoi4.map_rewrite`
20
+ - `hoi4.event_inspect` and `hoi4.event_render`
21
+ - `hoi4.impact_inspect`, `hoi4.decision_inspect`, `hoi4.mechanic_test`, `hoi4.package_check`, and `hoi4.scenario_test`
22
+ - `hoi4.tech_inspect` and `hoi4.tech_render`
23
+ - `hoi4.probability_inspect` and `hoi4.probability_analyze`
24
+ - `hoi4.map_inspect` and `hoi4.map_rewrite`
24
25
  - `hoi4.gui_inspect`, `hoi4.gui_render`, and `hoi4.gui_rewrite`
25
- - `hoi4.focus_inspect`, `hoi4.focus_render`, `hoi4.focus_raster`, and `hoi4.focus_rewrite`
26
+ - `hoi4.focus_inspect`, `hoi4.focus_render`, and `hoi4.focus_rewrite`
27
+
28
+ ## Warm workers
29
+
30
+ Domain tools run in a separate worker process. After a job the worker stays warm for `jobWorkerIdleSeconds` (default 180) and runs its server's next job with the indexes it already loaded, so a second GUI render or decision inspection of a large mod skips the cold scan. An idle worker holds no execution slot, exits when its idle time ends or its server closes, and a worker whose job failed, or whose heap still holds more than 40% of its limit after a job and a full collection, is never reused (the next job starts a fresh worker, so several heavy jobs in a row cannot exhaust one worker's heap). Set `jobWorkerIdleSeconds: 0` to start a fresh worker for every job.
31
+
32
+ ## Results
26
33
 
27
34
  Task results are exact tool results, including linked artifacts, partial-analysis markers, validation evidence, and tool-level errors.
28
35
  A completed tool-level error is therefore a completed task whose result has `isError: true`; an execution or storage failure is a failed task.
@@ -52,12 +59,14 @@ Cancelling an ordinary synchronous call prevents admission when possible and oth
52
59
  Closing the originating connection does not cancel an accepted native task.
53
60
 
54
61
  A worker busy in long synchronous analysis cannot observe its own cancellation, so the server that started it also supervises read-only jobs.
55
- A read-only job still running `jobCancelGraceSeconds` (default 10) after cancellation is stopped and settles as cancelled.
56
- A read-only job still running `jobDeadlineSeconds` (default 1,800) after it was dispatched is stopped and fails with `JOB_DEADLINE_EXCEEDED`; narrow its selector or limits, or raise the setting in the server configuration.
62
+ A read-only job still running `jobCancelGraceSeconds` (1–600, default 10) after cancellation is stopped and settles as cancelled.
63
+ A read-only job still running `jobDeadlineSeconds` (1–86,400, default 1,800) after it was dispatched is stopped and fails with `JOB_DEADLINE_EXCEEDED`; narrow its selector or limits, or raise the setting in the server configuration.
57
64
  Rewrite jobs are never stopped this way, because their transaction journal owns write recovery; they keep cooperative cancellation and reconciliation.
58
65
  Supervision belongs to the server process that dispatched the worker. A read-only worker whose dispatching server has exited enforces the same deadline itself and then exits; a rewrite worker keeps running until it finishes.
59
- `jobWorkerMaxHeapMiB` sets a V8 heap ceiling for each worker; without it, workers use Node's default.
60
- At most `maxSharedTools` (default 4) workers and expensive calls run at once across every server process that shares a `serverStateRoot`; further work waits for capacity.
66
+ `jobWorkerMaxHeapMiB` (256–65,536) sets a V8 heap ceiling for each worker; without it, a worker gets a quarter of physical memory, between 2,048 and 8,192 MiB.
67
+ A worker that stops without publishing a result ends the job with `JOB_WORKER_EXIT`, and the message gives the cause the server observed: a V8 heap limit (with its size), a native out-of-memory, a native crash, termination from outside the server, a stop by the server's own deadline, or an uncaught job error with its error code, together with the exit code or signal. Only a V8 heap limit or a native out-of-memory is a memory failure; raise `jobWorkerMaxHeapMiB` or narrow the request for those, and retry otherwise.
68
+ The standard error of the newest ten workers that ended unexpectedly is kept in `job-workers/logs` under the server state root.
69
+ At most `maxSharedTools` (1–128, default 4) workers and expensive calls run at once across every server process that shares a `serverStateRoot`; further work waits for capacity.
61
70
 
62
71
  Read-only jobs stage a source-revision-bound result checkpoint before terminal publication.
63
72
  If a worker or server stops after that checkpoint, a later authorized process publishes the retained result without rerunning the operation.