hoi4-agent-tools 3.10.0 → 4.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 (150) hide show
  1. package/CHANGELOG.md +109 -0
  2. package/README.md +115 -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/configuration.js +7 -0
  9. package/dist/hoi4_agent_tools/core/domain-scan-patterns.js +12 -0
  10. package/dist/hoi4_agent_tools/core/domain-tools.js +65 -0
  11. package/dist/hoi4_agent_tools/core/domain-validation.js +5 -2
  12. package/dist/hoi4_agent_tools/core/engine.js +29 -2
  13. package/dist/hoi4_agent_tools/core/index.js +2 -2
  14. package/dist/hoi4_agent_tools/core/job-executor.js +14 -1
  15. package/dist/hoi4_agent_tools/core/job-operation-registration.js +15 -7
  16. package/dist/hoi4_agent_tools/core/job-store.js +78 -5
  17. package/dist/hoi4_agent_tools/core/job-transactions.js +31 -2
  18. package/dist/hoi4_agent_tools/core/job-worker-host.js +215 -116
  19. package/dist/hoi4_agent_tools/core/job-worker.js +90 -36
  20. package/dist/hoi4_agent_tools/core/operation-result.js +123 -10
  21. package/dist/hoi4_agent_tools/core/operation-tasks.js +49 -89
  22. package/dist/hoi4_agent_tools/core/persistent-analysis-cache.js +25 -21
  23. package/dist/hoi4_agent_tools/core/server-registry.js +22 -5
  24. package/dist/hoi4_agent_tools/core/shared-request-capacity.js +26 -1
  25. package/dist/hoi4_agent_tools/core/source/cache.js +20 -10
  26. package/dist/hoi4_agent_tools/core/source/lexer.js +11 -3
  27. package/dist/hoi4_agent_tools/core/transactions.js +114 -23
  28. package/dist/hoi4_agent_tools/core/workspace.js +84 -8
  29. package/dist/hoi4_agent_tools/decision/ai.js +1 -1
  30. package/dist/hoi4_agent_tools/decision/service.js +28 -0
  31. package/dist/hoi4_agent_tools/decision/source-inventory.js +7 -5
  32. package/dist/hoi4_agent_tools/event/job-operations.js +9 -5
  33. package/dist/hoi4_agent_tools/event/operations.js +14 -1
  34. package/dist/hoi4_agent_tools/focus/job-operations.js +1 -2
  35. package/dist/hoi4_agent_tools/focus/tool-operations.js +1 -1
  36. package/dist/hoi4_agent_tools/gui/validators.js +8 -6
  37. package/dist/hoi4_agent_tools/map/bmp.js +1 -1
  38. package/dist/hoi4_agent_tools/map/derived.js +748 -0
  39. package/dist/hoi4_agent_tools/map/job-operations.js +7 -3
  40. package/dist/hoi4_agent_tools/map/model.js +103 -0
  41. package/dist/hoi4_agent_tools/map/operations.js +427 -58
  42. package/dist/hoi4_agent_tools/map/references.js +483 -0
  43. package/dist/hoi4_agent_tools/map/service.js +136 -61
  44. package/dist/hoi4_agent_tools/map/tool-operations.js +2 -1
  45. package/dist/hoi4_agent_tools/map/validation.js +3 -0
  46. package/dist/hoi4_agent_tools/map/world.js +1280 -0
  47. package/dist/hoi4_agent_tools/mcp/server/argument-errors.js +72 -0
  48. package/dist/hoi4_agent_tools/mcp/server/create-modern-operations.js +23 -5
  49. package/dist/hoi4_agent_tools/mcp/server/create.js +7 -0
  50. package/dist/hoi4_agent_tools/mcp/server/request-lifecycle.js +24 -30
  51. package/dist/hoi4_agent_tools/mcp/server/tool-listing.js +45 -0
  52. package/dist/hoi4_agent_tools/mcp/tools/analysis.js +25 -5
  53. package/dist/hoi4_agent_tools/mcp/tools/event.js +18 -29
  54. package/dist/hoi4_agent_tools/mcp/tools/focus.js +4 -12
  55. package/dist/hoi4_agent_tools/mcp/tools/gui.js +3 -3
  56. package/dist/hoi4_agent_tools/mcp/tools/job.js +2 -2
  57. package/dist/hoi4_agent_tools/mcp/tools/map.js +13 -16
  58. package/dist/hoi4_agent_tools/mcp/tools/probability.js +42 -48
  59. package/dist/hoi4_agent_tools/mcp/tools/reference.js +22 -5
  60. package/dist/hoi4_agent_tools/mcp/tools/technology.js +16 -29
  61. package/dist/hoi4_agent_tools/mcp/transports/http.js +28 -4
  62. package/dist/hoi4_agent_tools/mcp/transports/stdio-lifetime.js +31 -8
  63. package/dist/hoi4_agent_tools/probability/job-operations.js +4 -9
  64. package/dist/hoi4_agent_tools/probability/operations.js +175 -13
  65. package/dist/hoi4_agent_tools/probability/source-analysis.js +24 -1
  66. package/dist/hoi4_agent_tools/reference/error-log.js +359 -0
  67. package/dist/hoi4_agent_tools/reference/known-mistakes.js +307 -0
  68. package/dist/hoi4_agent_tools/reference/known-mistakes.json +154 -0
  69. package/dist/hoi4_agent_tools/reference/mod-index.js +101 -0
  70. package/dist/hoi4_agent_tools/reference/operations.js +88 -19
  71. package/dist/hoi4_agent_tools/reference/player-text.js +4 -3
  72. package/dist/hoi4_agent_tools/reference/script-validation.js +19 -1
  73. package/dist/hoi4_agent_tools/reference/service.js +6 -0
  74. package/dist/hoi4_agent_tools/schemas/event.js +78 -19
  75. package/dist/hoi4_agent_tools/schemas/focus-requests.js +10 -0
  76. package/dist/hoi4_agent_tools/schemas/lenient-arguments.js +266 -0
  77. package/dist/hoi4_agent_tools/schemas/map-requests.js +63 -20
  78. package/dist/hoi4_agent_tools/schemas/map.js +122 -3
  79. package/dist/hoi4_agent_tools/schemas/mod-tools.js +181 -0
  80. package/dist/hoi4_agent_tools/schemas/probability-requests.js +119 -9
  81. package/dist/hoi4_agent_tools/schemas/reference.js +13 -0
  82. package/dist/hoi4_agent_tools/schemas/scenarios.js +1 -3
  83. package/dist/hoi4_agent_tools/schemas/script-validation.js +13 -6
  84. package/dist/hoi4_agent_tools/schemas/technology.js +79 -21
  85. package/dist/hoi4_agent_tools/technology/job-operations.js +3 -4
  86. package/dist/hoi4_agent_tools/technology/operations.js +14 -1
  87. package/dist/hoi4_agent_tools/version.js +1 -1
  88. package/docs/README.md +7 -4
  89. package/docs/analysis.md +13 -0
  90. package/docs/configuration.md +281 -0
  91. package/docs/development.md +24 -2
  92. package/docs/events.md +27 -3
  93. package/docs/examples.md +6 -6
  94. package/docs/focus.md +125 -4
  95. package/docs/gui.md +98 -17
  96. package/docs/helper-expansion.md +8 -8
  97. package/docs/http.md +3 -1
  98. package/docs/jobs.md +19 -13
  99. package/docs/map.md +197 -6
  100. package/docs/mechanics.md +4 -0
  101. package/docs/probability.md +42 -15
  102. package/docs/reference.md +71 -4
  103. package/docs/setup.md +44 -11
  104. package/docs/technology.md +26 -1
  105. package/docs/third-party-notices.md +11 -0
  106. package/docs/tools.md +151 -42
  107. package/docs/troubleshooting.md +61 -0
  108. package/examples/clients/codex-config.toml +5 -2
  109. package/examples/clients/generic.json +2 -2
  110. package/examples/config/config.json +7 -0
  111. package/npm-shrinkwrap.json +151 -156
  112. package/package.json +13 -8
  113. package/schemas/configuration.schema.json +144 -128
  114. package/schemas/continuous-focus-palette.schema.json +1 -1
  115. package/schemas/custom-weighted-pool.schema.json +1 -1
  116. package/schemas/decision-inspect-input.schema.json +1 -1
  117. package/schemas/error-log-input.schema.json +55 -0
  118. package/schemas/event-feature-manifest.schema.json +1 -1
  119. package/schemas/focus-plan.schema.json +1 -1
  120. package/schemas/focus-planning-sidecar.schema.json +1 -1
  121. package/schemas/gui-animation-source.schema.json +1 -1
  122. package/schemas/gui-helper.schema.json +1 -1
  123. package/schemas/gui-scenario.schema.json +1 -1
  124. package/schemas/helper-expansion-request.schema.json +1 -1
  125. package/schemas/helper-expansion-summary.schema.json +1 -1
  126. package/schemas/impact-inspect-input.schema.json +1 -1
  127. package/schemas/map-operation.schema.json +597 -126
  128. package/schemas/mechanic-test-input.schema.json +1 -1
  129. package/schemas/mod-index-input.schema.json +51 -0
  130. package/schemas/operation-result.schema.json +2 -2
  131. package/schemas/package-check-input.schema.json +1 -1
  132. package/schemas/package-manifest.schema.json +1 -1
  133. package/schemas/probability-analysis-result.schema.json +1 -1
  134. package/schemas/probability-compare-input.schema.json +1 -1
  135. package/schemas/probability-evaluate-input.schema.json +1 -1
  136. package/schemas/probability-inspect-input.schema.json +1 -1
  137. package/schemas/probability-render-input.schema.json +1 -1
  138. package/schemas/probability-scenario-set.schema.json +1 -1
  139. package/schemas/probability-sequence-input.schema.json +1 -1
  140. package/schemas/probability-simulate-input.schema.json +1 -1
  141. package/schemas/probability-sweep-input.schema.json +1 -1
  142. package/schemas/reference-context-input.schema.json +1 -1
  143. package/schemas/reference-read-input.schema.json +1 -1
  144. package/schemas/reference-search-input.schema.json +1 -1
  145. package/schemas/scenario-suite.schema.json +3 -5
  146. package/schemas/scenario-test-input.schema.json +3 -5
  147. package/schemas/script-validate-input.schema.json +1 -1
  148. package/schemas/shared-scenario.schema.json +1 -1
  149. package/schemas/source-lookup-input.schema.json +1 -1
  150. package/server.json +3 -3
