hoi4-agent-tools 3.10.0 → 4.0.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +131 -0
- package/README.md +91 -147
- package/dist/bin/http.js +10 -0
- package/dist/bin/setup.js +3 -2
- package/dist/bin/stdio.js +10 -0
- package/dist/hoi4_agent_tools/core/artifacts.js +40 -5
- package/dist/hoi4_agent_tools/core/canonical.js +18 -4
- package/dist/hoi4_agent_tools/core/condition-evaluator.js +18 -0
- package/dist/hoi4_agent_tools/core/configuration.js +7 -0
- package/dist/hoi4_agent_tools/core/domain-scan-patterns.js +12 -0
- package/dist/hoi4_agent_tools/core/domain-tools.js +65 -0
- package/dist/hoi4_agent_tools/core/domain-validation.js +5 -2
- package/dist/hoi4_agent_tools/core/engine.js +29 -2
- package/dist/hoi4_agent_tools/core/index.js +2 -2
- package/dist/hoi4_agent_tools/core/job-executor.js +14 -1
- package/dist/hoi4_agent_tools/core/job-operation-registration.js +15 -7
- package/dist/hoi4_agent_tools/core/job-store.js +78 -5
- package/dist/hoi4_agent_tools/core/job-transactions.js +31 -2
- package/dist/hoi4_agent_tools/core/job-worker-host.js +314 -127
- package/dist/hoi4_agent_tools/core/job-worker.js +96 -37
- package/dist/hoi4_agent_tools/core/operation-result.js +123 -10
- package/dist/hoi4_agent_tools/core/operation-tasks.js +49 -89
- package/dist/hoi4_agent_tools/core/persistent-analysis-cache.js +25 -21
- package/dist/hoi4_agent_tools/core/server-registry.js +22 -5
- package/dist/hoi4_agent_tools/core/shared-request-capacity.js +26 -1
- package/dist/hoi4_agent_tools/core/source/cache.js +20 -10
- package/dist/hoi4_agent_tools/core/source/lexer.js +11 -3
- package/dist/hoi4_agent_tools/core/temporary-directories.js +293 -0
- package/dist/hoi4_agent_tools/core/transactions.js +114 -23
- package/dist/hoi4_agent_tools/core/worker-exit.js +80 -0
- package/dist/hoi4_agent_tools/core/workspace.js +84 -8
- package/dist/hoi4_agent_tools/decision/ai.js +1 -1
- package/dist/hoi4_agent_tools/decision/service.js +28 -0
- package/dist/hoi4_agent_tools/decision/source-inventory.js +7 -5
- package/dist/hoi4_agent_tools/event/job-operations.js +9 -5
- package/dist/hoi4_agent_tools/event/operations.js +14 -1
- package/dist/hoi4_agent_tools/focus/job-operations.js +1 -2
- package/dist/hoi4_agent_tools/focus/tool-operations.js +1 -1
- package/dist/hoi4_agent_tools/gui/assets.js +3 -0
- package/dist/hoi4_agent_tools/gui/dds.js +8 -4
- package/dist/hoi4_agent_tools/gui/layout.js +45 -5
- package/dist/hoi4_agent_tools/gui/native-state.js +244 -0
- package/dist/hoi4_agent_tools/gui/renderer.js +12 -7
- package/dist/hoi4_agent_tools/gui/source-graph.js +17 -4
- package/dist/hoi4_agent_tools/gui/studio.js +33 -21
- package/dist/hoi4_agent_tools/gui/validators.js +8 -6
- package/dist/hoi4_agent_tools/map/bmp.js +1 -1
- package/dist/hoi4_agent_tools/map/derived.js +748 -0
- package/dist/hoi4_agent_tools/map/job-operations.js +7 -3
- package/dist/hoi4_agent_tools/map/model.js +103 -0
- package/dist/hoi4_agent_tools/map/operations.js +427 -58
- package/dist/hoi4_agent_tools/map/references.js +483 -0
- package/dist/hoi4_agent_tools/map/service.js +136 -61
- package/dist/hoi4_agent_tools/map/tool-operations.js +2 -1
- package/dist/hoi4_agent_tools/map/validation.js +3 -0
- package/dist/hoi4_agent_tools/map/world.js +1280 -0
- package/dist/hoi4_agent_tools/mcp/prompts/probability.js +2 -2
- package/dist/hoi4_agent_tools/mcp/server/argument-errors.js +72 -0
- package/dist/hoi4_agent_tools/mcp/server/create-modern-operations.js +23 -5
- package/dist/hoi4_agent_tools/mcp/server/create.js +7 -0
- package/dist/hoi4_agent_tools/mcp/server/instructions.js +1 -1
- package/dist/hoi4_agent_tools/mcp/server/request-lifecycle.js +24 -30
- package/dist/hoi4_agent_tools/mcp/server/tool-listing.js +45 -0
- package/dist/hoi4_agent_tools/mcp/tools/analysis.js +28 -8
- package/dist/hoi4_agent_tools/mcp/tools/event.js +19 -30
- package/dist/hoi4_agent_tools/mcp/tools/focus.js +5 -13
- package/dist/hoi4_agent_tools/mcp/tools/gui.js +6 -6
- package/dist/hoi4_agent_tools/mcp/tools/job.js +4 -4
- package/dist/hoi4_agent_tools/mcp/tools/map.js +15 -18
- package/dist/hoi4_agent_tools/mcp/tools/probability.js +42 -48
- package/dist/hoi4_agent_tools/mcp/tools/reference.js +26 -9
- package/dist/hoi4_agent_tools/mcp/tools/technology.js +17 -30
- package/dist/hoi4_agent_tools/mcp/transports/http.js +28 -4
- package/dist/hoi4_agent_tools/mcp/transports/stdio-lifetime.js +31 -8
- package/dist/hoi4_agent_tools/probability/job-operations.js +4 -9
- package/dist/hoi4_agent_tools/probability/operations.js +175 -13
- package/dist/hoi4_agent_tools/probability/source-analysis.js +24 -1
- package/dist/hoi4_agent_tools/reference/error-log.js +359 -0
- package/dist/hoi4_agent_tools/reference/known-mistakes.js +307 -0
- package/dist/hoi4_agent_tools/reference/known-mistakes.json +154 -0
- package/dist/hoi4_agent_tools/reference/mod-index.js +101 -0
- package/dist/hoi4_agent_tools/reference/operations.js +88 -19
- package/dist/hoi4_agent_tools/reference/player-text.js +4 -3
- package/dist/hoi4_agent_tools/reference/script-validation.js +19 -1
- package/dist/hoi4_agent_tools/reference/service.js +6 -0
- package/dist/hoi4_agent_tools/runtime.js +14 -1
- package/dist/hoi4_agent_tools/schemas/event.js +78 -19
- package/dist/hoi4_agent_tools/schemas/focus-requests.js +10 -0
- package/dist/hoi4_agent_tools/schemas/lenient-arguments.js +266 -0
- package/dist/hoi4_agent_tools/schemas/map-requests.js +63 -20
- package/dist/hoi4_agent_tools/schemas/map.js +122 -3
- package/dist/hoi4_agent_tools/schemas/mod-tools.js +181 -0
- package/dist/hoi4_agent_tools/schemas/probability-requests.js +119 -9
- package/dist/hoi4_agent_tools/schemas/reference.js +13 -0
- package/dist/hoi4_agent_tools/schemas/scenarios.js +1 -3
- package/dist/hoi4_agent_tools/schemas/script-validation.js +13 -6
- package/dist/hoi4_agent_tools/schemas/technology.js +79 -21
- package/dist/hoi4_agent_tools/technology/job-operations.js +3 -4
- package/dist/hoi4_agent_tools/technology/operations.js +14 -1
- package/dist/hoi4_agent_tools/version.js +1 -1
- package/docs/README.md +7 -4
- package/docs/analysis.md +15 -2
- package/docs/configuration.md +281 -0
- package/docs/development.md +26 -2
- package/docs/events.md +29 -6
- package/docs/examples.md +13 -28
- package/docs/focus.md +127 -5
- package/docs/gui.md +105 -21
- package/docs/helper-expansion.md +9 -9
- package/docs/http.md +3 -1
- package/docs/jobs.md +23 -14
- package/docs/map.md +199 -7
- package/docs/mechanics.md +6 -2
- package/docs/probability.md +46 -16
- package/docs/reference.md +73 -5
- package/docs/setup.md +45 -14
- package/docs/technology.md +28 -4
- package/docs/third-party-notices.md +11 -0
- package/docs/tools.md +150 -42
- package/docs/troubleshooting.md +61 -0
- package/examples/clients/codex-config.toml +5 -2
- package/examples/clients/generic.json +2 -2
- package/examples/config/config.json +7 -0
- package/npm-shrinkwrap.json +151 -156
- package/package.json +13 -8
- package/schemas/configuration.schema.json +144 -128
- package/schemas/continuous-focus-palette.schema.json +1 -1
- package/schemas/custom-weighted-pool.schema.json +1 -1
- package/schemas/decision-inspect-input.schema.json +1 -1
- package/schemas/error-log-input.schema.json +55 -0
- package/schemas/event-feature-manifest.schema.json +1 -1
- package/schemas/focus-plan.schema.json +1 -1
- package/schemas/focus-planning-sidecar.schema.json +1 -1
- package/schemas/gui-animation-source.schema.json +1 -1
- package/schemas/gui-helper.schema.json +1 -1
- package/schemas/gui-scenario.schema.json +1 -1
- package/schemas/helper-expansion-request.schema.json +1 -1
- package/schemas/helper-expansion-summary.schema.json +1 -1
- package/schemas/impact-inspect-input.schema.json +1 -1
- package/schemas/map-operation.schema.json +597 -126
- package/schemas/mechanic-test-input.schema.json +1 -1
- package/schemas/mod-index-input.schema.json +51 -0
- package/schemas/operation-result.schema.json +2 -2
- package/schemas/package-check-input.schema.json +1 -1
- package/schemas/package-manifest.schema.json +1 -1
- package/schemas/probability-analysis-result.schema.json +1 -1
- package/schemas/probability-compare-input.schema.json +1 -1
- package/schemas/probability-evaluate-input.schema.json +1 -1
- package/schemas/probability-inspect-input.schema.json +1 -1
- package/schemas/probability-render-input.schema.json +1 -1
- package/schemas/probability-scenario-set.schema.json +1 -1
- package/schemas/probability-sequence-input.schema.json +1 -1
- package/schemas/probability-simulate-input.schema.json +1 -1
- package/schemas/probability-sweep-input.schema.json +1 -1
- package/schemas/reference-context-input.schema.json +1 -1
- package/schemas/reference-read-input.schema.json +1 -1
- package/schemas/reference-search-input.schema.json +1 -1
- package/schemas/scenario-suite.schema.json +3 -5
- package/schemas/scenario-test-input.schema.json +3 -5
- package/schemas/script-validate-input.schema.json +1 -1
- package/schemas/shared-scenario.schema.json +1 -1
- package/schemas/source-lookup-input.schema.json +1 -1
- package/server.json +3 -3
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,136 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
## Unreleased
|
|
4
|
+
|
|
5
|
+
## 4.0.1 - 2026-10-12
|
|
6
|
+
|
|
7
|
+
- Clean temporary test fixtures after each test, suite teardown and normal process exit. Reject fixture truncation above a 256 MiB aggregate disk budget before Windows allocates the file.
|
|
8
|
+
- Recover stale reference-source and random-name event-evaluation scratch on startup after three hours, with local process leases, lock and canonical-path checks. Evict dead owners oldest first under a 256 MiB scratch cap; preserve live owners and dated benchmark evidence.
|
|
9
|
+
- Document the leak's test-fixture origin. MCP reference lookup already reads configured sources directly and uses the shared persistent analysis cache; it does not copy a source tree per call or process.
|
|
10
|
+
- Describe modding tasks in plain language across the README, guides, package metadata and MCP tool descriptions.
|
|
11
|
+
|
|
12
|
+
### GUI render
|
|
13
|
+
|
|
14
|
+
- Decode uncompressed 16-bit RGB DDS portraits, including the 5:5:5 format used by vanilla leaders; truncated pixel data remains unsupported.
|
|
15
|
+
- Preserve declared font colours when a same-name bitmap atlas is loaded, including the dark super-event description font. Atlas metadata no longer outranks a named font declaration, and source links retain that declaration.
|
|
16
|
+
- `hoi4.gui_render` and `hoi4.gui_inspect` model the engine-controlled branches of `countrypoliticsview` instead of drawing all of them: no faction, faction leader, faction member and balance of power are chosen from the scenario country (`tag`, `ideology`, `faction`, `balanceOfPower`, or its `history/countries` facts at the scenario date), and `pol_faction_icon` follows the ruling ideology instead of its static frame. Explicit scenario visibility, values and selected frames still win.
|
|
17
|
+
- GUI text keys are matched without regard to case, so a window that spells `buttontext` in lower case (the vanilla trade window) shows its localised label instead of the key.
|
|
18
|
+
- Element visibility honours `show` as well as `visible`, `hide` and `hidden`, and scenario `name.visible` values may be yes/no words or 1/0 as well as booleans.
|
|
19
|
+
|
|
20
|
+
### Job workers
|
|
21
|
+
|
|
22
|
+
- Uncaught worker failures log only a bounded diagnostic code; exception messages, stacks and thrown values are excluded to protect source text and credentials.
|
|
23
|
+
- A worker that stops without a result is now reported by its real cause. The host keeps each worker's exit code, signal and last standard error and fails the job with `JOB_WORKER_EXIT` naming a V8 heap limit (with its size), a native out-of-memory, a native crash, an external termination, a stop by the server's own deadline, or an uncaught job error with its error code. Earlier releases discarded this and always suggested that memory ran out. Logs of workers that ended unexpectedly are kept, newest ten, in `job-workers/logs` under the server state root.
|
|
24
|
+
- Workers start with a V8 heap ceiling of a quarter of physical memory, between 2,048 and 8,192 MiB, when `jobWorkerMaxHeapMiB` is not set. Node's own default tops out near 4.5 GB, which a large GUI render on a big mod can approach.
|
|
25
|
+
- `hoi4.gui_render` rasterizes its derived variants, the comparison renders and the galleries one at a time instead of together, which lowers the peak native memory of a render.
|
|
26
|
+
|
|
27
|
+
## 4.0.0 - 2026-10-10
|
|
28
|
+
|
|
29
|
+
### Known mistakes
|
|
30
|
+
|
|
31
|
+
- 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.
|
|
32
|
+
- `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.
|
|
33
|
+
|
|
34
|
+
### Maps
|
|
35
|
+
|
|
36
|
+
- `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.
|
|
37
|
+
- `merge_states`, `create_state` and `split_state` accept `remapReferences` (`refuse` or `override`) to rewrite the scripts that named the state in the same plan.
|
|
38
|
+
- 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`.
|
|
39
|
+
- `MAP_COUNTRY_CAPITAL_NOT_OWNED` is checked only in `history/countries`.
|
|
40
|
+
|
|
41
|
+
### Tools
|
|
42
|
+
|
|
43
|
+
- 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.
|
|
44
|
+
|
|
45
|
+
### Workers
|
|
46
|
+
|
|
47
|
+
- 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.
|
|
48
|
+
|
|
49
|
+
### Documentation
|
|
50
|
+
|
|
51
|
+
- 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.
|
|
52
|
+
|
|
53
|
+
### Breaking changes
|
|
54
|
+
|
|
55
|
+
- 37 tools become 28, one inspect tool per domain:
|
|
56
|
+
- `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`.
|
|
57
|
+
- `hoi4.event_compare` and `hoi4.tech_compare` become `mode: compare` of `hoi4.event_inspect` and `hoi4.tech_inspect`.
|
|
58
|
+
- `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.
|
|
59
|
+
- `hoi4.map_render` is folded into `hoi4.map_inspect`: a `layer`, `overlays`, `scale`, `tile` or `area` renders that view.
|
|
60
|
+
- Inline results list at most 12 scanned files, mod files first.
|
|
61
|
+
|
|
62
|
+
- 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.
|
|
63
|
+
- 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.
|
|
64
|
+
- 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.
|
|
65
|
+
- 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`.
|
|
66
|
+
- `tools/list` omits the JSON Schema dialect and the safe-integer bounds that every integer field repeated; field types, ranges and descriptions are unchanged.
|
|
67
|
+
|
|
68
|
+
### Agent ergonomics
|
|
69
|
+
|
|
70
|
+
- 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.
|
|
71
|
+
- 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.
|
|
72
|
+
- 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.
|
|
73
|
+
- 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.
|
|
74
|
+
- 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.
|
|
75
|
+
- 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.
|
|
76
|
+
- 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.
|
|
77
|
+
- 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.
|
|
78
|
+
- `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.
|
|
79
|
+
- 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.
|
|
80
|
+
|
|
81
|
+
### Speed
|
|
82
|
+
|
|
83
|
+
- 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.
|
|
84
|
+
- 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.
|
|
85
|
+
- 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.
|
|
86
|
+
|
|
87
|
+
### Maps
|
|
88
|
+
|
|
89
|
+
- 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.
|
|
90
|
+
- 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).
|
|
91
|
+
- 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.
|
|
92
|
+
- 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.
|
|
93
|
+
- 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.
|
|
94
|
+
- 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.
|
|
95
|
+
- Name transaction diff artifacts safely for files with spaces in their names.
|
|
96
|
+
- 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.
|
|
97
|
+
- Review a new world over sources that hold no map without a "before" picture, instead of failing with `MAP_RENDER_RASTER_MISSING`.
|
|
98
|
+
- 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.
|
|
99
|
+
- 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.
|
|
100
|
+
|
|
101
|
+
### Tools
|
|
102
|
+
|
|
103
|
+
- 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.
|
|
104
|
+
- 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.
|
|
105
|
+
- Name the tool and up to five failing fields with their reasons when the 2026-07-28 server rejects tool arguments.
|
|
106
|
+
- 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.
|
|
107
|
+
- 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.
|
|
108
|
+
- Print `startup_timeout_sec = 120` and `tool_timeout_sec = 600` in the Codex registrations from `hoi4-agent-tools-setup --print-client-config`.
|
|
109
|
+
|
|
110
|
+
### Fixes
|
|
111
|
+
|
|
112
|
+
- 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.
|
|
113
|
+
- 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.
|
|
114
|
+
- 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.
|
|
115
|
+
- 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.
|
|
116
|
+
- Record an orphaned worker's own deadline as `JOB_DEADLINE_EXCEEDED` instead of leaving the job running.
|
|
117
|
+
- 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.
|
|
118
|
+
- 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.
|
|
119
|
+
- Refuse reads, not only writes, of server storage (`.hoi4-agent`, artifact and cache roots) through workspace paths.
|
|
120
|
+
- Keep artifact listings from removing a folder that a concurrent write is filling.
|
|
121
|
+
- 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.
|
|
122
|
+
- 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.
|
|
123
|
+
- Sweep expired finished job results on first use, and keep the record of a refused task call for five minutes.
|
|
124
|
+
- Bound retained scan snapshots by bytes, remove temporary files from failed heartbeat writes, and drop server records silent for two hours.
|
|
125
|
+
- Release a foreground task's cancellation listener when the task finishes.
|
|
126
|
+
|
|
127
|
+
### Documentation
|
|
128
|
+
|
|
129
|
+
- 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.
|
|
130
|
+
- Add a configuration reference with every key, range, default location and environment variable.
|
|
131
|
+
- Complete the GUI scenario and request field tables, and document the prompt, resources, task-capable tools and setup troubleshooting commands.
|
|
132
|
+
- 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.
|
|
133
|
+
|
|
3
134
|
## 3.10.0 - 2026-10-06
|
|
4
135
|
|
|
5
136
|
- 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.
|
package/README.md
CHANGED
|
@@ -1,160 +1,104 @@
|
|
|
1
1
|
# HOI4 Agent Tools
|
|
2
2
|
|
|
3
|
-
|
|
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
|
+
<!-- TODO-VIDEO-LINK: replace with the promo video URL -->
|
|
6
4
|
|
|
7
|
-
|
|
5
|
+
[](https://www.youtube.com/@ChaosRedux)
|
|
8
6
|
|
|
9
|
-
|
|
7
|
+
[](https://www.npmjs.com/package/hoi4-agent-tools)
|
|
8
|
+
[](https://nodejs.org/)
|
|
9
|
+
[](LICENSE)
|
|
10
|
+
[](https://discord.gg/rAXesGcT2t)
|
|
11
|
+
[](https://www.youtube.com/@ChaosRedux)
|
|
12
|
+
[](https://ko-fi.com/klimpaskov)
|
|
13
|
+
[](https://github.com/klimPaskov/hoi4-agent-tools/releases/latest)
|
|
14
|
+
[](https://github.com/klimPaskov/hoi4-agent-tools/issues)
|
|
10
15
|
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
16
|
+
An [MCP](https://modelcontextprotocol.io/) server that helps coding agents build and edit Hearts of Iron IV mods.
|
|
17
|
+
Make focus trees, events and decisions. Edit maps and generate a new world. Preview windows, trees and maps, find the right rule in the docs, fix broken script and balance AI choices.
|
|
18
|
+
|
|
19
|
+
## What it does
|
|
20
|
+
|
|
21
|
+
Your agent can build and edit focus trees, events, decisions and maps, and generate a new world.
|
|
22
|
+
It previews focus trees, technology folders, windows and maps, finds the right rule in the game's documentation, fixes broken script and tunes AI choices.
|
|
23
|
+
You describe what you want; the agent picks the right tools.
|
|
24
|
+
|
|
25
|
+
## Quick start
|
|
26
|
+
|
|
27
|
+
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.
|
|
28
|
+
2. Install the server:
|
|
29
|
+
|
|
30
|
+
```bash
|
|
31
|
+
npm install --global hoi4-agent-tools
|
|
32
|
+
```
|
|
15
33
|
|
|
16
|
-
|
|
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.
|
|
34
|
+
3. Print the client configuration:
|
|
20
35
|
|
|
21
|
-
|
|
22
|
-
|
|
36
|
+
```bash
|
|
37
|
+
hoi4-agent-tools-setup --print-client-config
|
|
38
|
+
```
|
|
39
|
+
|
|
40
|
+
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`.
|
|
41
|
+
|
|
42
|
+
4. Open your mod folder as the agent's workspace and tell it what you want to build or fix.
|
|
43
|
+
|
|
44
|
+
The [setup guide](docs/setup.md) covers several mods, explicit game paths, local wiki snapshots and troubleshooting with `--discover` and `--diagnose`.
|
|
45
|
+
|
|
46
|
+
[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 connect the server for your mod.
|
|
47
|
+
Part of the HOI4 modding toolkit with [Agentic HOI4 Modding](https://github.com/klimPaskov/Agentic-HOI4-Modding) (skills and instructions for your agent) and [HOI4 Live Tools](https://github.com/klimPaskov/HOI4-Live-Tools) (testing in the running game).
|
|
23
48
|
|
|
24
49
|
## Examples
|
|
25
50
|
|
|
26
|
-
[
|
|
51
|
+
[](docs/images/comparisons/holy-realm-mcp.png)
|
|
52
|
+
|
|
53
|
+
Each pair shows a capture from the game next to the server's preview of the same source.
|
|
54
|
+
|
|
55
|
+
| In game | Server preview |
|
|
56
|
+
| -------------------------------------------------------------------------------------------------------------------------------------- | -------------------------------------------------------------------------------------------------------------------------------- |
|
|
57
|
+
| [](docs/images/comparisons/fury-ingame.png) | [](docs/images/comparisons/fury-mcp.png) |
|
|
58
|
+
| [](docs/images/comparisons/infantry-ingame.png) | [](docs/images/comparisons/infantry-mcp.png) |
|
|
59
|
+
| [](docs/images/comparisons/gui/options-video-ingame.png) | [](docs/images/comparisons/gui/options-video-mcp.png) |
|
|
60
|
+
|
|
61
|
+
See more in the [examples gallery](docs/examples.md).
|
|
62
|
+
|
|
63
|
+
## Tools
|
|
64
|
+
|
|
65
|
+
The server gives your agent previews, documentation, script analysis and editing tools.
|
|
66
|
+
The agent combines them with its file editor to build events and decisions, repair scripts and adjust AI weights.
|
|
67
|
+
The [tool reference](docs/tools.md) lists exact names, arguments and results for integrations.
|
|
68
|
+
|
|
69
|
+
## FAQ
|
|
70
|
+
|
|
71
|
+
**Where do edits go?** Changes are written to your mod folder; use Git to review or undo them.
|
|
72
|
+
|
|
73
|
+
**Does it run the game?** No. Previews come from mod source; test gameplay in HOI4 to see live clicks, AI choices and timing.
|
|
74
|
+
|
|
75
|
+
## Configuration
|
|
76
|
+
|
|
77
|
+
Started inside a mod folder, the server needs no configuration file.
|
|
78
|
+
`hoi4-agent-tools-setup --init` writes one when you work on several mods or the game is not found automatically.
|
|
79
|
+
For remote or shared use, `hoi4-agent-tools-http` serves the same tools over HTTP with tokens or OAuth.
|
|
80
|
+
See the [configuration reference](docs/configuration.md) and the [HTTP guide](docs/http.md).
|
|
81
|
+
|
|
82
|
+
## Documentation
|
|
83
|
+
|
|
84
|
+
- [Setup](docs/setup.md) and [configuration](docs/configuration.md)
|
|
85
|
+
- [Examples](docs/examples.md) and [tool reference](docs/tools.md)
|
|
86
|
+
- 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)
|
|
87
|
+
- [Background jobs](docs/jobs.md) and [HTTP](docs/http.md)
|
|
88
|
+
- [Development](docs/development.md), [changelog](CHANGELOG.md) and [security policy](SECURITY.md)
|
|
89
|
+
- [Documentation index](docs/README.md)
|
|
90
|
+
|
|
91
|
+
## Development
|
|
92
|
+
|
|
93
|
+
```bash
|
|
94
|
+
npm ci
|
|
95
|
+
npm run check
|
|
96
|
+
```
|
|
27
97
|
|
|
28
|
-
|
|
98
|
+
See the [contributing guide](https://github.com/klimPaskov/hoi4-agent-tools/blob/main/CONTRIBUTING.md) and the [development guide](docs/development.md).
|
|
29
99
|
|
|
30
|
-
|
|
31
|
-
| ----------- | --------------------------------------------------------------------------------------------------------------------------- | --------------------------------------------------------------------------------------------------------------------- |
|
|
32
|
-
| 52 focuses | [](docs/images/comparisons/fury-ingame.png) | [](docs/images/comparisons/fury-mcp.png) |
|
|
33
|
-
| 111 focuses | [](docs/images/comparisons/holy-realm-ingame.png) | [](docs/images/comparisons/holy-realm-mcp.png) |
|
|
34
|
-
| 124 focuses | [](docs/images/comparisons/utopia-ingame.png) | [](docs/images/comparisons/utopia-mcp.png) |
|
|
100
|
+
## License
|
|
35
101
|
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
The
|
|
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 | [](docs/images/comparisons/infantry-ingame.png) | [](docs/images/comparisons/infantry-mcp.png) |
|
|
47
|
-
| Mod wide cards | [](docs/images/comparisons/chemical-recent-ingame.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 | [](docs/images/comparisons/gui/options-video-ingame.png) | [](docs/images/comparisons/gui/options-video-mcp.png) |
|
|
60
|
-
| Vanilla priority panel | [](docs/images/comparisons/gui/skoda-priority-ingame.png) | [](docs/images/comparisons/gui/skoda-priority-mcp.png) |
|
|
61
|
-
| Mod management window | [](docs/images/comparisons/gui/tag-manager-ingame.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
|
-
| [](docs/images/comparisons/gui/event-log-mcp.png) | [](docs/images/comparisons/gui/chaos-meter-status-mcp.png) | [](docs/images/comparisons/gui/chaos-meter-deaths-mcp.png) |
|
|
69
|
-
|
|
70
|
-
| Vanilla decisions | Vanilla occupation |
|
|
71
|
-
| -------------------------------------------------------------------------------------------------------------------------------------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
|
72
|
-
| [](docs/images/comparisons/native-ui/countrydecisionview-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
|
-
| [](docs/images/comparisons/source/map-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.
|
|
102
|
+
Apache-2.0; see [LICENSE](LICENSE) and the [third-party notices](docs/third-party-notices.md).
|
|
103
|
+
Hearts of Iron IV artwork belongs to Paradox Interactive; this project is unaffiliated with Paradox Interactive.
|
|
104
|
+
The in-game captures were supplied for these comparisons.
|
package/dist/bin/http.js
CHANGED
|
@@ -23,6 +23,16 @@ main().catch((error) => {
|
|
|
23
23
|
? String(error.code)
|
|
24
24
|
: 'INTERNAL_ERROR',
|
|
25
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
|
+
: {}),
|
|
26
36
|
})}\n`);
|
|
27
37
|
process.exitCode = 1;
|
|
28
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
|
-
|
|
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
|
@@ -53,6 +53,16 @@ async function main() {
|
|
|
53
53
|
level: 'error',
|
|
54
54
|
event: 'transport_startup_failed',
|
|
55
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
|
+
: {}),
|
|
56
66
|
})}\n`);
|
|
57
67
|
},
|
|
58
68
|
...(chaosxTools === undefined
|
|
@@ -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
|
-
|
|
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
|
|
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 = [];
|
|
@@ -16,10 +16,24 @@ export function canonicalize(value) {
|
|
|
16
16
|
return value.map(canonicalize);
|
|
17
17
|
if (typeof value === 'object') {
|
|
18
18
|
const object = value;
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
19
|
+
// Filling the copy directly avoids an entry array per member; a plain object lists integer
|
|
20
|
+
// keys first and the rest in insertion (here code unit) order, the same as before.
|
|
21
|
+
const copy = {};
|
|
22
|
+
for (const key of Object.keys(object).sort(compareCodeUnits)) {
|
|
23
|
+
const member = object[key];
|
|
24
|
+
if (member === undefined)
|
|
25
|
+
continue;
|
|
26
|
+
if (key === '__proto__')
|
|
27
|
+
Object.defineProperty(copy, key, {
|
|
28
|
+
value: canonicalize(member),
|
|
29
|
+
enumerable: true,
|
|
30
|
+
writable: true,
|
|
31
|
+
configurable: true,
|
|
32
|
+
});
|
|
33
|
+
else
|
|
34
|
+
copy[key] = canonicalize(member);
|
|
35
|
+
}
|
|
36
|
+
return copy;
|
|
23
37
|
}
|
|
24
38
|
throw new TypeError(`Canonical JSON cannot contain ${typeof value}`);
|
|
25
39
|
}
|
|
@@ -176,6 +176,24 @@ function evaluateAssignmentCore(assignment, scenario, candidate, definitions, he
|
|
|
176
176
|
const malformed = malformedBlock(assignment.value, candidate);
|
|
177
177
|
if (malformed !== undefined)
|
|
178
178
|
return malformed;
|
|
179
|
+
if (key === 'has_country_flag' || key === 'has_global_flag' || key === 'has_state_flag') {
|
|
180
|
+
// The block form tests a flag's stored value. A scenario declares that value as a number
|
|
181
|
+
// under `flag.<name>` (or `global_flag.<name>` for global flags).
|
|
182
|
+
const flag = firstScalar(assignment.value, 'flag')?.value;
|
|
183
|
+
const expected = firstScalar(assignment.value, 'value')?.value;
|
|
184
|
+
if (flag !== undefined) {
|
|
185
|
+
const names = key === 'has_global_flag' ? [`global_flag.${flag}`, `flag.${flag}`] : [`flag.${flag}`];
|
|
186
|
+
for (const name of names) {
|
|
187
|
+
const declared = scopeStateValue(scenario, name, scopeContext);
|
|
188
|
+
if (typeof declared === 'number' && expected !== undefined)
|
|
189
|
+
return { state: declared === Number(expected) ? 'true' : 'false', unresolved: [] };
|
|
190
|
+
if (typeof declared === 'boolean' && expected === undefined)
|
|
191
|
+
return { state: declared ? 'true' : 'false', unresolved: [] };
|
|
192
|
+
}
|
|
193
|
+
if (expected !== undefined)
|
|
194
|
+
return unresolved(assignment, candidate, `Scenario does not declare the value of flag ${flag}`, `flag.${flag}`);
|
|
195
|
+
}
|
|
196
|
+
}
|
|
179
197
|
if (key === 'AND' ||
|
|
180
198
|
key === 'hidden_trigger' ||
|
|
181
199
|
key === 'custom_trigger_tooltip' ||
|