hoi4-agent-tools 0.1.7 → 0.2.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.
- package/CHANGELOG.md +24 -0
- package/README.md +31 -25
- package/SECURITY.md +4 -2
- package/dist/bin/setup.js +11 -4
- package/dist/bin/setup.js.map +1 -1
- package/dist/hoi4_agent_tools/core/configuration.d.ts +1 -0
- package/dist/hoi4_agent_tools/core/configuration.d.ts.map +1 -1
- package/dist/hoi4_agent_tools/core/configuration.js +3 -3
- package/dist/hoi4_agent_tools/core/configuration.js.map +1 -1
- package/dist/hoi4_agent_tools/core/engine.d.ts +1 -0
- package/dist/hoi4_agent_tools/core/engine.d.ts.map +1 -1
- package/dist/hoi4_agent_tools/core/engine.js +1 -0
- package/dist/hoi4_agent_tools/core/engine.js.map +1 -1
- package/dist/hoi4_agent_tools/core/transactions.d.ts +2 -0
- package/dist/hoi4_agent_tools/core/transactions.d.ts.map +1 -1
- package/dist/hoi4_agent_tools/core/transactions.js +49 -6
- package/dist/hoi4_agent_tools/core/transactions.js.map +1 -1
- package/dist/hoi4_agent_tools/core/workspace.js +1 -1
- package/dist/hoi4_agent_tools/core/workspace.js.map +1 -1
- package/dist/hoi4_agent_tools/focus/service.d.ts.map +1 -1
- package/dist/hoi4_agent_tools/focus/service.js +4 -18
- package/dist/hoi4_agent_tools/focus/service.js.map +1 -1
- package/dist/hoi4_agent_tools/gui/studio.d.ts.map +1 -1
- package/dist/hoi4_agent_tools/gui/studio.js +3 -2
- package/dist/hoi4_agent_tools/gui/studio.js.map +1 -1
- package/dist/hoi4_agent_tools/map/service.d.ts.map +1 -1
- package/dist/hoi4_agent_tools/map/service.js +11 -5
- package/dist/hoi4_agent_tools/map/service.js.map +1 -1
- package/dist/hoi4_agent_tools/mcp/prompts/register.d.ts +2 -1
- package/dist/hoi4_agent_tools/mcp/prompts/register.d.ts.map +1 -1
- package/dist/hoi4_agent_tools/mcp/prompts/register.js +35 -13
- package/dist/hoi4_agent_tools/mcp/prompts/register.js.map +1 -1
- package/dist/hoi4_agent_tools/mcp/registry/metadata.d.ts +1 -1
- package/dist/hoi4_agent_tools/mcp/security/auth.d.ts.map +1 -1
- package/dist/hoi4_agent_tools/mcp/security/auth.js +1 -4
- package/dist/hoi4_agent_tools/mcp/security/auth.js.map +1 -1
- package/dist/hoi4_agent_tools/mcp/server/base-tools.d.ts +12 -0
- package/dist/hoi4_agent_tools/mcp/server/base-tools.d.ts.map +1 -1
- package/dist/hoi4_agent_tools/mcp/server/base-tools.js +239 -220
- package/dist/hoi4_agent_tools/mcp/server/base-tools.js.map +1 -1
- package/dist/hoi4_agent_tools/mcp/server/create.d.ts.map +1 -1
- package/dist/hoi4_agent_tools/mcp/server/create.js +8 -2
- package/dist/hoi4_agent_tools/mcp/server/create.js.map +1 -1
- package/dist/hoi4_agent_tools/mcp/server/output-schemas.d.ts +5 -0
- package/dist/hoi4_agent_tools/mcp/server/output-schemas.d.ts.map +1 -1
- package/dist/hoi4_agent_tools/mcp/server/output-schemas.js +1 -0
- package/dist/hoi4_agent_tools/mcp/server/output-schemas.js.map +1 -1
- package/dist/hoi4_agent_tools/mcp/server/result.js +1 -1
- package/dist/hoi4_agent_tools/mcp/server/result.js.map +1 -1
- package/dist/hoi4_agent_tools/mcp/server/transaction-execution.d.ts +31 -0
- package/dist/hoi4_agent_tools/mcp/server/transaction-execution.d.ts.map +1 -0
- package/dist/hoi4_agent_tools/mcp/server/transaction-execution.js +127 -0
- package/dist/hoi4_agent_tools/mcp/server/transaction-execution.js.map +1 -0
- package/dist/hoi4_agent_tools/mcp/tools/focus.d.ts.map +1 -1
- package/dist/hoi4_agent_tools/mcp/tools/focus.js +69 -23
- package/dist/hoi4_agent_tools/mcp/tools/focus.js.map +1 -1
- package/dist/hoi4_agent_tools/mcp/tools/gui.d.ts +6 -0
- package/dist/hoi4_agent_tools/mcp/tools/gui.d.ts.map +1 -1
- package/dist/hoi4_agent_tools/mcp/tools/gui.js +40 -12
- package/dist/hoi4_agent_tools/mcp/tools/gui.js.map +1 -1
- package/dist/hoi4_agent_tools/mcp/tools/map.d.ts.map +1 -1
- package/dist/hoi4_agent_tools/mcp/tools/map.js +39 -12
- package/dist/hoi4_agent_tools/mcp/tools/map.js.map +1 -1
- package/dist/hoi4_agent_tools/mcp/transports/http.d.ts.map +1 -1
- package/dist/hoi4_agent_tools/mcp/transports/http.js +3 -0
- package/dist/hoi4_agent_tools/mcp/transports/http.js.map +1 -1
- package/dist/hoi4_agent_tools/version.d.ts +1 -1
- package/dist/hoi4_agent_tools/version.js +1 -1
- package/docs/README.md +2 -2
- package/docs/adr/0012-autonomous-rewrites.md +55 -0
- package/docs/adr/README.md +1 -0
- package/docs/agent-integration.md +33 -23
- package/docs/architecture.md +20 -4
- package/docs/artifacts.md +8 -5
- package/docs/completion-report.md +85 -125
- package/docs/configuration.md +24 -8
- package/docs/focus-workflow.md +16 -14
- package/docs/gui-workflow.md +7 -3
- package/docs/limitations.md +3 -2
- package/docs/map-workflow.md +15 -9
- package/docs/performance.md +1 -1
- package/docs/release.md +11 -9
- package/docs/research/mcp-2026-07-10.md +9 -3
- package/docs/security.md +12 -6
- package/docs/self-hosting.md +8 -6
- package/docs/transactions.md +45 -33
- package/docs/troubleshooting.md +12 -4
- package/package.json +2 -2
- package/schemas/configuration.schema.json +3 -2
- package/schemas/continuous-focus-palette.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/map-operation.schema.json +1 -1
- package/schemas/operation-result.schema.json +1 -1
- package/schemas/transaction-manifest.schema.json +1 -1
- package/server.json +3 -3
package/docs/configuration.md
CHANGED
|
@@ -7,6 +7,14 @@ path is equally valid when the client registration sets `HOI4_AGENT_CONFIG`. Unk
|
|
|
7
7
|
rejected.
|
|
8
8
|
The read-only setup discovery command also checks `HOI4_GAME_ROOT` and the path-delimited `HOI4_MOD_ROOTS`; it reports candidates without registering or modifying them.
|
|
9
9
|
|
|
10
|
+
Setup stays read-only unless a write flag is explicit. The recommended write configuration is generated with:
|
|
11
|
+
|
|
12
|
+
```bash
|
|
13
|
+
hoi4-agent-tools-setup --init-config /absolute/path/config.json --workspace /absolute/path/mod --autonomous-writes --server-state /separate/operator/state
|
|
14
|
+
```
|
|
15
|
+
|
|
16
|
+
That writes `"writePolicy": "autonomous"` and `"writeEnabled": true` for the supplied mod. Use `--reviewed-writes` only for the legacy separate review/apply tool sequence; `--enable-writes` remains a compatibility alias for reviewed mode. Autonomous and reviewed flags are mutually exclusive, and both require `--server-state`.
|
|
17
|
+
|
|
10
18
|
The stdio executable accepts newline-delimited JSON-RPC frames up to a fixed 16,777,216-byte
|
|
11
19
|
ceiling, excluding the line-feed delimiter. This transport safety limit is deliberately not a
|
|
12
20
|
configuration field; malformed UTF-8 and oversized terminated or unterminated frames close the
|
|
@@ -16,7 +24,7 @@ separately configured `http.maxBodyBytes`.
|
|
|
16
24
|
```json
|
|
17
25
|
{
|
|
18
26
|
"version": 1,
|
|
19
|
-
"writePolicy": "
|
|
27
|
+
"writePolicy": "autonomous",
|
|
20
28
|
"serverStateRoot": "/var/lib/hoi4-agent-tools-state",
|
|
21
29
|
"transactionTtlSeconds": 3600,
|
|
22
30
|
"transactionMaxJournalBytes": 536870912,
|
|
@@ -47,7 +55,7 @@ separately configured `http.maxBodyBytes`.
|
|
|
47
55
|
"replacePaths": ["common/national_focus"],
|
|
48
56
|
"artifactRoot": "/srv/hoi4/workspaces/example/.hoi4-agent/artifacts",
|
|
49
57
|
"cacheRoot": "/srv/hoi4/workspaces/example/.hoi4-agent/cache",
|
|
50
|
-
"writeEnabled":
|
|
58
|
+
"writeEnabled": true
|
|
51
59
|
}
|
|
52
60
|
]
|
|
53
61
|
}
|
|
@@ -60,8 +68,8 @@ All byte values are exact bytes. Defaults are applied when a field is omitted.
|
|
|
60
68
|
| Field | Default | Validation and behavior |
|
|
61
69
|
| ---------------------------- | ----------------------: | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
|
62
70
|
| `version` | required | Must equal the current configuration version, `1`. |
|
|
63
|
-
| `writePolicy` | `"read-only"` | `"read-only"` or `"transactions"`.
|
|
64
|
-
| `serverStateRoot` | omitted | Required for
|
|
71
|
+
| `writePolicy` | `"read-only"` | `"read-only"`, recommended `"autonomous"`, or compatibility `"transactions"`. |
|
|
72
|
+
| `serverStateRoot` | omitted | Required for either write policy; absolute canonical operator state used for the private journal key and replay-protection heads. |
|
|
65
73
|
| `transactionTtlSeconds` | `3600` | 60 through 86,400 seconds. |
|
|
66
74
|
| `transactionMaxJournalBytes` | `536870912` | At least 1 MiB; aggregate transaction-journal retention ceiling and per-plan work ceiling. |
|
|
67
75
|
| `transactionMaxJournals` | `128` | 1 through 10,000 journals per workspace cache. |
|
|
@@ -82,7 +90,7 @@ The configuration also rejects unsafe combined budgets: `scanMaxBytes` multiplie
|
|
|
82
90
|
`maxConcurrentRequests` must be at most 16 MiB. HTTP concurrency has a fixed maximum of two so two
|
|
83
91
|
simultaneous offline renders cannot exceed the supported process-safety model.
|
|
84
92
|
|
|
85
|
-
`serverStateRoot` is mandatory whenever `writePolicy` is `"
|
|
93
|
+
`serverStateRoot` is mandatory whenever `writePolicy` is not `"read-only"`. It must be absolute,
|
|
86
94
|
resolve to a canonical directory through components that contain no symbolic links or junctions,
|
|
87
95
|
and it must not overlap any configured or runtime source, fixture, artifact, cache, registration,
|
|
88
96
|
writable-registration, or storage root. The server stores the native canonical spelling, including
|
|
@@ -112,7 +120,7 @@ protocol when those primitives are unavailable.
|
|
|
112
120
|
| `artifactRoot` | mod default; otherwise required | A mod defaults to `<root>/.hoi4-agent/artifacts`. A game/dependency primary workspace must name an operator-owned path under `storageRoots`. |
|
|
113
121
|
| `cacheRoot` | mod default; otherwise required | A mod defaults to `<root>/.hoi4-agent/cache`. A game/dependency primary workspace must name an operator-owned path under `storageRoots`. |
|
|
114
122
|
| `fixtureRoot` | omitted | Optional read-only fixture source. |
|
|
115
|
-
| `writeEnabled` | `false` | Effective only for `kind: "mod"` when global `writePolicy` is `"transactions"`.
|
|
123
|
+
| `writeEnabled` | `false` | Effective only for `kind: "mod"` when global `writePolicy` is `"autonomous"` or `"transactions"`. |
|
|
116
124
|
|
|
117
125
|
`registrationRoots`, `writableRegistrationRoots`, and `storageRoots` grant different capabilities:
|
|
118
126
|
|
|
@@ -170,11 +178,19 @@ path samples, so a workspace with many `replace_path` entries cannot inflate a t
|
|
|
170
178
|
|
|
171
179
|
## Read and write policy
|
|
172
180
|
|
|
173
|
-
`writePolicy` defaults to `read-only`.
|
|
181
|
+
`writePolicy` defaults to `read-only`. In this mode the server exposes analysis and evidence tools but no source-mutation path.
|
|
182
|
+
|
|
183
|
+
`autonomous` is the recommended write policy. With `writeEnabled: true` on a mod workspace, it exposes `hoi4.focus_rewrite`, `hoi4.gui_rewrite`, and `hoi4.map_rewrite`. Each tool plans, validates, journals, applies, rebuilds the index, and post-validates inside one call. If application or post-validation fails, exact original bytes are restored automatically. The transaction status/diff/apply/rollback tools are not registered in autonomous mode.
|
|
184
|
+
|
|
185
|
+
`transactions` is an optional compatibility policy for clients that still need a distinct reviewed plan and apply boundary. It exposes the `*_plan_changes`/`map_plan` tools plus `hoi4.transaction_status`, `hoi4.transaction_diff`, `hoi4.transaction_apply`, and `hoi4.transaction_rollback`. It uses the same journal, hash checks, post-validation, and automatic failure recovery as autonomous mode.
|
|
186
|
+
|
|
187
|
+
Both write policies require `serverStateRoot` and `writeEnabled: true` on the target mod. A dependency or game registration remains read-only even if misconfigured. Changing the global policy changes the MCP tool surface; restart the server and reinitialize the MCP session after changing it.
|
|
188
|
+
|
|
189
|
+
The autonomous rewrite tools advertise `destructiveHint: true`. MCP does not require per-call prompts from that annotation, and server configuration cannot override a client's host approval or filesystem policy. A client may still prompt for or refuse a rewrite.
|
|
174
190
|
|
|
175
191
|
`registrationRoots` controls runtime `hoi4.project_register`. A requested root must canonicalize beneath one of these roots, and a runtime mod additionally requires `writableRegistrationRoots`. HTTP principals also need `allowRegistration`. Granting `allowRegistration` permits that principal to register unclaimed sources beneath the configured capability roots, so use narrow roots or static reviewed workspaces for multi-user deployments. Runtime registration does not edit a client configuration or persist raw paths. It atomically records a hash-only owner/workspace claim in the canonical artifact root; later registrations of that physical store must match it. Reassigning a claimed store is therefore an explicit operator operation: stop the server, review/archive the claim and existing evidence, and choose whether to preserve or separately migrate data. The server never deletes or silently rebinds it.
|
|
176
192
|
|
|
177
|
-
|
|
193
|
+
Write modes do not accept pre-upgrade unauthenticated journal manifests. Preserve their
|
|
178
194
|
cache directories for operator review, then explicitly archive or remove them together with the
|
|
179
195
|
corresponding protected state decision; the server never guesses a migration or treats a public
|
|
180
196
|
integrity hash as authorization.
|
package/docs/focus-workflow.md
CHANGED
|
@@ -29,8 +29,10 @@ National focuses and continuous focuses use their actual HOI4 source models. Nat
|
|
|
29
29
|
3. `hoi4.focus_lint` separates syntax, reference, layout, and design diagnostics. Omit `mode` for national-tree compatibility, or pass `mode: "continuous"` with an optional `paletteId` to lint a palette directly.
|
|
30
30
|
4. `hoi4.focus_layout` calculates stable integer coordinates. Pinned positions and existing coordinates anchor incremental changes.
|
|
31
31
|
5. `hoi4.focus_render` returns deterministic HTML, SVG, PNG, JSON, and generated-source-map resources. National mode also returns the graph layout and hash-bound planning sidecar; a uniform `reviewScale` from `0.25` through `1.0` keeps unusually wide or deep trees within bounded raster limits without changing logical geometry or source coordinates. Continuous mode accepts palette columns and renders the actual continuous-focus source model.
|
|
32
|
-
6. `hoi4.
|
|
33
|
-
7.
|
|
32
|
+
6. In autonomous mode, `hoi4.focus_rewrite` accepts either a national plan (the default when `mode` is omitted) or `mode: "continuous"` with a continuous-palette plan. It makes source-preserving range edits where possible, produces before/proposed/bitmap-diff evidence, journals exact recovery bytes, applies, rebuilds the index, and post-validates in one call. National plans may set `horizontalSpacing`, `verticalSpacing`, `padding`, and a uniform `reviewScale` for both review renders; those pixel-space settings do not alter focus coordinates or compiled HOI4 source. National plans also maintain the adjacent planning sidecar. To create a first tree or palette in a new mod source file, set `createIfMissing: true`; without it, missing sources and IDs refuse. Creation never appends a different target to an existing source file, never copies a read-only game/dependency file into a shadowing mod path, and restores newly created source and sidecar files automatically if the rewrite fails.
|
|
33
|
+
7. Check `execution`, drift, diagnostics, validation, changed files, source maps, and diff artifacts. `execution: "planned"` means validation blocked the proposal without changing source; `execution: "applied"` means post-write validation succeeded.
|
|
34
|
+
|
|
35
|
+
With the optional `"transactions"` compatibility policy, use `hoi4.focus_plan_changes`, page through `hoi4.transaction_diff`, and call `hoi4.transaction_apply` with the exact plan hash instead. The same core validation and recovery engine is used.
|
|
34
36
|
|
|
35
37
|
## Repairing an existing large tree
|
|
36
38
|
|
|
@@ -48,17 +50,17 @@ full cleanup, the coding agent must make the movement policy explicit:
|
|
|
48
50
|
4. Keep only deliberate trunk or convergence anchors fixed/pinned. Change every movable focus to
|
|
49
51
|
`{ "mode": "auto", "pinned": false }`; `preferredX` and `preferredY` may retain the authored
|
|
50
52
|
route intent without making those coordinates mandatory.
|
|
51
|
-
5. Submit the complete plan to `hoi4.
|
|
52
|
-
lint, source-preserving range edits, deterministic before/proposed rendering,
|
|
53
|
+
5. Submit the complete plan to `hoi4.focus_rewrite`. The call performs layout, compilation,
|
|
54
|
+
lint, source-preserving range edits, deterministic before/proposed rendering, bitmap diffing,
|
|
55
|
+
journaling, application, index rebuild, and post-write validation.
|
|
53
56
|
For an unusually wide or deep tree, set a uniform national `reviewScale` between `0.25` and
|
|
54
57
|
`1.0`; `0.4` is appropriate for a very large comparison. It scales nodes, text, connectors, and
|
|
55
58
|
the viewport together, avoiding artificial overlap. The same scale governs both sides of the
|
|
56
59
|
comparison and affects only artifact pixels, never source-grid coordinates. Explicit spacing and
|
|
57
60
|
padding remain available when the artifact's logical presentation itself needs adjustment.
|
|
58
|
-
6.
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
`hoi4.transaction_rollback` and the same transaction ID and plan hash.
|
|
61
|
+
6. Inspect the returned validation and evidence links. Rescan, lint, and render when additional
|
|
62
|
+
final evidence is useful. A blocked proposal changes nothing; failure after replacement begins
|
|
63
|
+
restores every affected file automatically.
|
|
62
64
|
|
|
63
65
|
This workflow is suitable for hundreds of focuses. The solver keeps parents above children,
|
|
64
66
|
rejects visible overlap and duplicate coordinates, separates bounded lanes, validates relative
|
|
@@ -75,7 +77,7 @@ localisation/icon/AI/link metadata. Unsupported Clausewitz blocks belong in `raw
|
|
|
75
77
|
round-trip instead of being approximated.
|
|
76
78
|
|
|
77
79
|
This minimal national plan is schema-valid. It intentionally omits an icon and reward; a production
|
|
78
|
-
tree should add complete presentation and gameplay data before
|
|
80
|
+
tree should add complete presentation and gameplay data before rewriting:
|
|
79
81
|
|
|
80
82
|
```json
|
|
81
83
|
{
|
|
@@ -142,10 +144,10 @@ tree should add complete presentation and gameplay data before apply:
|
|
|
142
144
|
Within each focus, one `prerequisites.groups` entry represents one Clausewitz `prerequisite` block
|
|
143
145
|
whose listed focuses are OR alternatives. Multiple group entries are AND requirements. For a new
|
|
144
146
|
target, use `sourcePath: "plan:<tree-id>"` and 64 zeroes for both initial hashes, then call
|
|
145
|
-
`hoi4.
|
|
147
|
+
`hoi4.focus_rewrite` with `createIfMissing: true`. Use that convention only for a missing
|
|
146
148
|
target. Existing sources normally use imported, hash-bound provenance; resolving intentional
|
|
147
149
|
plan/source drift additionally requires explicit `authority: "plan"`. The server refuses to append
|
|
148
|
-
a different tree to an occupied source file and still requires
|
|
150
|
+
a different tree to an occupied source file and still requires complete pre-write and post-write validation.
|
|
149
151
|
|
|
150
152
|
## Prerequisite and route semantics
|
|
151
153
|
|
|
@@ -179,7 +181,7 @@ Weak dangling branches, terminal payoff, missing AI, and repeated generic reward
|
|
|
179
181
|
|
|
180
182
|
The plan records imported source and semantic hashes. If both saved plan and hand-edited script diverge, regeneration is blocked until the coding agent explicitly identifies the authoritative source. Raw fields remain attached to source ranges either way. An explicitly created target reports `target_missing` drift with `requiresAuthority: false`; that status means there is no prior target to reconcile, not that an existing source was overwritten.
|
|
181
183
|
|
|
182
|
-
Every compiled or proposed focus block receives a source-map entry containing the focus ID, generated location, planning-node location when available, and imported source location when available. National render artifacts use `<tree>.focus.source-map.json`; continuous renders use `<palette>.continuous.source-map.json`.
|
|
184
|
+
Every compiled or proposed focus block receives a source-map entry containing the focus ID, generated location, planning-node location when available, and imported source location when available. National render artifacts use `<tree>.focus.source-map.json`; continuous renders use `<palette>.continuous.source-map.json`. Rewrite journals retain the corresponding proposed source map and all review artifacts after success or automatic restoration.
|
|
183
185
|
|
|
184
186
|
## Artifacts
|
|
185
187
|
|
|
@@ -187,9 +189,9 @@ Each rendered node includes its ID, resolved title/working label, resolved icon
|
|
|
187
189
|
|
|
188
190
|
National-tree renders store `<tree>.focus.html`, `.svg`, `.png`, `.json`, `.source-map.json`, and `.plan.json`. Continuous-palette renders use the same core artifact store and produce `<palette>.continuous.html`, `.svg`, `.png`, `.json`, and `.source-map.json`. The JSON embeds the same complete generated-source map that is also stored separately, and all formats carry content hashes plus source/render provenance.
|
|
189
191
|
|
|
190
|
-
A national focus
|
|
192
|
+
A national focus rewrite also stores `<tree>.focus.proposed-validation.json`. It contains every
|
|
191
193
|
diagnostic and validation check from re-importing, laying out, and linting the compiled proposal.
|
|
192
194
|
When that complete set is larger than the fixed transaction-manifest allowance, the manifest keeps
|
|
193
195
|
a blocker-first bounded summary and an explicit resource diagnostic; it never drops findings from
|
|
194
|
-
the validation decision. The
|
|
196
|
+
the validation decision. The rewrite boundary uses the same pattern for oversized post-write
|
|
195
197
|
diagnostics.
|
package/docs/gui-workflow.md
CHANGED
|
@@ -63,11 +63,15 @@ BMFont text inputs stop at 2,097,152 bytes, 50,000 records, 32 fields per record
|
|
|
63
63
|
|
|
64
64
|
## Source-preserving plans
|
|
65
65
|
|
|
66
|
-
Existing `.gui` files accept only hash-bound patches at parser-proven ranges. A patch may replace one known scalar assignment or scalar value, delete one known scalar assignment, or insert complete parsed entries immediately before a block close. Whole-file ranges, block rewrites, unknown-field rewrites, malformed insertions, stale text, and ambiguous ranges are refused. New files may be supplied in full only when no mod, dependency, or game source already owns the path. Every proposal is reparsed and rendered before it can
|
|
66
|
+
Existing `.gui` files accept only hash-bound patches at parser-proven ranges. A patch may replace one known scalar assignment or scalar value, delete one known scalar assignment, or insert complete parsed entries immediately before a block close. Whole-file ranges, block rewrites, unknown-field rewrites, malformed insertions, stale text, and ambiguous ranges are refused. New files may be supplied in full only when no mod, dependency, or game source already owns the path. Every proposal is reparsed and rendered before it can be journaled or applied.
|
|
67
|
+
|
|
68
|
+
With `writePolicy: "autonomous"`, call `hoi4.gui_rewrite` in `source`, `patches`, or `helpers` mode. The one call validates the proposal, persists exact recovery bytes, applies under the workspace lock, rebuilds the index, and post-validates. A successful result reports `execution: "applied"`; a blocked proposal reports `execution: "blocked"` and changes no source; a valid no-change request reports `execution: "unchanged"`. Any application or post-validation failure restores the original bytes automatically. No transaction diff/apply/rollback tools are exposed in autonomous mode.
|
|
69
|
+
|
|
70
|
+
The optional `"transactions"` compatibility policy exposes `hoi4.gui_plan_changes` and the separate transaction review/apply tools instead. Both policies use the same source-preserving compiler, validation, journal, and recovery implementation.
|
|
67
71
|
|
|
68
72
|
## Declarative helper compilation
|
|
69
73
|
|
|
70
|
-
`hoi4.
|
|
74
|
+
`hoi4.gui_rewrite` in `helpers` mode compiles a strict, build-time helper document into explicit `.gui` source and runs it through the normal autonomous rewrite path. In compatibility mode, use `hoi4.gui_plan_changes` with the same input. The generated mod has no runtime dependency on `hoi4-agent-tools` or its server.
|
|
71
75
|
|
|
72
76
|
A document has one `root` and may declare reusable `templates`. A template instance uses `kind: "template"` plus `templateId`; its instance ID becomes the deterministic prefix for every expanded ID and name. For example, instance `left_status` of a template whose root is named `status_card` produces `left_status__status_card`. Instance fields may override the template root, but templates do not provide parameters, slots, or appended children. Missing references, duplicate template IDs, duplicate node IDs, reference cycles, duplicate compiled GUI names, and source or expanded budget overflow refuse compilation. Expanded identifiers stop at 1,024 UTF-8 bytes; conservative source-construction work stops at 16 MiB, and final source stops at the 8 MiB Clausewitz parser ceiling before a transaction is planned.
|
|
73
77
|
|
|
@@ -95,7 +99,7 @@ The structured helpers compile as follows:
|
|
|
95
99
|
|
|
96
100
|
Structured leaf output is type-aware. `iconType` accepts sprite/frame fields, `instantTextBoxType` accepts text/font plus `maxWidth` and `maxHeight`, and `buttonType` accepts sprite/frame plus `buttonText` and `buttonFont`. Leaf elements never receive a fabricated `size` block and cannot contain child GUI elements. Hardcoded or legacy forms such as `checkboxType`, `guiButtonType`, and `textBoxType` are refused by the structured helper; use `raw` only when an exact engine precedent justifies them.
|
|
97
101
|
|
|
98
|
-
Selecting a custom UI `state` requires a matching `stateVariants` entry. Its frame, sprite, text, font, and allowlisted scalar attributes replace the base values in the emitted source; no preview-state comment or inferred frame is written. The engine-managed `normal`, `hover`, `pressed`, and `disabled` states may be named on `buttonType` without a custom variant, but the compiler does not fabricate their frame mapping. Attribute keys must be both safe identifiers and documented scalar fields for the selected container, icon, text, or button type; structured fields, misspellings, and type-incompatible fields cannot be smuggled through `attributes`. `raw` remains the explicit escape hatch for complete advanced Clausewitz GUI source and is counted in
|
|
102
|
+
Selecting a custom UI `state` requires a matching `stateVariants` entry. Its frame, sprite, text, font, and allowlisted scalar attributes replace the base values in the emitted source; no preview-state comment or inferred frame is written. The engine-managed `normal`, `hover`, `pressed`, and `disabled` states may be named on `buttonType` without a custom variant, but the compiler does not fabricate their frame mapping. Attribute keys must be both safe identifiers and documented scalar fields for the selected container, icon, text, or button type; structured fields, misspellings, and type-incompatible fields cannot be smuggled through `attributes`. `raw` remains the explicit escape hatch for complete advanced Clausewitz GUI source and is counted in rewrite evidence.
|
|
99
103
|
|
|
100
104
|
## Validation
|
|
101
105
|
|
package/docs/limitations.md
CHANGED
|
@@ -15,6 +15,7 @@ These are precise safety boundaries, not silent fallbacks.
|
|
|
15
15
|
- Declarative GUI helper documents admit at most 1,024 one-root templates and 64 state variants per node; both source and expanded trees remain subject to the 128-level and 10,000-node ceilings. Grid columns stop at 10,000, expanded identifiers at 1,024 UTF-8 bytes, conservative source-construction work at 16 MiB, and final generated source at 8 MiB. Templates have root overrides but no parameters, slots, or appended children. Scroll-list helpers emit deterministic grid and entry-container handoff names but do not create `dynamic_lists` scripted-GUI bindings or verify an external scrollbar definition's axis. Meter helpers choose one static icon frame from a validated range and do not provide runtime progress behavior. Advanced, hardcoded, legacy, or non-allowlisted scalar GUI fields require the counted raw escape hatch.
|
|
16
16
|
- Focus design diagnostics such as weak branches, payoff quality, avoidable crossings, or generic rewards are deterministic heuristics and do not rewrite gameplay.
|
|
17
17
|
- Plan/script drift requires an explicit authoritative-source choice.
|
|
18
|
+
- Autonomous mode deliberately exposes only `hoi4.focus_rewrite`, `hoi4.gui_rewrite`, and `hoi4.map_rewrite`; it does not expose transaction diff, status, apply, or explicit rollback tools. Failed application and post-validation restore automatically. An intentional later reversal requires Git or another explicit domain rewrite. The tools advertise `destructiveHint: true`, but MCP does not mandate per-tool confirmation and the server cannot override its host's approval policy.
|
|
18
19
|
- Map geometry requires an exact polygon with explicit `fillRule: "even-odd"`, a canonical hash-bound raster-mask manifest, or absolute pixel selection. Polygon vertices are integer raster-boundary coordinates: `0` through raster width/height are valid, greater coordinates are refused before work allocation, and polygons are never clipped. Inclusion is determined at pixel centers. Descriptive geography alone cannot apply.
|
|
19
20
|
- Province hole detection is a deterministic four-connected digital-topology review. It warns on enclosed components but does not declare every enclave invalid; provinces touching the horizontally wrapping map seam are excluded from the planar hole calculation.
|
|
20
21
|
- Map text tables are limited to 16,777,216 bytes and 500,000 records so the bounded parser admits the current vanilla unit-position table. Province rasters are limited to the documented 13,238,272-pixel engine area, exact raster masks to 20,000,000 cells, and polygon rasterization to 50,000,000 cell-point comparisons. Every exact selection/recolor operation is additionally limited to 1,000,000 pixels, including explicit pixels, selected mask cells, rasterized polygons, normal-adjacency transfers, whole-province color updates, and merges. Known counts are refused before dangerous decoding/scanning/materialization with `MAP_SELECTED_PIXEL_BUDGET_BLOCKED`. Selected pixels use four-byte numeric offsets, so the primary operation-owned offset buffer remains below 4 MiB (4,000,000 bytes); coordinate-string keys and per-pixel coordinate/color object arrays are not materialized. Map diagnostics are capped at 2,000; overflow retains 1,999 findings and replaces the last slot with a blocking `MAP_DIAGNOSTICS_TRUNCATED`. Undefined bitmap colors retain at most 256 individual samples and add a blocker when more distinct colors exist.
|
|
@@ -24,8 +25,8 @@ These are precise safety boundaries, not silent fallbacks.
|
|
|
24
25
|
- State `capital` is derived from exact victory points for inspection; Agent Nudger does not write a generic state `capital` assignment.
|
|
25
26
|
- Map ID allocation obeys scanned format/contiguity evidence from every root's own `default.map`-selected definition database; it refuses an allocation when the current source family cannot safely represent a gap or append. A present selector with any syntax or parser-limit diagnostic blocks the whole map model, including when it belongs to a lower game/dependency root, because falling back could hide an ID or color collision.
|
|
26
27
|
- Province merge/removal supports arbitrary compatible source IDs and compacts every connected province reference; it refuses renumbering only when the active definition table is already gapped or ambiguous by ID/color, or when source and target type/state/region membership is incompatible.
|
|
27
|
-
- Recoverable logical multi-file atomicity cannot prevent an unrelated process from briefly reading a replacement sequence. Success follows the server's post-write validation and final hash check, and persisted before-bytes support rollback. This is not a race-proof filesystem transaction: hostile concurrent symlink, junction, mount, directory, or file replacement by another operating-system principal is outside the application security boundary.
|
|
28
|
-
- Artifact retention defaults to 536,870,912 bytes, 5,000 manifests, and 134,217,728 bytes per content object; each provenance manifest is separately capped at 1 MiB before parsing. Broad project, focus, GUI, and map manifests retain a bounded source-hash sample plus a digest commitment to the complete inventory, while exact structured artifact content retains the complete hashes. Opt-in oversized logical evidence is preserved as bounded binary chunks plus a one-read JSON index, not as a larger content object: every chunk/index manifest counts against the same quotas, an index above 1 MiB is refused, and one logical preparation batch has a fixed 536,870,912-byte in-memory ceiling (or the lower configured aggregate ceiling). The whole logical batch is admitted before copying or hashing; preflight and hashing yield to cancellation.
|
|
28
|
+
- Recoverable logical multi-file atomicity cannot prevent an unrelated process from briefly reading a replacement sequence. Success follows the server's post-write validation and final hash check, and persisted before-bytes support automatic failure restoration (plus explicit rollback in reviewed compatibility mode). This is not a race-proof filesystem transaction: hostile concurrent symlink, junction, mount, directory, or file replacement by another operating-system principal is outside the application security boundary. Git supplies project history but is not required for the internal recovery guarantee.
|
|
29
|
+
- Artifact retention defaults to 536,870,912 bytes, 5,000 manifests, and 134,217,728 bytes per content object; each provenance manifest is separately capped at 1 MiB before parsing. Broad project, focus, GUI, and map manifests retain a bounded source-hash sample plus a digest commitment to the complete inventory, while exact structured artifact content retains the complete hashes. Opt-in oversized logical evidence is preserved as bounded binary chunks plus a one-read JSON index, not as a larger content object: every chunk/index manifest counts against the same quotas, an index above 1 MiB is refused, and one logical preparation batch has a fixed 536,870,912-byte in-memory ceiling (or the lower configured aggregate ceiling). The whole logical batch is admitted before copying or hashing; preflight and hashing yield to cancellation. Internal rewrite/transaction journals default to 536,870,912 bytes and 128 entries, with a fixed 16 MiB ceiling per authenticated manifest; only expired authenticated planned/rolled-back journals, authenticated safe cache-without-head remnants, head-without-cache remnants, or old manifest-less directories are pruned, while other terminal/interrupted or unauthenticated states remain fail-closed and count against quota. See [artifacts](artifacts.md) and [autonomous rewrites and transactions](transactions.md).
|
|
29
30
|
- Installed-game and external-workspace font files are read locally and are never published as raw MCP resources or redistributed by this package. Their glyph outlines or bounded BMFont atlas crops may appear inside an authorized generated review artifact. Portable fixtures and tool-owned artifact labels use the pinned Roboto package under OFL-1.1; unavailable workspace glyph data is visibly classified as an approximation rather than delegated to a host font.
|
|
30
31
|
- Local external integration depends on environment-provided paths and is not a substitute for portable CI.
|
|
31
32
|
- The server never launches, automates, controls, or captures Hearts of Iron IV. Offline previews are not game screenshots and do not prove in-engine rendering or gameplay behavior.
|
package/docs/map-workflow.md
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
# Agent Nudger map workflow
|
|
2
2
|
|
|
3
|
-
Agent Nudger is a headless declarative map
|
|
3
|
+
Agent Nudger is a headless declarative map rewrite service for coding agents. HTML/PNG/JSON maps are inspection evidence, not a manual editor.
|
|
4
4
|
|
|
5
5
|
## Indexed sources
|
|
6
6
|
|
|
@@ -8,14 +8,14 @@ The shared scan connects province bitmap and definitions, states, strategic regi
|
|
|
8
8
|
|
|
9
9
|
## Geometry input
|
|
10
10
|
|
|
11
|
-
Province geometry
|
|
11
|
+
Province geometry rewrite requires one exact representation:
|
|
12
12
|
|
|
13
13
|
- selected existing province IDs;
|
|
14
14
|
- polygon with integer raster-boundary coordinates and explicit `fillRule: "even-odd"`;
|
|
15
15
|
- raster mask manifest with dimensions, origin, exact selected-pixel count, SHA-256, and canonical Base64 data;
|
|
16
16
|
- explicit absolute pixel region (`kind: pixels`).
|
|
17
17
|
|
|
18
|
-
Natural-language descriptions can guide a coding agent, but are not accepted as
|
|
18
|
+
Natural-language descriptions can guide a coding agent, but are not accepted as rewrite geometry.
|
|
19
19
|
|
|
20
20
|
Polygon vertices describe raster cell boundaries, not pixel indices. For a raster of `width` by `height`, every vertex must use an integer `x` from `0` through `width` and an integer `y` from `0` through `height`; the right and bottom boundary values `width` and `height` are valid. A greater coordinate is rejected with `MAP_GEOMETRY_OUT_OF_BOUNDS` before bounding-box or raster-work allocation, and polygon geometry is never silently clipped. Rasterization samples each candidate pixel at its center, `(x + 0.5, y + 0.5)`, using the required even-odd fill rule. Every selected center must still belong to the declared source province.
|
|
21
21
|
|
|
@@ -33,7 +33,7 @@ Split/merge/move operations do not guess manpower, resources, buildings, victory
|
|
|
33
33
|
- exact manifest values;
|
|
34
34
|
- block until resolved.
|
|
35
35
|
|
|
36
|
-
Proportional rounding is deterministic and checked for conservation. The
|
|
36
|
+
Proportional rounding is deterministic and checked for conservation. The rewrite remains blocked while any required policy is unresolved.
|
|
37
37
|
|
|
38
38
|
State move, split, and merge manifests also declare `ports`, `supplyNodes`, `railways`, and `positions` as `follow-province`. Those records are keyed by a selected province or its state association, so their source bytes remain unchanged except for the already modelled state-ID field on applicable position rows. The explicit literals make that behavior reviewable and prevent a partial distribution object from silently choosing it.
|
|
39
39
|
|
|
@@ -45,11 +45,11 @@ New states require an explicit name localisation key and a strict `localisation`
|
|
|
45
45
|
|
|
46
46
|
`merge_provinces` and `remove_province` accept arbitrary compatible source IDs; removed IDs do not need to be the highest rows in `definition.csv`. Surviving definitions are compacted deterministically to contiguous IDs from zero in old-ID order. Removed source IDs map to the target's compacted ID, including when the target itself moves downward.
|
|
47
47
|
|
|
48
|
-
The same total old-to-new map is applied
|
|
48
|
+
The same total old-to-new map is applied as one recoverable operation to state membership, victory points, province buildings, strategic regions, special-adjacency endpoints and through-provinces, supply nodes, railways, unit positions, and building-position sea references. Source pixels are repainted with the target color; other province colors and pixels remain unchanged. Reference collisions created by the merge are resolved by the declared sum/deduplicate policy. Definition row order, comments and extra fields, text-file comments, line endings, and source encoding are retained by targeted rewrites. A failed application or post-validation restores every affected file byte-for-byte.
|
|
49
49
|
|
|
50
50
|
Compaction requires an active definition table that is already contiguous from zero and unambiguous by ID and color. The merge also requires every source and target to share province type plus exact state and strategic-region membership; these are refusal cases rather than guessed redistribution.
|
|
51
51
|
|
|
52
|
-
Province split/create manifests explicitly retain existing victory points, province buildings, ports, supply nodes, railways, special adjacencies, positions, and entity locators on the source province while the selected pixels and new ID join the declared state and strategic region. To move connected data to the new province, place the corresponding exact remove/add or update operations after the split in the same ordered
|
|
52
|
+
Province split/create manifests explicitly retain existing victory points, province buildings, ports, supply nodes, railways, special adjacencies, positions, and entity locators on the source province while the selected pixels and new ID join the declared state and strategic region. To move connected data to the new province, place the corresponding exact remove/add or update operations after the split in the same ordered rewrite. Omitting any retention field blocks the split before geometry changes are proposed.
|
|
53
53
|
|
|
54
54
|
## Province type migration
|
|
55
55
|
|
|
@@ -66,7 +66,7 @@ The policy explicitly covers:
|
|
|
66
66
|
- building and unit positions (`retain-if-valid` or `remove`) and entity locators (`retain-at-coordinate`, because type migration does not alter geometry);
|
|
67
67
|
- special adjacency endpoint/through references (`retain-if-valid` or `remove-referencing`).
|
|
68
68
|
|
|
69
|
-
Land-to-water requires removal from the exact indexed state and cannot leave that state without land. Water-to-land requires an explicit existing target state in the same strategic region. Sea targets require `ocean` terrain and continent `0`; lake targets require `lakes` and continent `0`; land targets require a non-water terrain and nonzero continent. Coastal fields and neighboring coastal changes remain exact manifest inputs and are verified by final map validation. Dependency removals and the definition edit share one hash-bound
|
|
69
|
+
Land-to-water requires removal from the exact indexed state and cannot leave that state without land. Water-to-land requires an explicit existing target state in the same strategic region. Sea targets require `ocean` terrain and continent `0`; lake targets require `lakes` and continent `0`; land targets require a non-water terrain and nonzero continent. Coastal fields and neighboring coastal changes remain exact manifest inputs and are verified by final map validation. Dependency removals and the definition edit share one hash-bound journal, so success or automatic failure restoration covers every affected state, definition, network, position, and adjacency file together.
|
|
70
70
|
|
|
71
71
|
When a dependency should move rather than disappear, place the corresponding exact `update_state`, position, supply, railway, or adjacency operation after the type migration in the same ordered manifest. The migration policy removes or retains the old record explicitly; the later operation supplies the new target explicitly.
|
|
72
72
|
|
|
@@ -74,16 +74,22 @@ When a dependency should move rather than disappear, place the corresponding exa
|
|
|
74
74
|
|
|
75
75
|
Special adjacency rows remain declarative `add_adjacency` and `remove_adjacency` operations against the active `default.map` adjacency CSV. Normal topological adjacency is derived only from four-neighbor province bitmap geometry (including horizontal map wrap) and uses separate `add_normal_adjacency` and `remove_normal_adjacency` operations.
|
|
76
76
|
|
|
77
|
-
Every normal-adjacency operation carries unique exact pixel transfers with a coordinate, the province currently owning that pixel, and the destination province. Both requested endpoints and all transfer provinces must exist, every source must match the active raster, and every transfer must involve at least one requested endpoint. Agent Nudger repaints only those 24-bit pixels, rebuilds topology, and
|
|
77
|
+
Every normal-adjacency operation carries unique exact pixel transfers with a coordinate, the province currently owning that pixel, and the destination province. Both requested endpoints and all transfer provinces must exist, every source must match the active raster, and every transfer must involve at least one requested endpoint. Agent Nudger repaints only those 24-bit pixels, rebuilds topology, and restores the operation unless the requested pair is present after an add or absent after a remove. Related coastal-definition changes remain explicit ordered operations in the same rewrite.
|
|
78
78
|
|
|
79
79
|
## Allocation
|
|
80
80
|
|
|
81
81
|
ID/color allocation scans current game, dependencies, and mod sources first, including the definition table selected by each root's own `default.map` even when its filename differs from the active table. It records per-file/root maxima, used ranges, active definition contiguity, collisions, reserved values, selected value/color, and source revision. Explicit values are checked against the same evidence. A lower-root ID/color collision is returned as a named dependency conflict on the manifest operation that requested it. The allocator never assumes the numerically next value is safe.
|
|
82
82
|
|
|
83
|
+
## Autonomous rewrite
|
|
84
|
+
|
|
85
|
+
With `writePolicy: "autonomous"`, submit the complete ordered operation manifest once to `hoi4.map_rewrite`. The tool scans dependencies, resolves exact geometry and policies, renders baseline/proposed/diff evidence, validates, journals exact before-bytes, applies all affected text and binary files under the workspace lock, rescans, and post-validates. `execution: "applied"` means the final hashes and validation passed. A blocked proposal reports `execution: "blocked"` and changes nothing; a valid no-change request reports `execution: "unchanged"`; a failure after replacement begins restores every affected file automatically.
|
|
86
|
+
|
|
87
|
+
No transaction tools are registered in autonomous mode. The optional `"transactions"` compatibility policy exposes `hoi4.map_plan` followed by the separate diff/apply/status/rollback tools, using the same internal journal and recovery engine.
|
|
88
|
+
|
|
83
89
|
## Artifacts and validation
|
|
84
90
|
|
|
85
91
|
Map base layers cover province, state, strategic region, terrain, continent, owner, controller, cores, claims, and coast. Overlays cover coastlines, ports, victory points, resources, state buildings, province buildings, supply nodes, railways, special adjacencies, building positions, unit positions, and weather positions. Resource/building data is present in canonical JSON as exact sorted state/province maps as well as deterministic PNG markers; HTML embeds the same JSON and PNG with pan/zoom controls. Render loops honor cancellation signals.
|
|
86
92
|
|
|
87
|
-
Every map preflight stores three content-addressed PNG/JSON/HTML triplets: baseline (`map-before.*`), proposed (`map-proposed.*`), and changed-pixel/semantic diff (`map-diff.*`). Their links and content hashes are included in the
|
|
93
|
+
Every map preflight stores three content-addressed PNG/JSON/HTML triplets: baseline (`map-before.*`), proposed (`map-proposed.*`), and changed-pixel/semantic diff (`map-diff.*`). Their links and content hashes are included in the internal plan hash. Semantic diff JSON includes definitions, state/region membership, full state values (manpower, category, resources, owner/controller, cores/claims, VPs, state/province buildings, and derived capital), ports, building/unit/weather positions, entity locators, supply, railways, exact special-adjacency records, and exact bitmap-derived normal-adjacency pairs.
|
|
88
94
|
|
|
89
95
|
Validation detects duplicate IDs/colors, bitmap-definition mismatches, invalid references, unassigned/multi-state land, invalid derived capitals/VPs/ports/regions/adjacency/supply/rail/placements, removed references, coast inconsistencies, duplicate state IDs, missing localisation, ownership/control conflicts, lost payload, changes outside declared bounds, and dependency conflicts. Geometry review includes disconnected components, one-pixel corridors, and enclosed province holes. Hole detection uses one bounded digital-topology pass and reports `MAP_PROVINCE_HOLE_REVIEW` as a warning because intentional enclaves can be valid; provinces crossing the horizontally wrapping seam are excluded from planar hole classification. Baseline comparisons diagnose dimensions, file/DIB header, row orientation, pixel offset, bit depth, and palette changes separately. Sea and legitimate lake/island cases are not misclassified as missing state membership.
|
package/docs/performance.md
CHANGED
|
@@ -75,7 +75,7 @@ The benchmark changes only the copied fixture's modification time and confirms t
|
|
|
75
75
|
- metadata-only rescan/cache hit: 5.431 ms;
|
|
76
76
|
- same-size, same-mtime content change/rescan: 20.300 ms.
|
|
77
77
|
|
|
78
|
-
The deterministic unit test in `tests/unit/core-cache.test.ts` continuously checks this correctness property without asserting timing.
|
|
78
|
+
The deterministic unit test in `tests/unit/core-cache.test.ts` continuously checks this correctness property without asserting timing. Autonomous rewrites and reviewed transaction apply/rollback paths all invalidate the workspace cache; the content-derived revision remains the safety backstop for external edits.
|
|
79
79
|
|
|
80
80
|
The Scripted GUI Studio and Agent Nudger benchmark paths currently rebuild their domain scans/indexes on each call. Their warm figures therefore reflect runtime/JIT and operating-system cache effects rather than a domain-level memoization claim. Stored artifacts are content-addressed, but artifact storage is not treated as a parsed-source cache.
|
|
81
81
|
|
package/docs/release.md
CHANGED
|
@@ -59,7 +59,7 @@ stable package is published, the normal strict stable-version monotonic and exac
|
|
|
59
59
|
## Immutable fix-forward history
|
|
60
60
|
|
|
61
61
|
Stable tags and public package versions are never moved, deleted, or overwritten after a failed
|
|
62
|
-
release attempt. The retained history
|
|
62
|
+
release attempt. The retained history is:
|
|
63
63
|
|
|
64
64
|
- `v0.1.0` stopped during prepublication validation, before any public writer ran;
|
|
65
65
|
- `v0.1.1` stopped before npm accepted bytes because npm interpreted a slash-containing relative
|
|
@@ -86,14 +86,16 @@ release attempt. The retained history before the `0.1.7` candidate is:
|
|
|
86
86
|
the pinned official schema defines false as that field's default and every public object passed
|
|
87
87
|
its preceding publication gate. All public objects remain unchanged as audit evidence.
|
|
88
88
|
- `v0.1.6` completed the ordered workflow and independent verification across npm, GHCR, the
|
|
89
|
-
immutable GitHub Release, and the official MCP Registry.
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
89
|
+
immutable GitHub Release, and the official MCP Registry.
|
|
90
|
+
- `v0.1.7` completed the same ordered workflow with agent-first persistent setup guidance, large
|
|
91
|
+
focus-tree review scaling, symbolic focus-cost preservation, and complete resource-backed focus
|
|
92
|
+
validation. Its exact public evidence is retained in
|
|
93
|
+
[the 0.1.7 completion report](completion-report.md).
|
|
94
|
+
|
|
95
|
+
`0.2.0` is the current strictly monotonic release candidate. The normal stable-version gate treats
|
|
96
|
+
public `0.1.7` as immutable history; only a strictly newer version may be published. Rerunning or fixing a
|
|
97
|
+
release never authorizes rewriting a tag, package version, image tag, release asset, or Registry
|
|
98
|
+
version.
|
|
97
99
|
|
|
98
100
|
## Required pre-tag immutability check
|
|
99
101
|
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
# MCP protocol, SDK, security, and Registry review
|
|
2
2
|
|
|
3
|
-
Verified 2026-07-
|
|
3
|
+
Verified again on 2026-07-12 against official sources.
|
|
4
4
|
|
|
5
5
|
## Selected production baseline
|
|
6
6
|
|
|
@@ -17,10 +17,16 @@ The breaking `2026-07-28` protocol and SDK v2 split packages were release candid
|
|
|
17
17
|
- Stdio uses newline-delimited UTF-8 JSON-RPC, protocol-only stdout, and stderr logging.
|
|
18
18
|
- Streamable HTTP uses one `/mcp` POST/GET endpoint plus DELETE for session termination. It is stateful to support progress, cancellation, server notifications, SSE resumption, and secure random sessions.
|
|
19
19
|
- Sessions are bound to authenticated principals and expire; they are never authentication credentials.
|
|
20
|
-
- Tools use strict schemas and explicit read-only/destructive/idempotent/open-world annotations. Hints do not replace enforcement.
|
|
20
|
+
- Tools use strict schemas and explicit read-only/destructive/idempotent/open-world annotations. Hints do not replace enforcement and do not require a client to show a confirmation prompt for each call.
|
|
21
21
|
- Long work observes `AbortSignal` and sends monotonic progress only when the client supplies a progress token.
|
|
22
22
|
- Large results are content-addressed resources. Binary reads are bounded/chunkable because resource links defer retrieval but are not a byte-stream transport.
|
|
23
|
-
- Prompts describe
|
|
23
|
+
- Prompts describe domain workflows but grant no permission.
|
|
24
|
+
|
|
25
|
+
### Write-policy conclusion
|
|
26
|
+
|
|
27
|
+
MCP separates server-advertised tool metadata from client-host policy. A server can truthfully mark a source-changing tool with `readOnlyHint: false` and `destructiveHint: true`, but it cannot require, suppress, or bypass a host confirmation dialog. The host decides how to present or constrain the call; the server independently enforces its configured workspace, authentication, scope, validation, journaling, and recovery boundaries.
|
|
28
|
+
|
|
29
|
+
For this server, `writePolicy: "autonomous"` therefore exposes one-call `hoi4.focus_rewrite`, `hoi4.gui_rewrite`, and `hoi4.map_rewrite` tools with destructive annotations. The tools internally plan, validate, journal, apply, and post-validate, restoring original bytes on failure. Transaction tools are not registered in that mode. `writePolicy: "transactions"` remains an optional compatibility surface for the older client-driven review/apply sequence, while `read-only` remains the default.
|
|
24
30
|
|
|
25
31
|
## Remote security requirements applied
|
|
26
32
|
|
package/docs/security.md
CHANGED
|
@@ -4,13 +4,13 @@
|
|
|
4
4
|
|
|
5
5
|
- external mod source and binary map data;
|
|
6
6
|
- installed game and dependency references;
|
|
7
|
-
-
|
|
7
|
+
- configured write authority, authenticated journals, and exact recovery blobs;
|
|
8
8
|
- generated artifacts that may reveal source details;
|
|
9
9
|
- HTTP credentials and principal/workspace grants.
|
|
10
10
|
|
|
11
11
|
## Trust boundaries
|
|
12
12
|
|
|
13
|
-
MCP input, file paths, manifest content, client annotations, session IDs, Origin/Host headers, and remote access tokens are untrusted. Tool annotations are descriptive hints. Prompts are guidance. Server-side
|
|
13
|
+
MCP input, file paths, manifest content, client annotations, session IDs, Origin/Host headers, and remote access tokens are untrusted. Tool annotations are descriptive hints. Prompts are guidance. MCP does not require a confirmation prompt for every destructive tool call. Server-side configuration is authoritative for server access, while the MCP host independently controls its own approval and filesystem policy; neither can override the other.
|
|
14
14
|
|
|
15
15
|
## Filesystem controls
|
|
16
16
|
|
|
@@ -19,7 +19,7 @@ MCP input, file paths, manifest content, client annotations, session IDs, Origin
|
|
|
19
19
|
- Traversal, absolute paths, UNC/device paths, NULs, alternate data streams, ambiguous trailing characters, and device names are rejected.
|
|
20
20
|
- Existing symlinks and junctions are resolved; an escape outside the root is rejected.
|
|
21
21
|
- Artifact shards, transaction journals, blobs, and lock descendants are re-canonicalized before access. A symlink or junction observed in artifact/journal enumeration is rejected.
|
|
22
|
-
-
|
|
22
|
+
- Each write-enabled policy requires an absolute `serverStateRoot` whose existing components are non-linked
|
|
23
23
|
and whose canonical target does not overlap any source, registration capability,
|
|
24
24
|
generated-storage root, or runtime-nominated root. Harmless native path-spelling aliases are
|
|
25
25
|
normalized only after the link check. Its random journal key and protected revision heads are
|
|
@@ -40,7 +40,13 @@ concurrent mutation.
|
|
|
40
40
|
|
|
41
41
|
## Write controls
|
|
42
42
|
|
|
43
|
-
Read-only is the default.
|
|
43
|
+
Read-only is the default. The recommended `"autonomous"` policy exposes only `hoi4.focus_rewrite`, `hoi4.gui_rewrite`, and `hoi4.map_rewrite` for source mutation. Each call computes the complete affected-file set, validates proposed bytes, persists an authenticated journal and exact before-bytes, rechecks the unexpired principal/workspace binding and source hashes under a workspace lock, applies, rebuilds the index, and post-validates. Invalid proposals do not apply; an application, final-hash, or post-validation failure restores original bytes automatically.
|
|
44
|
+
|
|
45
|
+
The optional `"transactions"` compatibility policy exposes the older plan/diff/apply/status/rollback tool sequence. It uses the same core journal and failure-recovery path. Autonomous mode intentionally does not register the transaction tools, so it has no client-callable bypass around the one-call rewrite contract.
|
|
46
|
+
|
|
47
|
+
The autonomous rewrite tools advertise `destructiveHint: true` because a successful call changes mod source. That hint is truthful risk metadata, not a server request to suppress or force a dialog. A client host may prompt for or block the call; the server cannot override it. There is no command-execution field in either mode, and stale or cross-workspace writes fail closed.
|
|
48
|
+
|
|
49
|
+
Git remains the project-history and intentional-revert layer. It is not required for operational recovery: the journal and exact before-bytes prevent a failed multi-file rewrite from remaining partially applied.
|
|
44
50
|
|
|
45
51
|
Runtime registration definitions and raw paths are not persisted. The canonical artifact root does
|
|
46
52
|
retain an atomically created ownership claim containing only domain-separated SHA-256 workspace and
|
|
@@ -63,7 +69,7 @@ valid manifest. A cache-first crash may reconcile only an authenticated exact ne
|
|
|
63
69
|
missing head, revision gap, altered expiry/state/failure/rollback field, or recomputed public hash
|
|
64
70
|
fails closed. No HMAC key is derived from public workspace data.
|
|
65
71
|
|
|
66
|
-
Read-only
|
|
72
|
+
Read-only journal/resource operations never repair protected state. Cache-first successor promotion is
|
|
67
73
|
confined to startup recovery and authorized write paths. Artifact manifests are capped at 1 MiB and
|
|
68
74
|
transaction manifests at 16 MiB before parsing; transaction resource ranges use a bounded verified
|
|
69
75
|
byte cache instead of repeatedly rebuilding the authenticated object.
|
|
@@ -129,7 +135,7 @@ root ACL for the dedicated server account; the server still rejects a linked/non
|
|
|
129
135
|
inherits that operator ACL. A hostile operating-system principal that can read the key or replace
|
|
130
136
|
state-root entries remains outside the documented filesystem trust boundary.
|
|
131
137
|
|
|
132
|
-
Raw installed-game or dependency sprite, font, and bitmap files are never registered as downloadable resources. Structured JSON evidence strips embedded raster and glyph payloads, retaining only source-linked hashes, paths, frame and dimension metadata. Composite SVG/PNG reviews may contain processed frames or glyphs required to inspect the requested render, but remain generated, authorization-checked workspace evidence rather than raw asset-file resources.
|
|
138
|
+
Raw installed-game or dependency sprite, font, and bitmap files are never registered as downloadable resources. Structured JSON evidence strips embedded raster and glyph payloads, retaining only source-linked hashes, paths, frame and dimension metadata. Composite SVG/PNG reviews may contain processed frames or glyphs required to inspect the requested render, but remain generated, authorization-checked workspace evidence rather than raw asset-file resources. Rewrite and reviewed-transaction evidence may contain authorized mod-source before/proposed text and diffs; every artifact remains bound to the workspace principal.
|
|
133
139
|
|
|
134
140
|
The runtime sends no telemetry or analytics. Its only outbound network request is OAuth JWT-key retrieval from the administrator-configured JWKS endpoint; stdio and static-token loopback deployments require no runtime network access.
|
|
135
141
|
|
package/docs/self-hosting.md
CHANGED
|
@@ -51,7 +51,9 @@ Public mode—either a non-loopback listener or a non-loopback `publicUrl` in fr
|
|
|
51
51
|
}
|
|
52
52
|
```
|
|
53
53
|
|
|
54
|
-
The server is an OAuth resource server, not an authorization server. Protected Resource Metadata is served at the standard well-known paths and its endpoint-specific URL is included in 401 and insufficient-scope 403 challenges. Baseline access uses the configured `requiredScopes`;
|
|
54
|
+
The server is an OAuth resource server, not an authorization server. Protected Resource Metadata is served at the standard well-known paths and its endpoint-specific URL is included in 401 and insufficient-scope 403 challenges. Baseline access uses the configured `requiredScopes`; runtime registration and every source-mutation tool additionally require `hoi4:write`. In autonomous mode that means `hoi4.focus_rewrite`, `hoi4.gui_rewrite`, and `hoi4.map_rewrite`; in compatibility mode it includes planning, apply, and rollback. Each MCP session is bound to the exact bearer credential that initialized it, not only to mutable subject/client claims. A refreshed or step-up token must initialize a new MCP session; the previous session remains bound to its original credential and expires no later than that credential's `exp`. The server retains only a SHA-256 credential identifier, never the raw token. Static-token sessions keep the configured sliding inactivity lifetime. Terminate TLS at a trusted reverse proxy, preserve Authorization/Origin/Host headers, and do not make a session ID a bearer credential.
|
|
55
|
+
|
|
56
|
+
`hoi4:write` authorizes the server-side capability; it does not dictate the MCP host's user-interaction policy. Autonomous rewrite tools advertise `destructiveHint: true`, but MCP does not require a prompt for every such call. The server cannot override a host that prompts for or blocks it.
|
|
55
57
|
|
|
56
58
|
### Reverse-proxy boundary
|
|
57
59
|
|
|
@@ -110,7 +112,7 @@ releases the ordinary request-concurrency slot. Each session retains at most 1,0
|
|
|
110
112
|
`sessionTtlSeconds`. Old per-session history is evicted first. A new event that cannot fit the
|
|
111
113
|
shared budget is not retained for replay and does not evict another session's history.
|
|
112
114
|
|
|
113
|
-
Principal grants isolate tool, resource, session, and
|
|
115
|
+
Principal grants isolate tool, resource, session, and journal access within one deployment. Run separate least-privilege server instances or containers for mutually distrustful teams or operating-system trust domains; do not treat application-level grants as an OS sandbox.
|
|
114
116
|
|
|
115
117
|
Runtime registration has two operator capabilities. `registrationRoots` permits read-only source
|
|
116
118
|
selection. A caller-declared mod root additionally must be under the default-empty
|
|
@@ -121,14 +123,14 @@ these capability roots to that principal; prefer static registrations or separat
|
|
|
121
123
|
mutually distrustful users.
|
|
122
124
|
|
|
123
125
|
Runtime artifact storage must support same-volume hard links so the server can create persistent
|
|
124
|
-
owner claims without replacement races.
|
|
126
|
+
owner claims without replacement races. Every write-enabled deployment additionally requires an isolated,
|
|
125
127
|
persistent `serverStateRoot` on a filesystem with hard-link and atomic-replacement support. Do not
|
|
126
128
|
place it beneath any source, capability, artifact, cache, fixture, or `storageRoots` directory.
|
|
127
129
|
|
|
128
130
|
## Container
|
|
129
131
|
|
|
130
132
|
```bash
|
|
131
|
-
docker build -t hoi4-agent-tools:0.
|
|
133
|
+
docker build -t hoi4-agent-tools:0.2.0 .
|
|
132
134
|
docker run --read-only --rm -p 127.0.0.1:3210:3210 \
|
|
133
135
|
-e HOI4_AGENT_CONFIG=/config/config.json \
|
|
134
136
|
-v /srv/hoi4/config:/config:ro \
|
|
@@ -136,7 +138,7 @@ docker run --read-only --rm -p 127.0.0.1:3210:3210 \
|
|
|
136
138
|
-v /srv/hoi4/workspaces:/srv/hoi4/workspaces \
|
|
137
139
|
-v /var/lib/hoi4-agent-tools:/var/lib/hoi4-agent-tools \
|
|
138
140
|
-v /var/lib/hoi4-agent-tools-state:/var/lib/hoi4-agent-tools-state \
|
|
139
|
-
hoi4-agent-tools:0.
|
|
141
|
+
hoi4-agent-tools:0.2.0
|
|
140
142
|
```
|
|
141
143
|
|
|
142
144
|
Port publishing reaches the container through a non-loopback interface. The mounted configuration
|
|
@@ -146,7 +148,7 @@ Terminate TLS at the configured reverse proxy. Mapping the host port only to `12
|
|
|
146
148
|
exposure but does not turn the container-side listener into loopback, so it does not permit static
|
|
147
149
|
bearer tokens.
|
|
148
150
|
|
|
149
|
-
When writes are enabled, set `serverStateRoot` to `/var/lib/hoi4-agent-tools-state` in this example.
|
|
151
|
+
When writes are enabled in either autonomous or reviewed mode, set `serverStateRoot` to `/var/lib/hoi4-agent-tools-state` in this example.
|
|
150
152
|
Keep that mount persistent across restarts and protect it for the dedicated server account. It is a
|
|
151
153
|
separate mount because a state root may not overlap `/var/lib/hoi4-agent-tools` when that path is a
|
|
152
154
|
configured generated-storage capability.
|