hoi4-agent-tools 3.9.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 (157) hide show
  1. package/CHANGELOG.md +118 -0
  2. package/README.md +115 -147
  3. package/dist/bin/http.js +12 -0
  4. package/dist/bin/setup.js +3 -2
  5. package/dist/bin/stdio.js +12 -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 +56 -10
  13. package/dist/hoi4_agent_tools/core/index.js +45 -20
  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 +155 -0
  24. package/dist/hoi4_agent_tools/core/server-status-resource.js +22 -0
  25. package/dist/hoi4_agent_tools/core/shared-request-capacity.js +26 -1
  26. package/dist/hoi4_agent_tools/core/source/cache.js +108 -29
  27. package/dist/hoi4_agent_tools/core/source/lexer.js +11 -3
  28. package/dist/hoi4_agent_tools/core/transactions.js +114 -23
  29. package/dist/hoi4_agent_tools/core/workspace.js +84 -8
  30. package/dist/hoi4_agent_tools/decision/ai.js +1 -1
  31. package/dist/hoi4_agent_tools/decision/service.js +28 -0
  32. package/dist/hoi4_agent_tools/decision/source-inventory.js +7 -5
  33. package/dist/hoi4_agent_tools/event/job-operations.js +9 -5
  34. package/dist/hoi4_agent_tools/event/operations.js +14 -1
  35. package/dist/hoi4_agent_tools/event/service.js +7 -0
  36. package/dist/hoi4_agent_tools/focus/job-operations.js +1 -2
  37. package/dist/hoi4_agent_tools/focus/tool-operations.js +1 -1
  38. package/dist/hoi4_agent_tools/gui/scenario-generator.js +11 -3
  39. package/dist/hoi4_agent_tools/gui/studio.js +20 -7
  40. package/dist/hoi4_agent_tools/gui/validators.js +8 -6
  41. package/dist/hoi4_agent_tools/map/bmp.js +1 -1
  42. package/dist/hoi4_agent_tools/map/derived.js +748 -0
  43. package/dist/hoi4_agent_tools/map/job-operations.js +7 -3
  44. package/dist/hoi4_agent_tools/map/model.js +103 -0
  45. package/dist/hoi4_agent_tools/map/operations.js +427 -58
  46. package/dist/hoi4_agent_tools/map/references.js +483 -0
  47. package/dist/hoi4_agent_tools/map/service.js +136 -61
  48. package/dist/hoi4_agent_tools/map/tool-operations.js +2 -1
  49. package/dist/hoi4_agent_tools/map/validation.js +3 -0
  50. package/dist/hoi4_agent_tools/map/world.js +1280 -0
  51. package/dist/hoi4_agent_tools/mcp/resources/register-modern.js +13 -1
  52. package/dist/hoi4_agent_tools/mcp/resources/register.js +6 -0
  53. package/dist/hoi4_agent_tools/mcp/server/argument-errors.js +72 -0
  54. package/dist/hoi4_agent_tools/mcp/server/create-modern-operations.js +23 -5
  55. package/dist/hoi4_agent_tools/mcp/server/create.js +7 -0
  56. package/dist/hoi4_agent_tools/mcp/server/request-lifecycle.js +24 -30
  57. package/dist/hoi4_agent_tools/mcp/server/tool-listing.js +45 -0
  58. package/dist/hoi4_agent_tools/mcp/tools/analysis.js +25 -5
  59. package/dist/hoi4_agent_tools/mcp/tools/event.js +18 -29
  60. package/dist/hoi4_agent_tools/mcp/tools/focus.js +4 -12
  61. package/dist/hoi4_agent_tools/mcp/tools/gui.js +3 -3
  62. package/dist/hoi4_agent_tools/mcp/tools/job.js +2 -2
  63. package/dist/hoi4_agent_tools/mcp/tools/map.js +13 -16
  64. package/dist/hoi4_agent_tools/mcp/tools/probability.js +42 -48
  65. package/dist/hoi4_agent_tools/mcp/tools/reference.js +22 -5
  66. package/dist/hoi4_agent_tools/mcp/tools/technology.js +16 -26
  67. package/dist/hoi4_agent_tools/mcp/transports/http.js +28 -4
  68. package/dist/hoi4_agent_tools/mcp/transports/stdio-lifetime.js +37 -18
  69. package/dist/hoi4_agent_tools/probability/job-operations.js +4 -9
  70. package/dist/hoi4_agent_tools/probability/operations.js +175 -13
  71. package/dist/hoi4_agent_tools/probability/source-analysis.js +24 -1
  72. package/dist/hoi4_agent_tools/reference/error-log.js +359 -0
  73. package/dist/hoi4_agent_tools/reference/known-mistakes.js +307 -0
  74. package/dist/hoi4_agent_tools/reference/known-mistakes.json +154 -0
  75. package/dist/hoi4_agent_tools/reference/mod-index.js +101 -0
  76. package/dist/hoi4_agent_tools/reference/operations.js +88 -19
  77. package/dist/hoi4_agent_tools/reference/player-text.js +4 -3
  78. package/dist/hoi4_agent_tools/reference/script-validation.js +19 -1
  79. package/dist/hoi4_agent_tools/reference/service.js +6 -0
  80. package/dist/hoi4_agent_tools/schemas/event.js +78 -19
  81. package/dist/hoi4_agent_tools/schemas/focus-requests.js +10 -0
  82. package/dist/hoi4_agent_tools/schemas/lenient-arguments.js +266 -0
  83. package/dist/hoi4_agent_tools/schemas/map-requests.js +63 -20
  84. package/dist/hoi4_agent_tools/schemas/map.js +122 -3
  85. package/dist/hoi4_agent_tools/schemas/mod-tools.js +181 -0
  86. package/dist/hoi4_agent_tools/schemas/probability-requests.js +119 -9
  87. package/dist/hoi4_agent_tools/schemas/reference.js +13 -0
  88. package/dist/hoi4_agent_tools/schemas/scenarios.js +1 -3
  89. package/dist/hoi4_agent_tools/schemas/script-validation.js +13 -6
  90. package/dist/hoi4_agent_tools/schemas/technology.js +83 -23
  91. package/dist/hoi4_agent_tools/technology/job-operations.js +3 -4
  92. package/dist/hoi4_agent_tools/technology/operations.js +14 -1
  93. package/dist/hoi4_agent_tools/technology/service.js +7 -0
  94. package/dist/hoi4_agent_tools/version.js +1 -1
  95. package/docs/README.md +7 -4
  96. package/docs/analysis.md +13 -0
  97. package/docs/configuration.md +281 -0
  98. package/docs/development.md +24 -2
  99. package/docs/events.md +27 -3
  100. package/docs/examples.md +6 -6
  101. package/docs/focus.md +125 -4
  102. package/docs/gui.md +98 -17
  103. package/docs/helper-expansion.md +8 -8
  104. package/docs/http.md +3 -1
  105. package/docs/jobs.md +19 -13
  106. package/docs/map.md +197 -6
  107. package/docs/mechanics.md +4 -0
  108. package/docs/probability.md +42 -15
  109. package/docs/reference.md +71 -4
  110. package/docs/setup.md +45 -11
  111. package/docs/technology.md +26 -1
  112. package/docs/third-party-notices.md +11 -0
  113. package/docs/tools.md +151 -42
  114. package/docs/troubleshooting.md +61 -0
  115. package/examples/clients/codex-config.toml +5 -2
  116. package/examples/clients/generic.json +2 -2
  117. package/examples/config/config.json +7 -0
  118. package/npm-shrinkwrap.json +161 -162
  119. package/package.json +13 -8
  120. package/schemas/configuration.schema.json +144 -128
  121. package/schemas/continuous-focus-palette.schema.json +1 -1
  122. package/schemas/custom-weighted-pool.schema.json +1 -1
  123. package/schemas/decision-inspect-input.schema.json +1 -1
  124. package/schemas/error-log-input.schema.json +55 -0
  125. package/schemas/event-feature-manifest.schema.json +1 -1
  126. package/schemas/focus-plan.schema.json +1 -1
  127. package/schemas/focus-planning-sidecar.schema.json +1 -1
  128. package/schemas/gui-animation-source.schema.json +1 -1
  129. package/schemas/gui-helper.schema.json +1 -1
  130. package/schemas/gui-scenario.schema.json +1 -1
  131. package/schemas/helper-expansion-request.schema.json +1 -1
  132. package/schemas/helper-expansion-summary.schema.json +1 -1
  133. package/schemas/impact-inspect-input.schema.json +1 -1
  134. package/schemas/map-operation.schema.json +597 -126
  135. package/schemas/mechanic-test-input.schema.json +1 -1
  136. package/schemas/mod-index-input.schema.json +51 -0
  137. package/schemas/operation-result.schema.json +2 -2
  138. package/schemas/package-check-input.schema.json +1 -1
  139. package/schemas/package-manifest.schema.json +1 -1
  140. package/schemas/probability-analysis-result.schema.json +1 -1
  141. package/schemas/probability-compare-input.schema.json +1 -1
  142. package/schemas/probability-evaluate-input.schema.json +1 -1
  143. package/schemas/probability-inspect-input.schema.json +1 -1
  144. package/schemas/probability-render-input.schema.json +1 -1
  145. package/schemas/probability-scenario-set.schema.json +1 -1
  146. package/schemas/probability-sequence-input.schema.json +1 -1
  147. package/schemas/probability-simulate-input.schema.json +1 -1
  148. package/schemas/probability-sweep-input.schema.json +1 -1
  149. package/schemas/reference-context-input.schema.json +1 -1
  150. package/schemas/reference-read-input.schema.json +1 -1
  151. package/schemas/reference-search-input.schema.json +1 -1
  152. package/schemas/scenario-suite.schema.json +3 -5
  153. package/schemas/scenario-test-input.schema.json +3 -5
  154. package/schemas/script-validate-input.schema.json +1 -1
  155. package/schemas/shared-scenario.schema.json +1 -1
  156. package/schemas/source-lookup-input.schema.json +1 -1
  157. package/server.json +3 -3