@@ -7,7 +7,7 @@ npm ci
7
7
  npm run check
8
8
  ```
9
9
 
10
- `npm run check` runs formatting, type checks, tests, fixture checks, schema generation checks, build checks, and package validation. Use narrower commands during iteration:
10
+ `npm run check` runs formatting, lint, type checks, tests, fixture checks, schema generation checks, build checks, package validation, and MCP Registry metadata validation. Use narrower commands during iteration:
11
11
 
12
12
  ```bash
13
13
  npm run test
@@ -23,7 +23,7 @@ The event-chain acceptance fixture contains more than 300 project-owned event de
23
23
 
24
24
  The technology acceptance fixture contains 1,040 project-owned technologies across 13 folders and exercises classic and current doctrines, prerequisites, exclusive branches, multiple placements, unlocks, bonuses, grants, assets, unresolved references, rendering, and comparison.
25
25
 
26
- `npx vitest run tests/integration/mcp-concurrent-workloads.test.ts` tests simultaneous production calls across all six domains over six HTTP sessions and four independent stdio processes, including artifact retrieval and queued cancellation. Execution limits and connection behavior are described in [HTTP](http.md) and the [concurrency decision](https://github.com/klimPaskov/hoi4-agent-tools/blob/main/docs/adr/0026-concurrent-request-execution.md).
26
+ `npx vitest run tests/integration/mcp-concurrent-workloads.test.ts` tests simultaneous production calls across the tool domains over six HTTP sessions and four independent stdio processes, including artifact retrieval and queued cancellation. Execution limits and connection behavior are described in [HTTP](http.md) and the [concurrency decision](https://github.com/klimPaskov/hoi4-agent-tools/blob/main/docs/adr/0026-concurrent-request-execution.md).
27
27
 
28
28
  Persistent-job qualification covers authenticated record publication, request-key conflicts, read-result checkpoints, transaction-journal reconciliation, stopped-owner takeover, native task negotiation, ordinary-call parity, reconnect isolation, rewrite cancellation before source application, and fixed-entry worker execution. The public lifecycle contract is documented in [Persistent jobs and MCP tasks](jobs.md).
29
29
 
@@ -39,8 +39,30 @@ npm run test:local
39
39
 
40
40
  Add `HOI4_DEPENDENCY_ROOTS` as the platform path-delimited list when the external mod has dependencies. Local tests remain read-only.
41
41
 
42
+ `tests/integration/mcp-stdio-smoke.test.ts` starts the real `src/bin/stdio.ts` entry point and calls every exposed tool once with the argument shape an agent sends, then once with a deliberately wrong field.
43
+ Each success must be a non-error `ok` result whose inline structured content stays under 40 KB, and each wrong call must be a `INVALID_ARGUMENTS` tool error that names the field and shows a working example.
44
+ The suite also builds a world with `create_world`, splits and merges a state with `create_state` and `merge_states`, repairs script references with `remap_map_references`, and load-checks the resulting `definition.csv`, state, strategic region, supply and railway files independently of the server's own validator.
45
+ `tests/local/mcp-stdio-smoke.test.ts` repeats the read-only calls against the installed game (through an empty mod) and the external mod above; set `HOI4_SMOKE_REPORT` to a file path to receive the per-tool coverage table with timings.
46
+ Set `HOI4_SMOKE_STDIO_ENTRY` to the absolute `dist/bin/stdio.js` path in a clean tarball installation to test the packaged server instead of the TypeScript source. Rewrites receive invalid inputs on the real mod; successful writes are exercised only on synthetic fixtures.
47
+ `npm run benchmark:cold` times the slow first calls (`hoi4.mod_index`, an event lint and a decision inventory) of a real mod in a fresh server process and again in a second process on the same state folder; the maintainer checklist for tagging a release is `docs/RELEASING.md` in the repository.
48
+
42
49
  The installed-game qualification also parses every shipped bitmap-font descriptor, resolves every atlas page, shapes native and enlarged glyphs, verifies deterministic raster output, and checks HOI4 localisation colours across base fonts and language overrides.
43
50
 
51
+ ## Adding a known mistake
52
+
53
+ `src/hoi4_agent_tools/reference/known-mistakes.json` is the reviewed list behind `known_mistakes` in `hoi4.script_validate`, the `knownMistakes` of `hoi4.reference_context`, and the `knownMistake` of `hoi4.error_log`.
54
+ It is not written at run time: a mistake enters it through a commit.
55
+
56
+ 1. Find the mistake in the offline wiki, the game documentation, or a reproduced `error.log` message, and note the page, heading and item.
57
+ A rule without a source is not accepted.
58
+ 2. Add the rule: a unique snake_case `id`, `severity` (`error` when the definition cannot work, `warning` otherwise), the `surfaces` it belongs to, a `title`, the `mistake`, its `symptom`, the `fix`, the `sources`, and, when the game logs a fixed message, a `logPattern` regular expression.
59
+ 3. Add the detector with the same id in `known-mistakes.ts`, working on the parsed file, and the families it applies to.
60
+ `tests/unit/known-mistakes.test.ts` fails when a rule has no detector or a detector has no rule; add a case that flags the mistake and one that accepts the corrected script.
61
+ 4. When the rule is written from a recurring `error.log` pattern, run `hoi4.error_log` first: its `patterns` show the shapes, and the new `logPattern` makes later logs name the fix.
62
+
63
+ When the game fixes the behaviour, or the rule turns out to be wrong, set `status` to `resolved` and add `resolution` with the date and the reason, and leave the entry in the file.
64
+ A resolved rule is not applied and its detector is skipped; deleting it would lose why it was removed.
65
+
44
66
  See the package [Security Policy](../SECURITY.md) for private vulnerability reporting.
45
67
 
46
68
  ## Dependencies
package/docs/events.md CHANGED
@@ -6,6 +6,8 @@ Use the three event tools directly from the target mod.
6
6
 
7
7
  ## Inspect
8
8
 
9
+ A selector may also be a plain string: an event ID such as `my_mod.12`, a namespace such as `my_mod`, or a file path such as `events/my_events.txt`. An object without `kind` is read the same way from its `eventId`, `namespace`, `path` and `line` fields.
10
+
9
11
  `hoi4.event_inspect` provides eight focused modes:
10
12
 
11
13
  - `scan`: inventory event definitions, namespaces, call sites, and unresolved references.
@@ -40,6 +42,11 @@ Selectors use one of these forms:
40
42
 
41
43
  `impact` requires an `impactSubject` object with `kind` and `name`. Allowed impact kinds are `event`, `helper`, `flag`, `variable`, `array`, `event_target`, and `saved_scope`. Set `refresh: true` after source changes when a prior graph may be cached.
42
44
 
45
+ `maxDepth` defaults to 8 (range 1 to 64), `maxNodes` defaults to 500 (range 1 to 5,000), and `maxEdges` defaults to 2,000 (range 1 to 20,000).
46
+ `direction` defaults to `both`.
47
+ `expandHelpers` defaults to `true` for `explain_path` and `false` for the other modes.
48
+ `refresh` defaults to `true` for `scan` and `false` for the other modes.
49
+
43
50
  Example `hoi4.event_inspect` arguments:
44
51
 
45
52
  ```json
@@ -55,6 +62,19 @@ Example `hoi4.event_inspect` arguments:
55
62
  }
56
63
  ```
57
64
 
65
+ Example `explain_path` arguments, which explain the route from one event to another:
66
+
67
+ ```json
68
+ {
69
+ "mode": "explain_path",
70
+ "from": { "kind": "event", "eventId": "my_namespace.1" },
71
+ "to": { "kind": "event", "eventId": "my_namespace.5" },
72
+ "maxDepth": 8
73
+ }
74
+ ```
75
+
76
+ `from` and `to` accept any selector form and are both required in this mode.
77
+
58
78
  ## Render
59
79
 
60
80
  `hoi4.event_render` produces deterministic, source-linked views of a chain. The exact `view` values are `overview`, `neighborhood`, `options`, `entries`, `reachability`, `timing`, `state`, `targets`, `scope`, `terminals`, and `unresolved`. JSON is the authoritative graph; SVG and PNG provide visual review, with HTML available for bundled navigation when requested.
@@ -63,6 +83,9 @@ Large overview requests return a compact overview plus bounded branch JSON/SVG/P
63
83
 
64
84
  Dynamic and meta-generated targets that cannot be resolved statically remain explicit unresolved edges. The renderer never invents a destination.
65
85
 
86
+ `maxDepth` defaults to 4 (range 1 to 64) and `maxNodes` defaults to 120 (range 1 to 240).
87
+ `direction` defaults to `both`, and `expandHelpers`, `includeHtml`, and `refresh` default to `false`.
88
+
66
89
  Example `hoi4.event_render` arguments:
67
90
 
68
91
  ```json
@@ -80,16 +103,17 @@ Example `hoi4.event_render` arguments:
80
103
 
81
104
  ## Compare
82
105
 
83
- `hoi4.event_compare` compares whole workspace event graphs. `before` and `after` each accept exactly one graph reference: `{ "revision": "<sha256>" }` or `{ "artifactUri": "hoi4-agent://..." }`. If no reference or overlay is supplied, the tool compares the previous cached revision with a fresh scan of the current source and reports an error when no prior revision is available. Comparisons refresh current source by default so normal agent file edits are detected; set `refresh: false` only when intentionally comparing cached graphs.
106
+ `hoi4.event_inspect` with `mode: compare` compares whole workspace event graphs. `before` and `after` each accept exactly one graph reference: `{ "revision": "<sha256>" }` or `{ "artifactUri": "hoi4-agent://..." }`. If no reference or overlay is supplied, the tool compares the previous cached revision with a fresh scan of the current source and reports an error when no prior revision is available. Comparisons refresh current source by default so normal agent file edits are detected; set `refresh: false` only when intentionally comparing cached graphs.
84
107
 
85
108
  Set `selector` to an event, namespace, file, source location, node, or manifest to view the downstream chain in both revisions. `maxChainNodes` bounds each traversal, defaults to 1,000, and reports `selectionTruncated` when the chain exceeds the boundary. The artifact retains the full comparison and graph hashes, and its `selection` reports selected, omitted, and unattributed changes explicitly. Diagnostics without a chain owner remain unattributed. The rendered view uses the selected changed nodes.
86
109
 
87
110
  Alternatively, compare the current graph with `proposedSources`, an in-memory list of `{ relativePath, source, expectedSourceHash? }` overlays. Set `source` to a string to add or replace source, or to `null` to delete an existing mod source. `after` and `proposedSources` are mutually exclusive. Proposed sources are analyzed without being written. The result reports added, removed, and changed definitions, edges, options, state operations, diagnostics, and route reachability.
88
111
 
89
- Example `hoi4.event_compare` arguments:
112
+ Example `hoi4.event_inspect` comparison arguments:
90
113
 
91
114
  ```json
92
115
  {
116
+ "mode": "compare",
93
117
  "proposedSources": [
94
118
  {
95
119
  "relativePath": "events/example.txt",
@@ -114,6 +138,6 @@ A coding agent can combine the viewer with repository instructions, skills, and
114
138
  2. use `trace`, `explain_path`, `state_flow`, or `impact` for the current task;
115
139
  3. read linked JSON evidence only when the compact summary is insufficient;
116
140
  4. edit event source with the agent's normal file-editing workflow;
117
- 5. call `hoi4.event_compare`, `lint`, and `hoi4.event_render` to review the result; comparison refreshes the edited source by default.
141
+ 5. call `hoi4.event_inspect` with `mode: compare` and `lint`, then `hoi4.event_render` to review the result; comparison refreshes the edited source by default.
118
142
 
119
143
  Static analysis cannot prove runtime conditions, random outcomes, delayed scheduling, or arbitrary meta-generated text. Those limits are reported in diagnostics and artifacts rather than hidden or guessed. The server never launches or captures Hearts of Iron IV.
package/docs/examples.md CHANGED
@@ -2,7 +2,7 @@
2
2
 
3
3
  Start with a task you would normally give your coding agent.
4
4
  The agent chooses the MCP tools and opens the resulting images or source references.
5
- The renders below use actual Chaos Redux and installed HOI4 files; use names from your own mod when trying the prompts.
5
+ The renders below use real mod and installed HOI4 files; use names from your own mod when trying the prompts.
6
6
 
7
7
  ## Find a rule without reading a whole wiki
8
8
 
@@ -31,7 +31,7 @@ The [focus guide](focus.md) covers inspecting, rendering and reorganizing trees.
31
31
  [![Infantry technology folder](images/comparisons/infantry-mcp.png)](images/comparisons/infantry-mcp.png)
32
32
 
33
33
  The preview follows the loaded technology and GUI definitions, including wide equipment cards.
34
- The [technology comparisons](visual-comparisons.md#technology-folders) also show a mod folder with wide equipment cards rendered from a matching recorded source revision.
34
+ The [technology comparisons](https://github.com/klimPaskov/hoi4-agent-tools/blob/main/docs/visual-comparisons.md#technology-folders) also show a mod folder with wide equipment cards rendered from a matching recorded source revision.
35
35
  See the [technology guide](technology.md) for grants, bonuses and doctrine paths.
36
36
 
37
37
  ## Inspect an interface before editing it
@@ -44,7 +44,7 @@ See the [technology guide](technology.md) for grants, bonuses and doctrine paths
44
44
 
45
45
  For a mod window, ask for the same view at 100% and 125% UI scale and supply the state values needed by its controls.
46
46
  Unknown state values must stay unresolved; a visible button alone does not establish that it is enabled in the game.
47
- The [interface gallery](gui-comparisons.md) includes Škoda Priority, Chaos Redux Settings, Event Log, Chaos Meter, decisions and occupation views.
47
+ The [interface gallery](https://github.com/klimPaskov/hoi4-agent-tools/blob/main/docs/gui-comparisons.md) includes a vanilla priority panel, a mod settings window, an event log, a status panel, and the decision and occupation views.
48
48
 
49
49
  ## Locate map data and plan an edit
50
50
 
@@ -60,7 +60,7 @@ See [Maps](map.md) for supported edits.
60
60
 
61
61
  > Trace this event's options and follow-up events. Point out unresolved calls and link each route to its source.
62
62
 
63
- [![Chaos Redux event options](images/comparisons/source/event-chain-mcp.png)](images/comparisons/source/event-chain-mcp.png)
63
+ [![Mod event options](images/comparisons/source/event-chain-mcp.png)](images/comparisons/source/event-chain-mcp.png)
64
64
 
65
65
  > Compare this decision's `ai_will_do` score before and after my change in peace and war. List missing conditions separately from known results.
66
66
 
@@ -71,5 +71,5 @@ A decision score is not automatically a percentage chance of an AI click.
71
71
 
72
72
  The images are source previews, not recordings of the server running the game.
73
73
  Supplied game screenshots are identified separately and published with permission.
74
- The [comparison pages](visual-comparisons.md) and [interface gallery](gui-comparisons.md) keep source details, reproducible inputs and known differences alongside the images.
75
- The package does not include HOI4 or Chaos Redux source files or artwork.
74
+ The [comparison pages](https://github.com/klimPaskov/hoi4-agent-tools/blob/main/docs/visual-comparisons.md) and [interface gallery](https://github.com/klimPaskov/hoi4-agent-tools/blob/main/docs/gui-comparisons.md) keep source details, reproducible inputs and known differences alongside the images.
75
+ The package does not include HOI4 or mod source files or artwork.
package/docs/focus.md CHANGED
@@ -1,6 +1,6 @@
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
+ Use `hoi4.focus_inspect`, `hoi4.focus_render`, and `hoi4.focus_rewrite` for national focus trees and continuous focus palettes.
4
4
 
5
5
  ## Create a tree
6
6
 
@@ -14,7 +14,108 @@ A complete plan should include:
14
14
  - focus positions, convergence points, and shared support branches;
15
15
  - titles, descriptions, icons, filters, and AI behavior.
16
16
 
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.
17
+ The `plan` argument of `hoi4.focus_rewrite` follows [focus-plan.schema.json](../schemas/focus-plan.schema.json).
18
+ 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`.
19
+ A minimal plan that creates a two-focus tree looks like this:
20
+
21
+ ```json
22
+ {
23
+ "relativePath": "common/national_focus/my_focus_tree.txt",
24
+ "treeId": "my_focus_tree",
25
+ "createIfMissing": true,
26
+ "plan": {
27
+ "schemaVersion": 1,
28
+ "id": "my_focus_tree",
29
+ "countryAssignment": {
30
+ "raw": {
31
+ "text": "{ factor = 0 modifier = { add = 10 tag = AAA } }",
32
+ "referencedFocusIds": []
33
+ },
34
+ "countryTags": ["AAA"]
35
+ },
36
+ "default": false,
37
+ "branchGroups": [],
38
+ "laneGroups": [],
39
+ "entryFocusIds": ["my_root_focus"],
40
+ "focuses": [
41
+ {
42
+ "id": "my_root_focus",
43
+ "label": "Root focus",
44
+ "prerequisites": { "operator": "and", "groups": [] },
45
+ "mutuallyExclusive": [],
46
+ "routeLocks": [],
47
+ "position": { "mode": "fixed", "x": 0, "y": 0, "pinned": false },
48
+ "visibility": "normal",
49
+ "convergence": false,
50
+ "sharedSupport": false,
51
+ "icons": [{ "kind": "static", "sprite": "GFX_goal_generic_political_pressure" }],
52
+ "localisation": { "titleKey": "my_root_focus", "descriptionKey": "my_root_focus_desc" },
53
+ "ai": {
54
+ "raw": { "text": "{ factor = 1 }", "referencedFocusIds": [] },
55
+ "majorRoute": false,
56
+ "strategyIds": []
57
+ },
58
+ "filters": ["FOCUS_FILTER_POLITICAL"],
59
+ "links": [],
60
+ "cost": 10,
61
+ "completionReward": { "text": "{ add_political_power = 50 }", "referencedFocusIds": [] },
62
+ "rawPassthrough": []
63
+ },
64
+ {
65
+ "id": "my_second_focus",
66
+ "label": "Second focus",
67
+ "prerequisites": {
68
+ "operator": "and",
69
+ "groups": [{ "operator": "or", "focusIds": ["my_root_focus"], "rawPassthrough": [] }]
70
+ },
71
+ "mutuallyExclusive": [],
72
+ "routeLocks": [],
73
+ "position": {
74
+ "mode": "relative",
75
+ "x": 0,
76
+ "y": 1,
77
+ "relativeTo": "my_root_focus",
78
+ "pinned": false
79
+ },
80
+ "visibility": "normal",
81
+ "convergence": false,
82
+ "sharedSupport": false,
83
+ "icons": [{ "kind": "static", "sprite": "GFX_goal_generic_construct_civ_factory" }],
84
+ "localisation": { "titleKey": "my_second_focus", "descriptionKey": "my_second_focus_desc" },
85
+ "ai": {
86
+ "raw": { "text": "{ factor = 1 }", "referencedFocusIds": [] },
87
+ "majorRoute": false,
88
+ "strategyIds": []
89
+ },
90
+ "filters": ["FOCUS_FILTER_INDUSTRY"],
91
+ "links": [],
92
+ "cost": 10,
93
+ "completionReward": {
94
+ "text": "{ add_tech_bonus = { bonus = 0.5 uses = 1 category = industry } }",
95
+ "referencedFocusIds": []
96
+ },
97
+ "rawPassthrough": []
98
+ }
99
+ ],
100
+ "sharedFocusIds": [],
101
+ "continuousFocusPaletteIds": [],
102
+ "continuousFocusIds": [],
103
+ "rawPassthrough": [],
104
+ "provenance": {
105
+ "sourcePath": "plan:my_focus_tree",
106
+ "sourceHash": "0000000000000000000000000000000000000000000000000000000000000000",
107
+ "importedPlanHash": "0000000000000000000000000000000000000000000000000000000000000000"
108
+ }
109
+ }
110
+ }
111
+ ```
112
+
113
+ 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.
114
+ Each `prerequisites.groups` entry is one `prerequisite` block whose `focusIds` are alternatives.
115
+ `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.
116
+ When `treeId` is also supplied, it must equal `plan.id`.
117
+
118
+ 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
119
 
19
120
  ## Clean an existing tree
20
121
 
@@ -28,6 +129,11 @@ For a layout-only cleanup of an existing national tree, call `hoi4.focus_rewrite
28
129
  }
29
130
  ```
30
131
 
132
+ A plan-free call is accepted only in national mode with `layoutMode: "compact"`.
133
+ It requires `treeId`, works on an existing focus source, and rejects `createIfMissing: true`.
134
+ Every other national rewrite requires a `plan`.
135
+ `compactFocusIds` (1 to 10,000 IDs), `pinnedFocusIds` (up to 10,000 IDs), and `symmetryGroups` (up to 64 groups) are accepted only with `layoutMode: "compact"`.
136
+
31
137
  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
138
 
33
139
  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 +146,21 @@ Pass `symmetryGroups` with a `centerFocusId` and one or more `{ "leftFocusId": "
40
146
 
41
147
  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
148
 
149
+ ## Continuous focus palettes
150
+
151
+ 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`.
152
+
153
+ - `hoi4.focus_inspect` and `hoi4.focus_render` select one palette with `paletteId`.
154
+ Without it, inspection includes every palette in the selected source, and rendering requires the source to contain exactly one palette.
155
+ The inspection JSON artifact lists the imported palette plans in `continuousFocusPalettes`.
156
+ - `treeId` is rejected in continuous mode.
157
+ Inspection also rejects `previous`, `laneSpacing`, `nodeSpacing`, and `scenario`, and rendering rejects `horizontalSpacing`, `verticalSpacing`, `reviewScale`, and `cropFocusIds`.
158
+ - Rendering accepts `columns` (1 to 12) only in continuous mode, and continuous `padding` must be at least 24 pixels.
159
+ - `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.
160
+ `layoutMode` must stay `authored`, and `horizontalSpacing`, `verticalSpacing`, `padding`, and `reviewScale` are rejected.
161
+ - A palette needs a mod-owned source.
162
+ Creating a palette with `createIfMissing: true` requires a new source file, so an unrelated existing file is never repurposed.
163
+
43
164
  ## Layout metadata and unsupported script
44
165
 
45
166
  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 +173,10 @@ Inspection and rendering can report missing references, invalid prerequisite str
52
173
 
53
174
  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
175
 
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.
176
+ 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
177
 
57
178
  The layout JSON reports horizontal, vertical, and Manhattan grid spans for every prerequisite connector in `layout.connectorMeasurements`.
58
179
 
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.
180
+ `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
181
 
61
182
  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
@@ -6,7 +6,7 @@ Use `hoi4.gui_inspect`, `hoi4.gui_render`, and `hoi4.gui_rewrite` for `.gui`, `.
6
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
8
 
9
- The [interface examples](gui-comparisons.md) show real vanilla and Chaos Redux windows.
9
+ The [interface examples](https://github.com/klimPaskov/hoi4-agent-tools/blob/main/docs/gui-comparisons.md) show real vanilla and mod windows.
10
10
  Cyan click regions have confirmed availability under the supplied scenario.
11
11
  Dashed amber regions are potential controls with unresolved visibility or enabling conditions; they do not count as confirmed branch coverage.
12
12
  The scene retains the reason so the agent can supply the missing facts instead of guessing.
@@ -112,7 +112,7 @@ Generation is reproducible. Set `generatedScenarios.seed` to any stable string f
112
112
  ```json
113
113
  {
114
114
  "generatedScenarios": {
115
- "seed": "chaos-meter-review",
115
+ "seed": "status-panel-review",
116
116
  "count": 3,
117
117
  "numericMinimum": 0,
118
118
  "numericMaximum": 100,
@@ -164,7 +164,10 @@ Broad inspection indexes localisation actually referenced by GUI source and retu
164
164
 
165
165
  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
166
 
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.
167
+ Large inspections, renders, and rewrites send periodic MCP progress heartbeats while a service stage is still running.
168
+ Clients that request progress can reset their idle request timer from these notifications, and cancellation follows the request signal.
169
+ 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.
170
+ See [persistent jobs and MCP tasks](jobs.md#cancellation-and-recovery).
168
171
 
169
172
  ## Source-backed button shading
170
173
 
@@ -186,20 +189,48 @@ The renderer does not run the game engine. Each render includes a fidelity repor
186
189
 
187
190
  ### Scenario fields
188
191
 
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. |
192
+ Every `scenario` needs an `id`, a short label such as `"usa_1936"`.
193
+ The other fields describe the game state the window is drawn under and how the preview is produced.
194
+ Unknown fields are rejected.
195
+ The complete schema is [gui-scenario.schema.json](../schemas/gui-scenario.schema.json); `relatedScenarios` entries and `comparisonScenario` use the same shape.
196
+
197
+ | Field | Type | Default and limits | Meaning |
198
+ | ---------------------- | --------------------------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
199
+ | `id` | string | Required; 1–128 characters matching `^[A-Za-z0-9][A-Za-z0-9._-]*$`. | Scenario label used in artifact names and reports. |
200
+ | `description` | string | Optional; at most 500 characters. | Free-text note about the scenario. |
201
+ | `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. |
202
+ | `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. |
203
+ | `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`. |
204
+ | `flags` | map of flag name → boolean | `{}`. | Flags on the viewing country, `{"show_settings_page": true}`. |
205
+ | `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. |
206
+ | `variables` | map of name → number | `{}`. | Variables on the viewing country, `{"settings_page": 1}`. |
207
+ | `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`. |
208
+ | `stateValues` | map of key → string, number, or boolean | Optional. | Additional condition state for the viewing country; `variables` and `values` override the same key. |
209
+ | `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. |
210
+ | `visibility` | map of element or scripted-GUI name → boolean | `{}`. | Forced visibility, `{"settings_page_events": false}`; it overrides evaluated triggers. |
211
+ | `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`. |
212
+ | `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. |
213
+ | `localisation` | map of key → text | `{}`. | Per-scenario localisation overrides; a key here replaces the installed text for that key. |
214
+ | `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. |
215
+ | `elementStates` | map of element name → preview state | `{}`; states as listed for `state`. | Per-element preview state that overrides `state` for that element. |
216
+ | `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. |
217
+ | `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. |
218
+ | `guiCosts` | map of key → number | `{}`. | Cost shown by the GUI for a key. |
219
+ | `scriptCosts` | map of key → number | `{}`. | Cost charged by script for the same key; a different `guiCosts` value for that key reports `GUI_COST_MISMATCH`. |
220
+ | `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. |
221
+ | `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). |
222
+ | `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. |
223
+ | `uiScale` | number | `1`; 0.25–4. | In-game UI scale. It changes layout geometry and is not an output-image zoom. |
224
+ | `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. |
225
+ | `language` | string | `"l_english"`; matches `^l_[a-z_]+$`. | Localisation language, which also selects language-specific fonts. |
226
+ | `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. |
227
+ | `animationTimeSeconds` | number | `0`; 0–86,400. | Elapsed time for frame animation and button-state shading; `0` represents entry into the state. |
228
+ | `visibleTimeSeconds` | number | Optional; 0–86,400. | Elapsed time since the window became visible, used by frame animations that play on show; absent means `animationTimeSeconds`. |
229
+
230
+ A whole scenario may hold at most 100,000 object keys and 1,000,000 string characters in total.
231
+
232
+ GUI `flags` is a `{ "name": true }` map.
233
+ 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
234
 
204
235
  A scripted GUI `visible` or `<element>_visible` trigger that the scenario decides hides or shows its element exactly.
205
236
  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 +243,53 @@ Scripted localisation (`defined_text`) used by the window resolves to its first
212
243
  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
244
 
214
245
  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.
246
+
247
+ ### Generated scenarios
248
+
249
+ `generatedScenarios` configures the seeded exploratory scenarios that `hoi4.gui_inspect` and `hoi4.gui_render` build from the supplied scenario.
250
+ It requires a window `scenario`, and unknown fields are rejected.
251
+
252
+ | Field | Default and limits | Meaning |
253
+ | --------------------- | --------------------------------------------------------------------------------------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
254
+ | `enabled` | `true` | `false` renders only the supplied scenario and its related scenarios. |
255
+ | `count` | `1`; 1–16. | Number of generated scenarios. |
256
+ | `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. |
257
+ | `idPrefix` | `"generated"`; 1–64 characters matching `^[A-Za-z0-9][A-Za-z0-9._-]*$`. | Generated scenario IDs are `<scenario id>-<idPrefix>-<n>`. |
258
+ | `preservePlaceholder` | `false` | `true` also renders the supplied scenario, with unresolved tokens shown as `[X]` and `[dynamic_loc]`. |
259
+ | `numericMinimum` | `0`; −1,000,000,000 to 1,000,000,000. | Lower bound for generated numbers. |
260
+ | `numericMaximum` | `100`; −1,000,000,000 to 1,000,000,000, and at least `numericMinimum`. | Upper bound for generated numbers. |
261
+ | `integerValues` | `true` | `false` allows decimal values. |
262
+ | `listRowsMinimum` | `1`; 0–100. | Fewest generated rows per list. |
263
+ | `listRowsMaximum` | `5`; 0–100, and at least `listRowsMinimum`. | Most generated rows per list. |
264
+ | `trueProbability` | `0.7`; 0–1. | Probability that a generated Boolean is `true`. |
265
+ | `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. |
266
+ | `elementStates` | `"normal"`; `normal` or `varied`. | `varied` samples per-element preview states; `normal` keeps controls in their normal state. |
267
+ | `textSamples` | `["Operational", "Ready", "Stable", "Available", "In Progress"]`; 1–64 strings of 1–128 characters. | Strings used for generated text values. |
268
+
269
+ ### Request fields
270
+
271
+ Every request accepts `workspaceId`, which defaults to `"current"`.
272
+ `windowName` is 1–256 characters, and `scenario` follows the scenario fields above.
273
+
274
+ | Field | Tools | Limits | Meaning |
275
+ | -------------------- | ------------------------ | -------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
276
+ | `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. |
277
+ | `scenario` | inspect, render, rewrite | Required for render and rewrite. | Primary scenario. |
278
+ | `relatedScenarios` | inspect, render | At most 32; requires `scenario`. | Additional explicit scenarios rendered beside the primary and generated views. |
279
+ | `generatedScenarios` | inspect, render | Requires `scenario`. | Generator options from the table above. |
280
+ | `states` | render | At most 14 values of the `state` enumeration; defaults to all 14. | Preview states in the state gallery. |
281
+ | `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`. |
282
+ | `comparisonScenario` | render | Same shape as `scenario`. | Second scenario compared against the primary scenario on the current source. |
283
+ | `sourceBaseline` | render | `{ relativePath, source }`; `source` at most 32 MiB. | Previous mod-owned `.gui` text rendered with the same scenario for a source comparison. |
284
+ | `mode` | rewrite | Required; `source`, `helpers`, or `patches`. | Rewrite input form. |
285
+ | `relativePath` | rewrite | Required workspace-relative path. | Main `.gui` file to write. |
286
+ | `source` | rewrite | Required in `source` mode and rejected in the other modes; at most 32 MiB. | Complete replacement `.gui` source. |
287
+ | `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). |
288
+ | `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). |
289
+ | `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`. |
290
+ | `patches` | rewrite | Required in `patches` mode and rejected otherwise; 1–1,000 entries. | Targeted replacements of `{ start, end, expectedText, text, description }`. |
291
+ | `requestKey` | rewrite | 1–256 characters. | Caller-stable key for native background rewrites and their retries; see [rewrite request keys](jobs.md#rewrite-request-keys). |
292
+
293
+ Each patch replaces the source text between offsets `start` and `end`, which are integers of at least 0.
294
+ The current text in that range must equal `expectedText`; otherwise the rewrite stops with `GUI_PATCH_PRECONDITION_FAILED`.
295
+ `expectedText` and `text` are at most 5,000,000 characters each, and `description` is 1–1,000 characters.
@@ -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.