package/CHANGELOG.md CHANGED
@@ -1,5 +1,123 @@
1
1
  # Changelog
2
2
 
3
+ ## Unreleased
4
+
5
+ ## 4.0.0 - 2026-10-10
6
+
7
+ ### Known mistakes
8
+
9
+ - Add a reviewed, source-cited list of documented script mistakes (`known-mistakes.json`, with a detector for each rule) in place of a mutable learned-rule database. `hoi4.script_validate` in file mode flags seven of them as `KNOWN_MISTAKE_<RULE>` with the symptom and the fix and reports `known_mistakes` in `checksPerformed`: an event without `add_namespace`, an event number that is not a whole number below 100,000, a timer on a triggered-only event, an automatic event that can fire every day, a news event that is not `major` or is `fire_only_once`, a date window shorter than the 20-day trigger check, and a scope prefix on a temporary variable.
10
+ - `hoi4.reference_context` returns the `knownMistakes` of the requested surface, and `hoi4.error_log` adds `knownMistake` (rule id and fix) to a logged message that a rule explains. A rule that no longer applies is kept as `resolved` with the date and reason and is not applied.
11
+
12
+ ### Maps
13
+
14
+ - `move_state_provinces` redistributes by default: without a `distribution`, or with `"proportional"`, the target receives the moved provinces' share of the source state's manpower, resources and slot buildings (in whole units; levels such as infrastructure keep the higher value). `stateValues: "retain-in-current-states"` keeps the old behaviour.
15
+ - `merge_states`, `create_state` and `split_state` accept `remapReferences` (`refuse` or `override`) to rewrite the scripts that named the state in the same plan.
16
+ - Script references now include `has_full_control_of_state`, `set_state_controller`, `to_state`, `border_state`, `capital` in any script, `set_province_controller`, `reset_province_name`, `goto_province`, `prioritize_location`, `to_province`, `region`, `area`, `prioritize = { ... }` lists and `province = { id = ... }` blocks. Arguments that take exactly one value are never copied or deleted by a remap; they change to the first successor, or stay and are reported as `MAP_REFERENCE_NEEDS_REVIEW`.
17
+ - `MAP_COUNTRY_CAPITAL_NOT_OWNED` is checked only in `history/countries`.
18
+
19
+ ### Tools
20
+
21
+ - Show at most 8 resource links beside a result (images first); every artifact stays in `structuredContent.artifacts`. A GUI render result was about 33 KB, a third of it links listed twice. Passed validation checks that only report a problem "not detected" are no longer listed.
22
+
23
+ ### Workers
24
+
25
+ - A warm job worker whose heap still holds more than 40% of its limit after a job and a full collection exits instead of waiting for the next job. Against the real Chaos Redux mod, a GUI render followed by a decision inspection in one worker ran past the 4 GB heap limit and ended with `JOB_WORKER_EXIT`; the next job now starts in a fresh worker. The `JOB_WORKER_EXIT` message now names an out-of-memory exit and the `jobWorkerMaxHeapMiB` setting.
26
+
27
+ ### Documentation
28
+
29
+ - Add a troubleshooting guide with the error codes and their fixes, the tool audit and the review of smerss/Clausewitz-MCP and cpntodd/HOI4-MCP under `docs/plans`, a worked example that builds and reshapes a world in the map guide, and a section on adding a known mistake to the development guide.
30
+
31
+ ### Breaking changes
32
+
33
+ - 37 tools become 28, one inspect tool per domain:
34
+ - `hoi4.probability_inspect` finds weighted logic and evaluates it in the same call, with a fact-free scenario when none is given; `evaluate: false` returns only the inventory. `hoi4.probability_analyze` replaces `hoi4.probability_evaluate`'s siblings `_sweep`, `_simulate`, `_sequence`, `_compare` and `_render`, selected by `analysis`; `hoi4.probability_evaluate` itself is folded into `hoi4.probability_inspect`.
35
+ - `hoi4.event_compare` and `hoi4.tech_compare` become `mode: compare` of `hoi4.event_inspect` and `hoi4.tech_inspect`.
36
+ - `hoi4.focus_raster` is folded into `hoi4.focus_render`, which now produces the PNG with decoded icons by default; `png: false` keeps the vector-only output.
37
+ - `hoi4.map_render` is folded into `hoi4.map_inspect`: a `layer`, `overlays`, `scale`, `tile` or `area` renders that view.
38
+ - Inline results list at most 12 scanned files, mod files first.
39
+
40
+ - The HTTP server verifies the bearer token before it reads a request body, so an unauthenticated `POST /mcp` receives `401` without its body being parsed; body-dependent scopes such as `hoi4:write` for rewrites are checked again afterwards.
41
+ - Behind a trusted proxy, rate limiting uses the rightmost `X-Forwarded-For` hop that is not a trusted proxy instead of the leftmost, client-supplied entry.
42
+ - A rewrite journal that cannot be recovered no longer stops startup: the server starts, and rewrites of that workspace fail with `TRANSACTION_RECOVERY_REQUIRED` until recovery succeeds. A journal folder without a manifest is skipped.
43
+ - Rolling back a transaction keeps a planned file that was never replaced and has no backup, instead of refusing the whole rollback; a replaced file that changed since still reports `TRANSACTION_STALE`.
44
+ - `tools/list` omits the JSON Schema dialect and the safe-integer bounds that every integer field repeated; field types, ranges and descriptions are unchanged.
45
+
46
+ ### Agent ergonomics
47
+
48
+ - Accept the argument shorthands agents most often send: an event selector as a plain string or without `kind`, a GUI scenario without `id`, a decision inspection without a scenario, a probability scenario set as a bare list or without ids and `state`, a probability `source` as a string, and `generatedScenarios.maxScenarios`. The full event selector is published in the tool schema. Also a namespace wildcard such as `chaosx.nr14.*`, a selector with `id` for its own field, a trace started from `from`, a GUI inspection without a scenario, a decision by `decisionId`, and a script file check that names the kind and scope its file fixes.
49
+ - Answer invalid arguments with a tool error, code `INVALID_ARGUMENTS`, naming each failing field, what it expected and a working call, instead of a protocol error that clients reduced to "Invalid tool arguments". Error and blocked results carry their blockers in the text content, which is what clients show for an error.
50
+ - Find decisions in files that open the same category block more than once; such decisions were reported as unresolved definitions. Decision inspections list each scenario's eligible, visible and available outcome inline, and a sample of any unresolved definitions.
51
+ - A snippet check without a `kind` is read as the effect or trigger with fewer errors and unresolved commands, and a `limit`, `maxDepth`, `maxNodes` or `maxEdges` above its maximum is lowered to the maximum, instead of rejecting the call.
52
+ - Return the answer inline: probability results rank the strongest candidates per scenario with weight, probability and MTTH, list the facts still missing, and list the largest changes of a comparison.
53
+ - An event ID in a probability `candidatePool` stands for all its options and a `random_list` ID for its entries; a pool alone finds its defining file; a wrong adapter guess, such as a mission named as a decision, switches to the matching adapter.
54
+ - Order inline diagnostics with the mod's own files first, summarise an omitted flood by code, and keep the first diagnostics of an oversized result instead of dropping them all.
55
+ - Name the error kind and a path-free message for unexpected failures, and print the cause of a startup failure such as a configuration file's JSON error.
56
+ - `hoi4.error_log` adds a fix hint per category, groups messages that differ only in names and numbers into `patterns`, and compares each new launch's log with the previous one: `sinceLastLaunch` counts new, persisting and fixed entries and every entry says whether it is new.
57
+ - Every tool description now says what the tool is for, shows a working example call and gives the size of the answer, and every invalid-argument error shows an example for its tool (28 of 28; ten before). Tests send each published example to its tool's schema, and `docs/tools.md` lists the examples with the result sizes.
58
+
59
+ ### Speed
60
+
61
+ - Keep a job worker warm for `jobWorkerIdleSeconds` (default 180) after a job, so its server's next job reuses the loaded indexes instead of scanning cold. An idle worker holds no execution slot and exits with its server; a failed job never leaves a worker for reuse.
62
+ - Authenticate persistent cache entries over their metadata and payload hash instead of the whole payload, decode a cached parsed document when it is first read instead of for every file at load, and stop copying the payload of an entry that is already stored on every scan. The entry format version is 2, so older entries are rewritten once. Fill the canonical copy used for hashing and for index segments directly, about 40% faster on large segments with identical output.
63
+ - Record where a cold index of a large mod spends its time, and why a background warm-up of the persistent cache does not help it, in ADR 0045. Add `npm run benchmark:cold`, which times `hoi4.mod_index`, an event lint and a decision inventory in a first and a second server process.
64
+
65
+ ### Maps
66
+
67
+ - Add `create_world` to `hoi4.map_rewrite`: a complete new map from dimensions, a seed, land coverage or outlines and countries, with provinces, terrain, heights, rivers, trees, colour maps, continents, strategic regions with weather, states, country files, history, flags, a bookmark, localisation, positions, supply and `replace_path` entries.
68
+ - Add `regenerate_map_positions` (building, unit-stack and weather positions from geometry), `rebuild_supply` (supply nodes in state capitals joined to each country's hub by railway, or only the states with a supply gap) and `remap_map_references` (rewrite script references to changed states, provinces or regions, copying a reference per successor, and override game files only on request).
69
+ - Add `references: true` to `hoi4.map_inspect`: missing state, province and region references across events, focuses, decisions, helpers, history and AI areas, undeclared state tags, and countries whose capital they do not own.
70
+ - Split states with dated history: dated ownership and effects apply to both parts, and dated victory points and buildings follow their provinces. Merges carry dated blocks without building levels.
71
+ - Keep level buildings (infrastructure, air bases, anti-air, radar, or any building without `shares_slots`) at their level in both parts of a split and at the highest level in a merge, and divide slot buildings and resources in whole units.
72
+ - A merge's distribution policy may be omitted. Generated positions take their height from the heightmap. Province 0's reserved null row no longer reports an unknown terrain or a missing continent.
73
+ - Name transaction diff artifacts safely for files with spaces in their names.
74
+ - Say why a restored rewrite failed: `JOB_REWRITE_RESTORED` now names the error and the first failing check or blocking diagnostic, such as `GUI_REFERENCE_UNRESOLVED`, instead of only that the source was restored.
75
+ - Review a new world over sources that hold no map without a "before" picture, instead of failing with `MAP_RENDER_RASTER_MISSING`.
76
+ - Notice a changed `descriptor.mod` at the next scan of a running server. A new world adds `replace_path` folders to the descriptor, and its post-write check used to see the base-game states it replaces and fail on duplicate state IDs until the server restarted. Jobs, transactions and caches keep the workspace identity they started under.
77
+ - Stop undoing map rewrites that touch a state file. The post-write check scanned only the changed files, so every province a state lists counted as an unresolved reference unless the rewrite also changed `map/definition.csv`; a split, merge or manpower change on a real map was restored with `JOB_REWRITE_RESTORED`. The check now also reads `map/default.map` and the map CSV files.
78
+
79
+ ### Tools
80
+
81
+ - Add `hoi4.error_log`: read the game's `logs/error.log` from its last launch, grouped by category, with each entry's source file, line and layer, whether that file changed since the log was written, and `scope`, `category` and text filters. Set `gameUserRoot` when the game's user folder is not found automatically.
82
+ - Add `hoi4.mod_index`: summarize a mod's descriptor, definitions by kind, folders and event namespace ranges, or find the next free numbered ID for an event namespace or prefix across every source layer, with the first unused gap.
83
+ - Name the tool and up to five failing fields with their reasons when the 2026-07-28 server rejects tool arguments.
84
+ - Check every supported family of `hoi4.script_validate` file mode from one shared scan, skip localisation from shadowed files in player-text checks, and report only `§` colour codes in news text.
85
+ - Report an overlapping pair whose visibility the GUI scenario does not decide only as `GUI_UNRESOLVED_VISIBILITY_OVERLAP`, without a generic overlap or click-region conflict.
86
+ - Print `startup_timeout_sec = 120` and `tool_timeout_sec = 600` in the Codex registrations from `hoi4-agent-tools-setup --print-client-config`.
87
+
88
+ ### Fixes
89
+
90
+ - Lex Clausewitz whitespace with a character-code test instead of a regular expression per character, which shortens the cold index of a large mod by roughly a quarter.
91
+ - Update the MCP SDK packages (`@modelcontextprotocol/sdk` 1.32.1, `core`, `server` and `client` 2.3.1, `node` 2.1.1) and `sharp` 0.35.5 past their published high-severity advisories.
92
+ - Keep each file's own diagnostics when an index is rebuilt incrementally after an edit; a rebuild could copy other files' errors and lose real ones.
93
+ - Close a cancelled stdio request so the idle limit still applies, count a request open for twice the idle limit as abandoned, and finish open requests before exiting after the launching process exits.
94
+ - Record an orphaned worker's own deadline as `JOB_DEADLINE_EXCEEDED` instead of leaving the job running.
95
+ - Start one worker launcher per job across HTTP requests and polls, and spawn nothing when the job has finished or a live worker runs it.
96
+ - Re-check a rewrite's journal under the workspace lock before applying it, re-hash the backup it moves aside, and take over a stale workspace lock only through an atomic rename that one process can win.
97
+ - Refuse reads, not only writes, of server storage (`.hoi4-agent`, artifact and cache roots) through workspace paths.
98
+ - Keep artifact listings from removing a folder that a concurrent write is filling.
99
+ - Evict a chunked artifact by the age of its newest member, index first, and protect all its pieces when any of them is protected, so a large result's index never points at evicted pieces.
100
+ - Treat a job store lock held for more than ten minutes as abandoned even when its process ID now belongs to another process, and wait at most two minutes for the lock before failing with `JOB_STORE_BUSY`, so a lock left by a crashed process cannot hang every job.
101
+ - Sweep expired finished job results on first use, and keep the record of a refused task call for five minutes.
102
+ - Bound retained scan snapshots by bytes, remove temporary files from failed heartbeat writes, and drop server records silent for two hours.
103
+ - Release a foreground task's cancellation listener when the task finishes.
104
+
105
+ ### Documentation
106
+
107
+ - Restructure the README around what the server does, a four-step quick start, a grouped tool table with what each area writes, and safety notes.
108
+ - Add a configuration reference with every key, range, default location and environment variable.
109
+ - Complete the GUI scenario and request field tables, and document the prompt, resources, task-capable tools and setup troubleshooting commands.
110
+ - Add `docs/RELEASING.md`, the checklist for tagging a release, and describe the stdio smoke suites in the development guide: every tool called once with an agent-style argument shape and once with a wrong field, a generated world split, merged and repaired, and the same calls against the installed game and a real mod.
111
+
112
+ ## 3.10.0 - 2026-10-06
113
+
114
+ - Rebuild a workspace index after an edit from the previous index, parsing and indexing only changed files, and keep the latest scan of each pattern set and each GUI graph scope instead of one per workspace. A repeated GUI preview of a large, actively edited mod took 64 s instead of 244 s.
115
+ - Admit parsed documents to a full cache only on their second miss and only in place of entries never read, so scans larger than the cache no longer serialize and evict every document; build scripted-localisation definitions only for windows that show scripted localisation.
116
+ - List every server process sharing a server state root, with its memory, last client activity and execution limits, in the `hoi4-agent://server/status` resource of local stdio connections.
117
+ - Refuse an `hoi4.event_compare` or `hoi4.tech_compare` call without references before scanning when no earlier revision is cached, instead of after a full scan.
118
+ - Report a `hoi4.tech_render` folder view without `folderId` as a readable argument error instead of a raw validation dump.
119
+ - Ship `proxy-addr` 2.0.8, which fixes IP spoofing through IPv4-mapped IPv6 trust subnets (GHSA-jqcg-44mw-7w3h); the HTTP server sets no `trust proxy`, so earlier releases did not reach the affected code.
120
+
3
121
  ## 3.9.0 - 2026-10-06
4
122
 
5
123
  - Exit a stdio server whose launching process has exited, and add `stdioIdleExitMinutes` so clients that keep idle per-subagent connections no longer accumulate servers.
package/README.md CHANGED
@@ -1,160 +1,128 @@
1
1
  # HOI4 Agent Tools
2
2
 
3
- Give your coding agent one MCP server for Hearts of Iron IV modding.
4
- It can find local documentation and vanilla examples, inspect a mod, render its trees and interfaces, compare source behavior, and make focused edits to focus trees, GUIs and maps.
5
- The pictures below use real Chaos Redux or installed HOI4 files; click any image for the full-size version.
3
+ [![npm](https://img.shields.io/npm/v/hoi4-agent-tools)](https://www.npmjs.com/package/hoi4-agent-tools)
4
+ [![Node.js](https://img.shields.io/node/v/hoi4-agent-tools)](https://nodejs.org/)
5
+ [![License](https://img.shields.io/npm/l/hoi4-agent-tools)](LICENSE)
6
6
 
7
- ## Get started
7
+ An [MCP](https://modelcontextprotocol.io/) server that lets a coding agent such as Claude Code, Codex or Cursor read, preview, analyse and safely edit a Hearts of Iron IV mod.
8
+ Your agent gets cited answers from the game's own documentation, pictures of focus trees, technology folders, interfaces and maps, and checks that catch load errors before you launch the game.
8
9
 
9
- Install [Node.js](https://nodejs.org/) 22.19+ in the Node 22 line, or Node.js 24, then run:
10
+ [![A large focus tree rendered from mod source](docs/images/comparisons/holy-realm-mcp.png)](docs/images/comparisons/holy-realm-mcp.png)
10
11
 
11
- ```bash
12
- npm install --global hoi4-agent-tools
13
- hoi4-agent-tools-setup --print-client-config
14
- ```
12
+ ## What it does
13
+
14
+ | Area | Ask your agent, for example |
15
+ | ---------------------- | ---------------------------------------------------------------------------------------------------------- |
16
+ | Find the rule | "Find the installed documentation for `save_event_target_as` and show a vanilla usage with file and line." |
17
+ | Check before launch | "Check `events/my_events.txt` for scope errors, then group the last `error.log` by category." |
18
+ | See the tree | "Render this mod's largest focus tree and list focuses with missing icons." |
19
+ | Preview the window | "Preview this scripted GUI at 100% and 125% UI scale and check for clipped text." |
20
+ | Read the map | "Find Brandenburg, list its provinces and neighbours, and show the files a change would touch." |
21
+ | Reshape the map | "Split Brandenburg in two and update every event and focus that names it." |
22
+ | Build a new world | "Create a 2048x1024 world with six countries, then list what still needs hand-made content." |
23
+ | Follow the events | "Trace this event's options and follow-up events and point out unresolved calls." |
24
+ | Weigh the AI | "Show the AI weights of event `my_mod.12`'s options, then compare them before and after my change." |
25
+ | Plan new content | "Give me the next free event ID in my namespace and summarize what the mod defines." |
26
+ | Edit with a safety net | "Add a new branch to this focus tree" — the edit is validated before anything is written. |
27
+
28
+ The server never launches the game.
29
+ Previews and tests are built from source files, so they show what the source says, not what a running campaign did.
30
+
31
+ ## Quick start
32
+
33
+ 1. Install [Node.js](https://nodejs.org/) 22 (22.19 or later) or 24, and keep Hearts of Iron IV installed for vanilla files, artwork and fonts.
34
+ 2. Install the server:
35
+
36
+ ```bash
37
+ npm install --global hoi4-agent-tools
38
+ ```
15
39
 
16
- Add the printed configuration to your MCP client and open your mod as its workspace.
17
- The install is about 280 MiB, because npm fetches the image library's binaries for every platform to keep each install identical.
18
- Keep an installed copy of HOI4 available for vanilla examples, artwork and fonts.
19
- The [setup guide](docs/setup.md) covers connecting your agent and choosing game or mod paths.
40
+ 3. Print the client configuration:
20
41
 
21
- Ask your agent to find a focus tree and render it, locate the installed documentation for a script command, or preview a scripted GUI at different UI scales.
22
- The examples below show the results.
42
+ ```bash
43
+ hoi4-agent-tools-setup --print-client-config
44
+ ```
45
+
46
+ Paste the `globalInstall` block into a JSON client such as Claude Code, Claude Desktop or Cursor, or the `codexTomlGlobal` block into Codex's `config.toml`.
47
+
48
+ 4. Open your mod folder as the agent's workspace and try: "Render this mod's largest focus tree."
49
+
50
+ The [setup guide](docs/setup.md) covers several mods, explicit game paths, local wiki snapshots and troubleshooting with `--discover` and `--diagnose`.
51
+
52
+ [Watch the Agent Tools demo](https://github.com/klimPaskov/Agentic-HOI4-Modding/releases/latest/download/hoi4_agent_tools_promo.mp4) or use [HOI4 Mod Setup](https://github.com/klimPaskov/HOI4-Mod-Setup/releases/latest) to install and register the verified server for your mod.
23
53
 
24
54
  ## Examples
25
55
 
26
- [Focus trees](#focus-trees-and-alternative-prerequisites) · [Technology folders](#technology-folders-and-card-artwork) · [Interfaces](#scripted-interfaces) · [Maps and events](#maps-and-event-chains) · [Local rules and AI](#local-rules-and-ai-weights) · [All tools](#complete-tool-list)
56
+ Each pair shows a capture from the game next to the server's preview of the same source.
57
+
58
+ | In game | Server preview |
59
+ | -------------------------------------------------------------------------------------------------------------------------------------- | -------------------------------------------------------------------------------------------------------------------------------- |
60
+ | [![Focus tree in game](docs/images/comparisons/fury-ingame.png)](docs/images/comparisons/fury-ingame.png) | [![Focus tree preview](docs/images/comparisons/fury-mcp.png)](docs/images/comparisons/fury-mcp.png) |
61
+ | [![Infantry technology folder in game](docs/images/comparisons/infantry-ingame.png)](docs/images/comparisons/infantry-ingame.png) | [![Infantry technology folder preview](docs/images/comparisons/infantry-mcp.png)](docs/images/comparisons/infantry-mcp.png) |
62
+ | [![Video options in game](docs/images/comparisons/gui/options-video-ingame.png)](docs/images/comparisons/gui/options-video-ingame.png) | [![Video options preview](docs/images/comparisons/gui/options-video-mcp.png)](docs/images/comparisons/gui/options-video-mcp.png) |
63
+
64
+ In focus previews, dotted lines mark alternative prerequisites: any one of them unlocks the focus.
65
+ The focus screen in the game has its own framing, labels and icons, and the video options preview has no observed gamma value.
66
+ More comparisons, with their source revisions and fidelity notes, are in the [focus and technology gallery](https://github.com/klimPaskov/hoi4-agent-tools/blob/main/docs/visual-comparisons.md), the [interface gallery](https://github.com/klimPaskov/hoi4-agent-tools/blob/main/docs/gui-comparisons.md) and the [examples guide](docs/examples.md), which also shows map and event renders.
67
+
68
+ ## Tools
69
+
70
+ The default server has 28 tools.
71
+ Agents pick them from ordinary language, so you rarely need their names.
72
+
73
+ | Area | Tools | Writes |
74
+ | --------------------------- | ----------------------------------------------------------------------------------------------------------------------- | ----------------------- |
75
+ | References and source | `reference_context`, `reference_search`, `reference_read`, `source_lookup`, `script_validate`, `error_log`, `mod_index` | — |
76
+ | Focus trees | `focus_inspect`, `focus_render`, `focus_rewrite` | review files; mod files |
77
+ | Scripted GUIs | `gui_inspect`, `gui_render`, `gui_rewrite` | review files; mod files |
78
+ | Maps | `map_inspect`, `map_rewrite` | review files; mod files |
79
+ | Events | `event_inspect`, `event_render` | — |
80
+ | Technology and doctrines | `tech_inspect`, `tech_render` | — |
81
+ | AI weights and timing | `probability_inspect`, `probability_analyze` | — |
82
+ | Decisions, impact and tests | `impact_inspect`, `decision_inspect`, `mechanic_test`, `package_check`, `scenario_test` | — |
83
+ | Background jobs | `job_inspect`, `job_cancel` | job state |
84
+
85
+ Every name starts with `hoi4.`.
86
+ "Review files" are images and reports in the server's own storage; only the three `*_rewrite` tools change mod files.
87
+ The [tool reference](docs/tools.md) gives each tool's purpose, prompts, resources and long-running behaviour.
88
+
89
+ ## Safety and limits
90
+
91
+ - The server reads the mod, its dependencies, the installed game, local reference folders and the game's error log.
92
+ - Inspection and rendering never change mod files.
93
+ The focus, GUI and map rewrite tools validate a proposed edit before writing it and write it as a journaled transaction, so an interrupted write is restored rather than left half-applied.
94
+ - Large renders and reports are stored as linked files, and documentation is returned as cited sections rather than whole manuals.
95
+ - The server does not launch or control the game.
96
+ Previews and source tests cannot prove live clicks, AI choices or engine timing; a source score alone does not establish an AI click probability.
97
+ - Your repository instructions and review process still apply.
98
+
99
+ ## Configuration
100
+
101
+ Started inside a mod folder, the server needs no configuration file.
102
+ `hoi4-agent-tools-setup --init` writes one when you work on several mods or the game is not found automatically.
103
+ For remote or shared use, `hoi4-agent-tools-http` serves the same tools over HTTP with tokens or OAuth.
104
+ See the [configuration reference](docs/configuration.md) and the [HTTP guide](docs/http.md).
105
+
106
+ ## Documentation
107
+
108
+ - [Setup](docs/setup.md) and [configuration](docs/configuration.md)
109
+ - [Examples](docs/examples.md) and [tool reference](docs/tools.md)
110
+ - Guides: [local references](docs/reference.md), [focus trees](docs/focus.md), [scripted GUIs](docs/gui.md), [maps](docs/map.md), [events](docs/events.md), [technology](docs/technology.md), [AI weights and timing](docs/probability.md), [decisions and impact](docs/analysis.md), [mechanic and package tests](docs/mechanics.md)
111
+ - [Background jobs](docs/jobs.md) and [HTTP](docs/http.md)
112
+ - [Development](docs/development.md), [changelog](CHANGELOG.md) and [security policy](SECURITY.md)
113
+ - [Documentation index](docs/README.md)
114
+
115
+ ## Development
116
+
117
+ ```bash
118
+ npm ci
119
+ npm run check
120
+ ```
27
121
 
28
- ### Focus trees and alternative prerequisites
122
+ See the [contributing guide](https://github.com/klimPaskov/hoi4-agent-tools/blob/main/CONTRIBUTING.md) and the [development guide](docs/development.md).
29
123
 
30
- | Focus tree | Supplied in-game capture | MCP source preview |
31
- | ----------- | --------------------------------------------------------------------------------------------------------------------------- | --------------------------------------------------------------------------------------------------------------------- |
32
- | 52 focuses | [![Medium focus tree in game](docs/images/comparisons/fury-ingame.png)](docs/images/comparisons/fury-ingame.png) | [![Medium focus tree preview](docs/images/comparisons/fury-mcp.png)](docs/images/comparisons/fury-mcp.png) |
33
- | 111 focuses | [![Large focus tree in game](docs/images/comparisons/holy-realm-ingame.png)](docs/images/comparisons/holy-realm-ingame.png) | [![Large focus tree preview](docs/images/comparisons/holy-realm-mcp.png)](docs/images/comparisons/holy-realm-mcp.png) |
34
- | 124 focuses | [![Branching focus tree in game](docs/images/comparisons/utopia-ingame.png)](docs/images/comparisons/utopia-ingame.png) | [![Branching focus tree preview](docs/images/comparisons/utopia-mcp.png)](docs/images/comparisons/utopia-mcp.png) |
124
+ ## License
35
125
 
36
- Dotted connectors in the MCP preview mark focuses where either preceding focus satisfies one prerequisite group.
37
- The tree previews show route structure; the game's focus screen has different framing, labels and icons.
38
- The [focus guide](docs/focus.md) explains inspection, rendering and edits, and the [comparison details](docs/visual-comparisons.md#focus-trees) retain source revisions.
39
-
40
- ### Technology folders and card artwork
41
-
42
- > Render a technology folder. Check card sizes, artwork, links and missing placements.
43
-
44
- | Folder | Supplied in-game capture | MCP source preview |
45
- | ---------------- | ------------------------------------------------------------------------------------------------------------------------------------------ | -------------------------------------------------------------------------------------------------------------------------------------------- |
46
- | Vanilla infantry | [![Infantry folder in game](docs/images/comparisons/infantry-ingame.png)](docs/images/comparisons/infantry-ingame.png) | [![Infantry technology folder](docs/images/comparisons/infantry-mcp.png)](docs/images/comparisons/infantry-mcp.png) |
47
- | Mod wide cards | [![Mod technology folder in game](docs/images/comparisons/chemical-recent-ingame.png)](docs/images/comparisons/chemical-recent-ingame.png) | [![Mod technology folder preview](docs/images/comparisons/chemical-historical-mcp.png)](docs/images/comparisons/chemical-historical-mcp.png) |
48
-
49
- The mod folder preview uses the source revision recorded with its screenshot and includes wide equipment cards.
50
- Armored-car artwork that installed DLC folders provide appears in the infantry preview.
51
- The [technology comparison](docs/visual-comparisons.md#technology-folders) records its source revision, and the [technology guide](docs/technology.md) covers inspection and doctrine paths.
52
-
53
- ### Scripted interfaces
54
-
55
- > Preview an interface with its game assets and fonts. Check states, text clipping and clickable areas at 100% and 125% UI scale.
56
-
57
- | Interface | Supplied in-game capture | MCP source preview |
58
- | ---------------------- | ----------------------------------------------------------------------------------------------------------------------------------------- | ----------------------------------------------------------------------------------------------------------------------------------- |
59
- | Vanilla video options | [![Options in game](docs/images/comparisons/gui/options-video-ingame.png)](docs/images/comparisons/gui/options-video-ingame.png) | [![Options preview](docs/images/comparisons/gui/options-video-mcp.png)](docs/images/comparisons/gui/options-video-mcp.png) |
60
- | Vanilla priority panel | [![Priority panel in game](docs/images/comparisons/gui/skoda-priority-ingame.png)](docs/images/comparisons/gui/skoda-priority-ingame.png) | [![Priority panel preview](docs/images/comparisons/gui/skoda-priority-mcp.png)](docs/images/comparisons/gui/skoda-priority-mcp.png) |
61
- | Mod management window | [![Management window in game](docs/images/comparisons/gui/tag-manager-ingame.png)](docs/images/comparisons/gui/tag-manager-ingame.png) | [![Management window preview](docs/images/comparisons/gui/tag-manager-mcp.png)](docs/images/comparisons/gui/tag-manager-mcp.png) |
62
-
63
- The management window capture comes from an older layout.
64
- The video options preview has no observed gamma value, and the priority panel's capture frames its background differently.
65
-
66
- | Mod event log | Mod status panel | Mod status panel, second tab |
67
- | -------------------------------------------------------------------------------------------------------------------- | --------------------------------------------------------------------------------------------------------------------------------------- | --------------------------------------------------------------------------------------------------------------------------------------- |
68
- | [![Event Log preview](docs/images/comparisons/gui/event-log-mcp.png)](docs/images/comparisons/gui/event-log-mcp.png) | [![Chaos Meter status](docs/images/comparisons/gui/chaos-meter-status-mcp.png)](docs/images/comparisons/gui/chaos-meter-status-mcp.png) | [![Chaos Meter deaths](docs/images/comparisons/gui/chaos-meter-deaths-mcp.png)](docs/images/comparisons/gui/chaos-meter-deaths-mcp.png) |
69
-
70
- | Vanilla decisions | Vanilla occupation |
71
- | -------------------------------------------------------------------------------------------------------------------------------------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------- |
72
- | [![Decision window](docs/images/comparisons/native-ui/countrydecisionview-window.png)](docs/images/comparisons/native-ui/countrydecisionview-window.png) | [![Occupation window](docs/images/comparisons/native-ui/countryoccupationview-window.png)](docs/images/comparisons/native-ui/countryoccupationview-window.png) |
73
-
74
- The event log, status panel, decision and occupation previews use declared states or positions for layout review.
75
- They are source previews, not observations of a running campaign.
76
- See the [interface gallery](docs/gui-comparisons.md) for full images and fidelity notes, and the [GUI guide](docs/gui.md) for scenario inputs.
77
-
78
- ### Maps and event chains
79
-
80
- > Find Brandenburg on the map, inspect its provinces and neighbours, and show the affected source files before a change.
81
-
82
- > Trace an event's options and follow-up events. Point out unresolved calls and link each route to its source.
83
-
84
- | Source map | Mod event chain |
85
- | ------------------------------------------------------------------------------------------------------------------------------- | -------------------------------------------------------------------------------------------------------------------------------------- |
86
- | [![Map rendered from installed source](docs/images/comparisons/source/map-mcp.png)](docs/images/comparisons/source/map-mcp.png) | [![Chaos Redux event options](docs/images/comparisons/source/event-chain-mcp.png)](docs/images/comparisons/source/event-chain-mcp.png) |
87
-
88
- The [map guide](docs/map.md) covers connected province, state, supply and railway data.
89
- The [event guide](docs/events.md) covers routes, scope, timing and unresolved references.
90
-
91
- ### Local rules and AI weights
92
-
93
- > Find the installed documentation for `save_event_target_as`, read the relevant section, and show a vanilla usage with file and line references.
94
-
95
- > Compare this decision's `ai_will_do` score before and after a change in peace and war. List missing conditions separately from known results.
96
-
97
- The [reference example](docs/research/reference-benchmark.md) found the installed effect documentation first and read its relevant 12-line section instead of loading whole wiki pages.
98
- The [AI guide](docs/probability.md) covers supported weights, chance and timing models; a source score alone does not establish an AI click probability.
99
- The [examples guide](docs/examples.md) has more prompt details.
100
-
101
- ## Complete tool list
102
-
103
- The default server exposes 35 tools.
104
- Your agent can select them from ordinary language; use the live tool schema for call parameters.
105
-
106
- | Tool | Purpose |
107
- | --------------------------- | ---------------------------------------------------------------------------------------------------------------- |
108
- | `hoi4.focus_inspect` | Read focus trees, continuous-focus placement, and structural or reference problems. |
109
- | `hoi4.focus_render` | Produce fast HTML, SVG, JSON, and source-linked layout artifacts. |
110
- | `hoi4.focus_raster` | Produce a PNG preview with decoded source icons. |
111
- | `hoi4.focus_rewrite` | Create or update a focus tree. |
112
- | `hoi4.gui_inspect` | Read a scripted GUI and its linked assets and logic. |
113
- | `hoi4.gui_render` | Render generated and explicit GUI scenarios, states, resolutions, and layout diagnostics. |
114
- | `hoi4.gui_rewrite` | Create or update a GUI source package. |
115
- | `hoi4.map_inspect` | Search, click, navigate, and inspect the complete rendered map and its linked data. |
116
- | `hoi4.map_render` | Render full-map layers, overlays, names, IDs, coordinates, and source-linked catalogs. |
117
- | `hoi4.map_rewrite` | Create or update states, provinces, IDs, networks, positions, and connected map data. |
118
- | `hoi4.reference_context` | Get compact, cited wiki and installed documentation pointers for a modding surface. |
119
- | `hoi4.reference_search` | Search local documentation in plain words or script names; each result names its answering line. |
120
- | `hoi4.reference_read` | Read one revision-bound section, with line continuation. |
121
- | `hoi4.source_lookup` | Find exact definitions, overrides and usages across game, DLC and mod, or the definition containing a file line. |
122
- | `hoi4.script_validate` | Check a snippet or a whole mod file for syntax, command kinds, and scopes against local documentation. |
123
- | `hoi4.event_inspect` | Scan, trace, explain, lint, or assess event chains and their state flow. |
124
- | `hoi4.event_render` | Render source-linked event routes, options, timing, state, scope, and unresolved edges. |
125
- | `hoi4.event_compare` | Compare event-chain topology and diagnostics between revisions. |
126
- | `hoi4.impact_inspect` | Trace symbol and changed-file consumers across source systems and compare proposals. |
127
- | `hoi4.decision_inspect` | Inventory and evaluate decisions or missions under declared scenarios and source changes. |
128
- | `hoi4.mechanic_test` | Execute bounded source effects on a copied declared scenario and check assertions. |
129
- | `hoi4.package_check` | Check declarative package definitions, calls, registrations, assets, and case links. |
130
- | `hoi4.scenario_test` | Run named source and domain cases in resumable, revision-bound batches. |
131
- | `hoi4.job_inspect` | Inspect durable background work or retrieve its completed tool result. |
132
- | `hoi4.job_cancel` | Durably request cancellation of authorized background work. |
133
- | `hoi4.tech_inspect` | Scan, trace, explain, lint, and assess technology and doctrine systems. |
134
- | `hoi4.tech_render` | Render source layouts with real item sizes and year guides, plus dependencies and assets. |
135
- | `hoi4.tech_compare` | Compare technology graphs, placements, references, diagnostics, and source overlays. |
136
- | `hoi4.probability_inspect` | Locate weighted logic and discover compatible adapters, candidates, and required inputs. |
137
- | `hoi4.probability_evaluate` | Evaluate supported weights, probability and timing models, and missing inputs. |
138
- | `hoi4.probability_sweep` | Find sensitivity, breakpoints, cliffs, and rank reversals across declared ranges. |
139
- | `hoi4.probability_simulate` | Run deterministic sampled analysis with confidence and convergence data. |
140
- | `hoi4.probability_sequence` | Analyze declared recovery, caps, cooldowns, resets, timers, and terminal states. |
141
- | `hoi4.probability_compare` | Attribute AI-weight and MTTH changes between real or proposed source. |
142
- | `hoi4.probability_render` | Render cached rankings, matrices, timing, sensitivity, sequence, and comparisons. |
143
-
144
- Set `HOI4_AGENT_TOOLS_CHAOSX=1` to expose two optional Chaos Redux workflow tools: `chaosx.focus_country_assets` and `chaosx.visual_revision`.
145
- The [tool guide](docs/tools.md) explains results, linked artifacts and long operations.
146
-
147
- ## How it fits your workflow
148
-
149
- The server works through your coding agent and follows the mod workspace you provide.
150
- It keeps large renders and reports in linked files, and retrieves relevant documentation sections instead of whole manuals.
151
- Your repository instructions and review process still apply.
152
-
153
- Inspection and rendering do not edit the mod.
154
- The focus, GUI and map rewrite tools can change source files after checking the proposed edit.
155
- The server does not launch or control the game; previews and source tests cannot prove live clicks, AI choices or engine timing.
156
-
157
- [Documentation](docs/README.md) · [Tool reference](docs/tools.md) · [Contributing](CONTRIBUTING.md) · [Security](SECURITY.md)
158
-
159
- Apache-2.0 licensed.
160
- Hearts of Iron IV artwork belongs to its respective owners; this project is unaffiliated with Paradox Interactive.
126
+ Apache-2.0; see [LICENSE](LICENSE) and the [third-party notices](docs/third-party-notices.md).
127
+ Hearts of Iron IV artwork belongs to Paradox Interactive; this project is unaffiliated with Paradox Interactive.
128
+ The in-game captures were supplied for these comparisons.
package/dist/bin/http.js CHANGED
@@ -1,11 +1,13 @@
1
1
  #!/usr/bin/env node
2
2
  import { canonicalJson } from '../hoi4_agent_tools/core/canonical.js';
3
+ import { ServerRegistry } from '../hoi4_agent_tools/core/server-registry.js';
3
4
  import { createMcpServer } from '../hoi4_agent_tools/mcp/server/create.js';
4
5
  import { startHttpServer } from '../hoi4_agent_tools/mcp/transports/http.js';
5
6
  import { createEngine } from '../hoi4_agent_tools/runtime.js';
6
7
  async function main() {
7
8
  const engine = await createEngine();
8
9
  const handle = await startHttpServer(engine, engine.resolver.config(), createMcpServer);
10
+ new ServerRegistry(engine.resolver, 'http').start();
9
11
  const shutdown = async () => {
10
12
  await handle.close();
11
13
  process.exit(0);
@@ -21,6 +23,16 @@ main().catch((error) => {
21
23
  ? String(error.code)
22
24
  : 'INTERNAL_ERROR',
23
25
  message: error instanceof Error ? error.message : String(error),
26
+ // Startup output goes to the operator's own log; the cause (such as the JSON parse
27
+ // position in a configuration file) is what makes the failure fixable.
28
+ ...(typeof error === 'object' &&
29
+ error !== null &&
30
+ 'details' in error &&
31
+ typeof error.details === 'object' &&
32
+ error.details !== null &&
33
+ Object.keys(error.details).length > 0
34
+ ? { details: error.details }
35
+ : {}),
24
36
  })}\n`);
25
37
  process.exitCode = 1;
26
38
  });
package/dist/bin/setup.js CHANGED
@@ -226,8 +226,9 @@ function printClientConfig(configPath) {
226
226
  ...(useDefaultConfiguration ? {} : { env: { HOI4_AGENT_CONFIG: absolute } }),
227
227
  };
228
228
  // Codex keeps a server per subagent connected after the subagent finishes, so its servers
229
- // exit after half an hour without traffic instead of accumulating.
230
- const codexEnv = `\nenv = { ${useDefaultConfiguration ? '' : `HOI4_AGENT_CONFIG = ${JSON.stringify(absolute)}, `}HOI4_AGENT_STDIO_IDLE_EXIT_MINUTES = "30" }`;
229
+ // exit after half an hour without traffic instead of accumulating. The first scan of a large
230
+ // mod and long renders need more than Codex's default startup and tool-call timeouts.
231
+ const codexEnv = `\nstartup_timeout_sec = 120\ntool_timeout_sec = 600\nenv = { ${useDefaultConfiguration ? '' : `HOI4_AGENT_CONFIG = ${JSON.stringify(absolute)}, `}HOI4_AGENT_STDIO_IDLE_EXIT_MINUTES = "30" }`;
231
232
  const npxToml = `[mcp_servers.hoi4_agent_tools]\ncommand = "${command}"\nargs = ["-y", "hoi4-agent-tools@${PACKAGE_VERSION}"]${codexEnv}`;
232
233
  const globalToml = `[mcp_servers.hoi4_agent_tools]\ncommand = "${installedCommand}"${codexEnv}`;
233
234
  process.stdout.write(`${JSON.stringify({
package/dist/bin/stdio.js CHANGED
@@ -2,6 +2,7 @@
2
2
  import { canonicalJson } from '../hoi4_agent_tools/core/canonical.js';
3
3
  import { StdioFrameLimitError, StdioInvalidMessageError, StdioInvalidUtf8Error, } from '../hoi4_agent_tools/mcp/transports/bounded-stdio.js';
4
4
  import { serveNegotiatedStdio } from '../hoi4_agent_tools/mcp/transports/negotiated-stdio.js';
5
+ import { ServerRegistry } from '../hoi4_agent_tools/core/server-registry.js';
5
6
  import { StdioLifetime } from '../hoi4_agent_tools/mcp/transports/stdio-lifetime.js';
6
7
  import { createEngine } from '../hoi4_agent_tools/runtime.js';
7
8
  /**
@@ -52,6 +53,16 @@ async function main() {
52
53
  level: 'error',
53
54
  event: 'transport_startup_failed',
54
55
  message: error instanceof Error ? error.message : String(error),
56
+ // Startup output goes to the operator's own log; the cause (such as the JSON parse
57
+ // position in a configuration file) is what makes the failure fixable.
58
+ ...(typeof error === 'object' &&
59
+ error !== null &&
60
+ 'details' in error &&
61
+ typeof error.details === 'object' &&
62
+ error.details !== null &&
63
+ Object.keys(error.details).length > 0
64
+ ? { details: error.details }
65
+ : {}),
55
66
  })}\n`);
56
67
  },
57
68
  ...(chaosxTools === undefined
@@ -63,6 +74,7 @@ async function main() {
63
74
  });
64
75
  closeTransport = () => transport.close();
65
76
  lifetime.start();
77
+ new ServerRegistry(engine.resolver, 'stdio', () => lifetime.lastActivity()).start();
66
78
  }
67
79
  main().catch((error) => {
68
80
  process.stderr.write(`${canonicalJson({
@@ -201,6 +201,14 @@ const artifactTemporaryPrefix = '.artifact-tmp-';
201
201
  const ownedArtifactContent = Symbol('ownedArtifactContent');
202
202
  const precomputedArtifactSha256 = Symbol('precomputedArtifactSha256');
203
203
  export const chunkedArtifactIndexMimeType = 'application/json';
204
+ /** The chunked logical artifact a chunk or index manifest belongs to, and its role in it. */
205
+ function chunkMembership(manifest) {
206
+ const chunked = manifest.provenance.metadata?.chunkedArtifact;
207
+ if (typeof chunked?.originalSha256 !== 'string' ||
208
+ (chunked.role !== 'chunk' && chunked.role !== 'index'))
209
+ return undefined;
210
+ return { group: chunked.originalSha256, role: chunked.role };
211
+ }
204
212
  function isValidArtifactName(name) {
205
213
  return (safeNamePattern.test(name) &&
206
214
  isPortablePathSegment(name) &&
@@ -342,7 +350,12 @@ async function withArtifactQueue(root, action, signal) {
342
350
  });
343
351
  }
344
352
  }
345
- async function artifactUsage(root, signal) {
353
+ /**
354
+ * Measure artifact storage. With `cleanup`, also remove aged temporary files and empty
355
+ * folders; only the serialized write path may do that, since a listing running beside a
356
+ * write could remove the folder a new artifact is about to be written into.
357
+ */
358
+ async function artifactUsage(root, signal, cleanup = false) {
346
359
  let bytes = 0;
347
360
  let entries = 0;
348
361
  const canonicalRoot = await containedGeneratedPath(root);
@@ -388,7 +401,7 @@ async function artifactUsage(root, signal) {
388
401
  const metadata = await lstat(temporary);
389
402
  if (metadata.isSymbolicLink())
390
403
  throw new ServiceError('ARTIFACT_STORAGE_UNSAFE', 'Artifact storage contains a symbolic link or junction');
391
- if (Date.now() - metadata.mtimeMs >= artifactDebrisMinimumAgeMs)
404
+ if (cleanup && Date.now() - metadata.mtimeMs >= artifactDebrisMinimumAgeMs)
392
405
  await unlink(temporary);
393
406
  }
394
407
  catch (error) {
@@ -420,7 +433,7 @@ async function artifactUsage(root, signal) {
420
433
  }
421
434
  }
422
435
  }
423
- if (directory !== canonicalRoot) {
436
+ if (cleanup && directory !== canonicalRoot) {
424
437
  try {
425
438
  await rmdir(directory);
426
439
  }
@@ -883,8 +896,27 @@ export class ArtifactStore {
883
896
  }
884
897
  };
885
898
  await reclaimDebris(await containedGeneratedPath(workspace.artifactRoot));
899
+ // A chunked artifact's pieces are written before its index, so they are always older. Age
900
+ // a group by its newest member and evict its index first, so readers never follow an index
901
+ // to evicted pieces, and protect the whole group when any member is protected.
902
+ const groupAge = new Map();
903
+ const protectedGroups = new Set();
904
+ for (const entry of retained) {
905
+ const membership = chunkMembership(entry.manifest);
906
+ if (membership === undefined)
907
+ continue;
908
+ groupAge.set(membership.group, Math.max(groupAge.get(membership.group) ?? 0, entry.modifiedAt));
909
+ if (protectedManifests.has(entry.manifestPath) || protectedTargets.has(entry.targetPath))
910
+ protectedGroups.add(membership.group);
911
+ }
912
+ const evictionAge = (entry) => {
913
+ const membership = chunkMembership(entry.manifest);
914
+ return membership === undefined ? entry.modifiedAt : groupAge.get(membership.group);
915
+ };
916
+ const indexFirst = (entry) => chunkMembership(entry.manifest)?.role === 'chunk' ? 1 : 0;
886
917
  retained.sort((left, right) => Number(right.staleIdentity) - Number(left.staleIdentity) ||
887
- left.modifiedAt - right.modifiedAt ||
918
+ evictionAge(left) - evictionAge(right) ||
919
+ indexFirst(left) - indexFirst(right) ||
888
920
  compareCodeUnits(left.manifestPath, right.manifestPath));
889
921
  const current = { ...usage };
890
922
  for (const candidate of retained) {
@@ -893,6 +925,9 @@ export class ArtifactStore {
893
925
  break;
894
926
  if (protectedManifests.has(candidate.manifestPath))
895
927
  continue;
928
+ const membership = chunkMembership(candidate.manifest);
929
+ if (membership !== undefined && protectedGroups.has(membership.group))
930
+ continue;
896
931
  try {
897
932
  await unlink(candidate.manifestPath);
898
933
  }
@@ -1366,7 +1401,7 @@ export class ArtifactStore {
1366
1401
  if (!Number.isSafeInteger(additionalBytes)) {
1367
1402
  throw new ServiceError('ARTIFACT_STORAGE_LIMIT', 'Artifact batch size is unsafe');
1368
1403
  }
1369
- const usage = await artifactUsage(workspace.artifactRoot, signal);
1404
+ const usage = await artifactUsage(workspace.artifactRoot, signal, true);
1370
1405
  const additionalEntries = [...uniqueManifests.values()].filter((artifact) => !artifact.exists).length;
1371
1406
  await this.pruneForAdmission(workspace, usage, additionalBytes, additionalEntries, new Set(uniqueManifests.keys()), new Set(uniqueTargets.keys()), signal);
1372
1407
  const createdTargets = [];