hoi4-agent-tools 3.1.0 → 3.3.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (74) hide show
  1. package/CHANGELOG.md +16 -0
  2. package/README.md +10 -2
  3. package/dist/hoi4_agent_tools/core/analysis-evidence.js +9 -0
  4. package/dist/hoi4_agent_tools/core/analysis-job-operations.js +48 -0
  5. package/dist/hoi4_agent_tools/core/condition-evaluator.js +21 -1
  6. package/dist/hoi4_agent_tools/core/impact-comparison.js +49 -0
  7. package/dist/hoi4_agent_tools/core/impact-graph.js +301 -0
  8. package/dist/hoi4_agent_tools/core/impact-semantic.js +256 -0
  9. package/dist/hoi4_agent_tools/core/job-worker-host.js +5 -0
  10. package/dist/hoi4_agent_tools/core/job-worker.js +2 -0
  11. package/dist/hoi4_agent_tools/core/operation-tasks.js +12 -0
  12. package/dist/hoi4_agent_tools/core/scenario-model.js +85 -0
  13. package/dist/hoi4_agent_tools/core/source-overlay.js +125 -0
  14. package/dist/hoi4_agent_tools/decision/ai.js +104 -0
  15. package/dist/hoi4_agent_tools/decision/comparison.js +106 -0
  16. package/dist/hoi4_agent_tools/decision/cost.js +177 -0
  17. package/dist/hoi4_agent_tools/decision/evaluation.js +256 -0
  18. package/dist/hoi4_agent_tools/decision/lifecycle.js +114 -0
  19. package/dist/hoi4_agent_tools/decision/service.js +172 -0
  20. package/dist/hoi4_agent_tools/decision/source-inventory.js +182 -0
  21. package/dist/hoi4_agent_tools/gui/scenario-conditions.js +2 -23
  22. package/dist/hoi4_agent_tools/impact/scenario-suites.js +74 -0
  23. package/dist/hoi4_agent_tools/impact/service.js +127 -0
  24. package/dist/hoi4_agent_tools/mcp/server/create.js +2 -0
  25. package/dist/hoi4_agent_tools/mcp/server/instructions.js +1 -1
  26. package/dist/hoi4_agent_tools/mcp/server/request-lifecycle.js +5 -0
  27. package/dist/hoi4_agent_tools/mcp/server/task-tool-catalog.js +2 -0
  28. package/dist/hoi4_agent_tools/mcp/tools/analysis.js +155 -0
  29. package/dist/hoi4_agent_tools/mechanic/assertions.js +112 -0
  30. package/dist/hoi4_agent_tools/mechanic/interpreter.js +619 -0
  31. package/dist/hoi4_agent_tools/mechanic/service.js +145 -0
  32. package/dist/hoi4_agent_tools/mechanic/source.js +89 -0
  33. package/dist/hoi4_agent_tools/package-check/service.js +231 -0
  34. package/dist/hoi4_agent_tools/probability/evaluation.js +3 -1
  35. package/dist/hoi4_agent_tools/scenario-suite/service.js +341 -0
  36. package/dist/hoi4_agent_tools/schemas/analysis.js +228 -0
  37. package/dist/hoi4_agent_tools/schemas/scenarios.js +264 -0
  38. package/dist/hoi4_agent_tools/version.js +1 -1
  39. package/docs/README.md +2 -0
  40. package/docs/analysis.md +100 -0
  41. package/docs/jobs.md +2 -1
  42. package/docs/mechanics.md +70 -0
  43. package/package.json +6 -2
  44. package/schemas/configuration.schema.json +1 -1
  45. package/schemas/continuous-focus-palette.schema.json +1 -1
  46. package/schemas/custom-weighted-pool.schema.json +1 -1
  47. package/schemas/decision-inspect-input.schema.json +290 -0
  48. package/schemas/event-feature-manifest.schema.json +1 -1
  49. package/schemas/focus-plan.schema.json +1 -1
  50. package/schemas/focus-planning-sidecar.schema.json +1 -1
  51. package/schemas/gui-animation-source.schema.json +1 -1
  52. package/schemas/gui-helper.schema.json +1 -1
  53. package/schemas/gui-scenario.schema.json +1 -1
  54. package/schemas/helper-expansion-request.schema.json +1 -1
  55. package/schemas/helper-expansion-summary.schema.json +1 -1
  56. package/schemas/impact-inspect-input.schema.json +203 -0
  57. package/schemas/map-operation.schema.json +1 -1
  58. package/schemas/mechanic-test-input.schema.json +650 -0
  59. package/schemas/operation-result.schema.json +1 -1
  60. package/schemas/package-check-input.schema.json +164 -0
  61. package/schemas/package-manifest.schema.json +142 -0
  62. package/schemas/probability-analysis-result.schema.json +1 -1
  63. package/schemas/probability-compare-input.schema.json +1 -1
  64. package/schemas/probability-evaluate-input.schema.json +1 -1
  65. package/schemas/probability-inspect-input.schema.json +1 -1
  66. package/schemas/probability-render-input.schema.json +1 -1
  67. package/schemas/probability-scenario-set.schema.json +1 -1
  68. package/schemas/probability-sequence-input.schema.json +1 -1
  69. package/schemas/probability-simulate-input.schema.json +1 -1
  70. package/schemas/probability-sweep-input.schema.json +1 -1
  71. package/schemas/scenario-suite.schema.json +1004 -0
  72. package/schemas/scenario-test-input.schema.json +1057 -0
  73. package/schemas/shared-scenario.schema.json +237 -0
  74. package/server.json +3 -3
@@ -0,0 +1,264 @@
1
+ import { z } from 'zod/v4';
2
+ import { declaredConditionScenarioSchema } from './analysis.js';
3
+ import { workspaceIdSchema, workspaceRelativePathSchema } from './common.js';
4
+ const identifier = z.string().min(1).max(512);
5
+ const manifestToken = z.string().regex(/^[A-Za-z0-9_.:-]{1,512}$/u);
6
+ const sourceSelector = z
7
+ .object({
8
+ kind: z.enum(['scripted_effect', 'event_option', 'decision', 'focus_reward']),
9
+ id: identifier,
10
+ option: identifier.optional(),
11
+ })
12
+ .strict();
13
+ export const sharedScenarioSchema = declaredConditionScenarioSchema.safeExtend({
14
+ schemaVersion: z.literal('1.0'),
15
+ globalFlags: z.array(identifier).max(10_000).optional(),
16
+ scopeCatalogs: z
17
+ .record(identifier, z
18
+ .object({
19
+ complete: z.boolean(),
20
+ members: z.array(identifier).max(2_048),
21
+ })
22
+ .strict())
23
+ .optional(),
24
+ });
25
+ const assertionPath = z
26
+ .object({
27
+ scope: identifier.default('ROOT'),
28
+ key: identifier,
29
+ })
30
+ .strict();
31
+ const scalar = z.union([z.string().max(4_096), z.number(), z.boolean(), z.null()]);
32
+ export const mechanicAssertionSchema = z.discriminatedUnion('kind', [
33
+ z
34
+ .object({ id: identifier, kind: z.literal('equals'), path: assertionPath, expected: scalar })
35
+ .strict(),
36
+ z
37
+ .object({
38
+ id: identifier,
39
+ kind: z.literal('conservation'),
40
+ paths: z.array(assertionPath).min(2).max(64),
41
+ tolerance: z.number().nonnegative().default(0),
42
+ })
43
+ .strict(),
44
+ z
45
+ .object({
46
+ id: identifier,
47
+ kind: z.literal('array_alignment'),
48
+ paths: z.array(assertionPath).min(2).max(32),
49
+ })
50
+ .strict(),
51
+ z
52
+ .object({
53
+ id: identifier,
54
+ kind: z.literal('affordability'),
55
+ balance: assertionPath,
56
+ cost: z.number().nonnegative(),
57
+ })
58
+ .strict(),
59
+ z
60
+ .object({
61
+ id: identifier,
62
+ kind: z.literal('single_payment'),
63
+ balance: assertionPath,
64
+ cost: z.number().nonnegative(),
65
+ })
66
+ .strict(),
67
+ z
68
+ .object({
69
+ id: identifier,
70
+ kind: z.literal('repeated_setup'),
71
+ firstStep: z.number().int().nonnegative(),
72
+ secondStep: z.number().int().nonnegative(),
73
+ })
74
+ .strict(),
75
+ z
76
+ .object({
77
+ id: identifier,
78
+ kind: z.literal('exclusive_flags'),
79
+ scope: identifier.default('ROOT'),
80
+ flags: z.array(identifier).min(2).max(64),
81
+ })
82
+ .strict(),
83
+ z
84
+ .object({
85
+ id: identifier,
86
+ kind: z.literal('cleanup'),
87
+ scope: identifier.default('ROOT'),
88
+ flags: z.array(identifier).max(64).default([]),
89
+ targets: z.array(identifier).max(64).default([]),
90
+ })
91
+ .strict(),
92
+ z
93
+ .object({ id: identifier, kind: z.literal('end_state'), path: assertionPath, expected: scalar })
94
+ .strict(),
95
+ ]);
96
+ export const mechanicCaseSchema = z
97
+ .object({
98
+ id: identifier,
99
+ scenario: sharedScenarioSchema,
100
+ steps: z
101
+ .array(z.discriminatedUnion('kind', [
102
+ z
103
+ .object({
104
+ kind: z.literal('effect'),
105
+ source: sourceSelector,
106
+ repeat: z.number().int().min(1).max(8).default(1),
107
+ })
108
+ .strict(),
109
+ z
110
+ .object({ kind: z.literal('advance_days'), days: z.number().int().min(0).max(36_500) })
111
+ .strict(),
112
+ ]))
113
+ .min(1)
114
+ .max(128),
115
+ assertions: z.array(mechanicAssertionSchema).min(1).max(256),
116
+ })
117
+ .strict();
118
+ export const mechanicTestRequestSchema = z
119
+ .object({
120
+ workspaceId: workspaceIdSchema,
121
+ test: mechanicCaseSchema,
122
+ expectedRevision: z
123
+ .string()
124
+ .regex(/^[a-f0-9]{64}$/u)
125
+ .optional(),
126
+ refresh: z.boolean().default(false),
127
+ })
128
+ .strict();
129
+ const manifestItem = z.object({ kind: manifestToken, id: manifestToken }).strict();
130
+ export const packageManifestSchema = z
131
+ .object({
132
+ schemaVersion: z.literal('1.0'),
133
+ id: manifestToken,
134
+ definitions: z.array(manifestItem).max(2_048).default([]),
135
+ calls: z
136
+ .array(z.object({ from: manifestItem, to: manifestItem }).strict())
137
+ .max(2_048)
138
+ .default([]),
139
+ registrations: z
140
+ .array(z.object({ path: workspaceRelativePathSchema, token: manifestToken }).strict())
141
+ .max(2_048)
142
+ .default([]),
143
+ localisation: z.array(manifestToken).max(2_048).default([]),
144
+ assets: z.array(workspaceRelativePathSchema).max(2_048).default([]),
145
+ requiredCases: z
146
+ .array(z.object({ suite: workspaceRelativePathSchema, caseId: manifestToken }).strict())
147
+ .max(512)
148
+ .default([]),
149
+ })
150
+ .strict();
151
+ export const packageCheckRequestSchema = z
152
+ .object({
153
+ workspaceId: workspaceIdSchema,
154
+ manifest: packageManifestSchema,
155
+ expectedRevision: z
156
+ .string()
157
+ .regex(/^[a-f0-9]{64}$/u)
158
+ .optional(),
159
+ refresh: z.boolean().default(false),
160
+ })
161
+ .strict();
162
+ const readOnlySuiteTool = z.enum([
163
+ 'hoi4.impact_inspect',
164
+ 'hoi4.decision_inspect',
165
+ 'hoi4.event_inspect',
166
+ 'hoi4.event_render',
167
+ 'hoi4.tech_inspect',
168
+ 'hoi4.tech_render',
169
+ 'hoi4.probability_inspect',
170
+ 'hoi4.probability_evaluate',
171
+ 'hoi4.probability_render',
172
+ 'hoi4.focus_inspect',
173
+ 'hoi4.focus_render',
174
+ 'hoi4.gui_inspect',
175
+ 'hoi4.gui_render',
176
+ 'hoi4.map_inspect',
177
+ 'hoi4.map_render',
178
+ ]);
179
+ const suiteCaseMetadata = {
180
+ sourceSelectors: z.array(manifestItem).max(64).default([]),
181
+ assertions: z
182
+ .array(z
183
+ .object({
184
+ id: identifier,
185
+ path: z.array(identifier).min(1).max(16),
186
+ expected: scalar,
187
+ })
188
+ .strict())
189
+ .max(64)
190
+ .default([]),
191
+ views: z
192
+ .array(z.enum(['summary', 'artifacts', 'diagnostics']))
193
+ .max(3)
194
+ .default(['summary']),
195
+ };
196
+ export const scenarioSuiteSchema = z
197
+ .object({
198
+ schemaVersion: z.literal('1.0'),
199
+ id: identifier,
200
+ cases: z
201
+ .array(z.discriminatedUnion('domain', [
202
+ z
203
+ .object({
204
+ domain: z.literal('mechanic'),
205
+ id: identifier,
206
+ test: mechanicCaseSchema,
207
+ ...suiteCaseMetadata,
208
+ })
209
+ .strict(),
210
+ z
211
+ .object({
212
+ domain: z.literal('package'),
213
+ id: identifier,
214
+ manifest: packageManifestSchema,
215
+ ...suiteCaseMetadata,
216
+ })
217
+ .strict(),
218
+ z
219
+ .object({
220
+ domain: z.literal('tool'),
221
+ id: identifier,
222
+ tool: readOnlySuiteTool,
223
+ arguments: z.record(z.string().max(256), z.json()),
224
+ ...suiteCaseMetadata,
225
+ })
226
+ .strict(),
227
+ ]))
228
+ .min(1)
229
+ .max(10_000),
230
+ })
231
+ .strict()
232
+ .superRefine((suite, context) => {
233
+ const ids = new Set();
234
+ for (const [index, item] of suite.cases.entries()) {
235
+ if (ids.has(item.id))
236
+ context.addIssue({
237
+ code: 'custom',
238
+ path: ['cases', index, 'id'],
239
+ message: 'Suite case ids must be unique',
240
+ });
241
+ ids.add(item.id);
242
+ }
243
+ });
244
+ export const scenarioTestRequestSchema = z
245
+ .object({
246
+ workspaceId: workspaceIdSchema,
247
+ suite: scenarioSuiteSchema.optional(),
248
+ suitePath: workspaceRelativePathSchema.optional(),
249
+ continuation: z.string().max(4_096).optional(),
250
+ maxCases: z.number().int().min(1).max(256).default(32),
251
+ expectedRevision: z
252
+ .string()
253
+ .regex(/^[a-f0-9]{64}$/u)
254
+ .optional(),
255
+ refresh: z.boolean().default(false),
256
+ })
257
+ .strict()
258
+ .superRefine((input, context) => {
259
+ if ((input.suite === undefined) === (input.suitePath === undefined))
260
+ context.addIssue({
261
+ code: 'custom',
262
+ message: 'Specify exactly one inline suite or suitePath',
263
+ });
264
+ });
@@ -1,6 +1,6 @@
1
1
  import { LATEST_PROTOCOL_VERSION } from '@modelcontextprotocol/sdk/types.js';
2
2
  export const PACKAGE_NAME = 'hoi4-agent-tools';
3
- export const PACKAGE_VERSION = '3.1.0';
3
+ export const PACKAGE_VERSION = '3.3.0';
4
4
  export const MCP_PROTOCOL_VERSION = LATEST_PROTOCOL_VERSION;
5
5
  export const CONFIG_VERSION = 1;
6
6
  export const TRANSACTION_VERSION = 1;
package/docs/README.md CHANGED
@@ -2,6 +2,8 @@
2
2
 
3
3
  - [Setup](setup.md): install the server, configure HOI4 paths, and connect an MCP client.
4
4
  - [Event chains](events.md): inspect, trace, lint, render, and compare event chains.
5
+ - [Cross-system impact and decisions](analysis.md): trace source consumers and evaluate decision or mission scenarios.
6
+ - [Mechanic tests and scenario suites](mechanics.md): interpret declared effect steps, check package links, and run resumable cases.
5
7
  - [Technology trees](technology.md): inspect, trace, lint, render, and compare technologies and doctrines.
6
8
  - [Bounded helper expansion](helper-expansion.md): resume source-linked event and technology helper paths with exact coverage boundaries.
7
9
  - [Persistent jobs](jobs.md): run, inspect, cancel, and recover long operations.
@@ -0,0 +1,100 @@
1
+ # Cross-system impact and decisions
2
+
3
+ `hoi4.impact_inspect` and `hoi4.decision_inspect` analyze authorized HOI4 source without changing it or running the game.
4
+ Both tools return a compact result and a linked JSON report containing source locations, hashes, unresolved cases, and the full analysis.
5
+ They support ordinary calls and persistent MCP tasks through stdio and HTTP.
6
+
7
+ ## Cross-system impact
8
+
9
+ Use a symbol when you know the definition you plan to change:
10
+
11
+ ```json
12
+ {
13
+ "workspaceId": "current",
14
+ "symbols": [{ "kind": "idea", "id": "rationing" }],
15
+ "maxDepth": 12
16
+ }
17
+ ```
18
+
19
+ Use `changedFiles` with scanned display paths such as `mod:common/ideas/rationing.txt` to seed every active definition in a file.
20
+ Use `proposedSources` to add, replace, or remove files in memory under the authorized mod root; a `null` content removes a source from the proposed snapshot.
21
+ When `changedFiles` is omitted, each proposed file seeds all its active definitions alongside any selected symbols.
22
+ The report compares the original and proposed consumer graph, including added and removed consumers and affected files.
23
+ Moving a source location within one file does not count an unchanged reference as a new or removed consumer.
24
+ `expectedRevision` prevents analysis against a source revision different from the one the caller reviewed.
25
+ Pass up to 32 workspace-relative JSON paths in `scenarioSuites` to locate cases that declare an affected source selector or scanned display path.
26
+ The tool reads reference metadata only; it never runs a case or its assertions.
27
+
28
+ ```json
29
+ {
30
+ "schemaVersion": "1.0",
31
+ "id": "policy_checks",
32
+ "cases": [
33
+ {
34
+ "id": "rationing_decision",
35
+ "sourceSelectors": [{ "kind": "decision", "id": "ration" }],
36
+ "sourceFiles": ["mod:common/decisions/rationing.txt"]
37
+ }
38
+ ]
39
+ }
40
+ ```
41
+
42
+ The suite can carry additional case fields for a later scenario executor; impact analysis reads only `sourceSelectors` and `sourceFiles`.
43
+ Malformed, missing, or oversized suite files produce explicit partial coverage.
44
+
45
+ The graph includes active and overridden definitions, direct and transitive consumers, source locations, state-key reads and writes, and coverage limits.
46
+ It connects source-backed event, focus, decision, idea, technology, scripted-helper, localisation, GUI, sprite, and texture references where a typed static edge can be established.
47
+ Unresolved dynamic names, missing definitions, skipped sources, cycles, and traversal limits remain explicit in the report.
48
+ An affected file is a source dependency lead, not a claim that the game executed that path.
49
+
50
+ ## Decisions and missions
51
+
52
+ Inventory active decision categories and definitions:
53
+
54
+ ```json
55
+ { "workspaceId": "current", "mode": "inventory" }
56
+ ```
57
+
58
+ Inspect one decision under declared actor and target state:
59
+
60
+ ```json
61
+ {
62
+ "workspaceId": "current",
63
+ "mode": "inspect",
64
+ "id": "fund_relief",
65
+ "scenarios": [
66
+ {
67
+ "id": "actor_and_target",
68
+ "actor": "AAA",
69
+ "state": { "political_power": 30, "treasury": 20 },
70
+ "flags": ["relief_open"],
71
+ "scopes": {
72
+ "FROM": {
73
+ "id": "BBB",
74
+ "type": "country",
75
+ "actor": "BBB",
76
+ "state": {}
77
+ }
78
+ }
79
+ }
80
+ ]
81
+ }
82
+ ```
83
+
84
+ `ROOT` is the actor country and `FROM` is the declared target country or state.
85
+ The inventory lists active decisions, category fragments, overridden source definitions, and each decision's explicit targets, target arrays, state filters, and target trigger declarations.
86
+ Category and decision `allowed`, `visible`, and `available` results remain separate; mission visibility is reported as ignored where documented.
87
+ Target selection covers explicit lists and arrays plus supported state ownership, control, and continent filters.
88
+ When a target, flag, variable, or helper input is unknown, the corresponding gate remains unresolved.
89
+
90
+ Costs distinguish automatic engine political-power payment from a custom affordability trigger and its separate `complete_effect` payment.
91
+ The report identifies direct deductions, possible double payment, missing direct payment, conditional or helper-dependent paths, repeatability, cooldowns, removal, activation, cancellation, and mission timeout paths.
92
+ Removal and cancellation triggers are evaluated under each declared scenario; `cancel_if_not_visible` is evaluated against decision visibility, with unsupported mission visibility left unresolved.
93
+ It does not execute these effects or assert that a campaign reached an outcome.
94
+
95
+ Set `mode` to `compare` and supply `proposedSources` to compare the same scenarios against an in-memory source proposal.
96
+ Decision AI scores use the existing probability service's `decision_ai_will_do` and `mission_ai_will_do` adapters, with linked score traces and unresolved input evidence.
97
+ Those adapters return scores and eligibility; they do not invent selection probabilities.
98
+ When a proposal changes multiple files or adds or removes the weighted definition, the report marks proposed AI scoring unresolved and points to explicit probability comparison.
99
+
100
+ All paths and scenarios are bounded by the public input schema, and artifacts remain subject to workspace and principal authorization.
package/docs/jobs.md CHANGED
@@ -14,9 +14,10 @@ A modern native task handoff ends that request's heartbeat without declaring the
14
14
 
15
15
  ## Supported tools
16
16
 
17
- Optional tasks are available for every read-only event, technology, probability, map, GUI, and focus operation, and for the three rewrite tools:
17
+ Optional tasks are available for every read-only event, impact, decision, technology, probability, map, GUI, and focus operation, and for the three rewrite tools:
18
18
 
19
19
  - `hoi4.event_inspect`, `hoi4.event_render`, and `hoi4.event_compare`
20
+ - `hoi4.impact_inspect` and `hoi4.decision_inspect`
20
21
  - `hoi4.tech_inspect`, `hoi4.tech_render`, and `hoi4.tech_compare`
21
22
  - `hoi4.probability_inspect`, `hoi4.probability_evaluate`, `hoi4.probability_sweep`, `hoi4.probability_simulate`, `hoi4.probability_sequence`, `hoi4.probability_compare`, and `hoi4.probability_render`
22
23
  - `hoi4.map_inspect`, `hoi4.map_render`, and `hoi4.map_rewrite`
@@ -0,0 +1,70 @@
1
+ # Mechanic tests, package checks, and scenario suites
2
+
3
+ `hoi4.mechanic_test`, `hoi4.package_check`, and `hoi4.scenario_test` read authorized HOI4 source and return linked, revision-bound evidence.
4
+ They do not launch the game or change source files.
5
+ Supply `expectedRevision` when continuing analysis against a reviewed scan.
6
+
7
+ ## Test an effect
8
+
9
+ `hoi4.mechanic_test` copies a versioned scenario, selects each active source effect, applies explicit steps, and evaluates typed assertions.
10
+ Source selectors support `scripted_effect`, `event_option`, `decision`, and `focus_reward`; event options also need `option`.
11
+ An `advance_days` step only expires modeled timed flags; it never runs on actions.
12
+
13
+ ```json
14
+ {
15
+ "workspaceId": "current",
16
+ "test": {
17
+ "id": "treasury_transfer",
18
+ "scenario": {
19
+ "schemaVersion": "1.0",
20
+ "id": "treasury_transfer",
21
+ "state": { "treasury": 10, "savings": 2 },
22
+ "closedFlags": true
23
+ },
24
+ "steps": [{ "kind": "effect", "source": { "kind": "scripted_effect", "id": "transfer" } }],
25
+ "assertions": [
26
+ {
27
+ "id": "total_conserved",
28
+ "kind": "conservation",
29
+ "paths": [{ "key": "treasury" }, { "key": "savings" }]
30
+ },
31
+ {
32
+ "id": "single_charge",
33
+ "kind": "single_payment",
34
+ "balance": { "key": "treasury" },
35
+ "cost": 3
36
+ }
37
+ ]
38
+ }
39
+ }
40
+ ```
41
+
42
+ The linked trace records applied, skipped, and unresolved source operations with before and after values.
43
+ The `single_payment` assertion checks the named balance's final change and the number and size of its traced deductions, so a compensating grant cannot hide a second charge.
44
+ Supported operations include documented variable arithmetic, flags, event targets, arrays, conditionals, finite declared scope iteration, scripted helpers, safe meta substitutions, and selected balance effects.
45
+ Decision engine political-power costs are applied once before `complete_effect`; custom cost triggers check affordability and their payment remains in `complete_effect`.
46
+ Unresolved eligibility, unsupported effects, dynamic names that cannot be resolved, missing finite scope catalogs, and bounded-work limits remain unresolved rather than guessed.
47
+ An effect with an unknown write set conservatively makes state assertions unresolved.
48
+ This is source interpretation of declared steps, not campaign simulation.
49
+
50
+ ## Check a package
51
+
52
+ `hoi4.package_check` accepts a declarative manifest with `schemaVersion: "1.0"` and an `id`.
53
+ Add expected `definitions` and `calls` as `{ "kind": "scripted_effect", "id": "transfer" }` selectors, `registrations` as workspace-relative path and token pairs, `localisation` keys, `assets` as workspace-relative paths, and `requiredCases` as suite path and case id pairs.
54
+ The report separates present, absent, shadowed, and unresolved links and includes source hashes and locations.
55
+ Required cases are checked for declaration; run `hoi4.scenario_test` to evaluate them.
56
+ The manifest accepts no source patches or executable commands.
57
+
58
+ ## Run a suite
59
+
60
+ `hoi4.scenario_test` accepts either an inline `suite` or an authorized workspace-relative `suitePath`.
61
+ The suite has `schemaVersion: "1.0"`, an `id`, and named `cases` in the `mechanic`, `package`, or fixed read-only `tool` domain.
62
+ A mechanic case supplies the same `test` as `hoi4.mechanic_test`; a package case supplies a `manifest`.
63
+ A tool case names one allowed inspect, render, or evaluate operation and supplies its typed `arguments`.
64
+ Cases may declare `sourceSelectors`, output path assertions, and `views` (`summary`, `artifacts`, `diagnostics`).
65
+
66
+ Set `maxCases` to bound a batch.
67
+ Each case receives a content-addressed result artifact; the batch returns its counts and, while cases remain, a `continuation`.
68
+ Pass that continuation with the same suite to resume.
69
+ The token is authenticated and bound to the workspace, caller, suite content, and source revision; changed inputs or source require a fresh run.
70
+ Every requested case is reported as completed, failed, unresolved, or pending.
package/package.json CHANGED
@@ -1,8 +1,8 @@
1
1
  {
2
2
  "name": "hoi4-agent-tools",
3
3
  "mcpName": "io.github.klimPaskov/hoi4-agent-tools",
4
- "version": "3.1.0",
5
- "description": "Analyze HOI4 events, tech trees, AI weights, and MTTH; build focus trees, GUIs, and maps.",
4
+ "version": "3.3.0",
5
+ "description": "Analyze HOI4 events, decisions, impact, tech, AI, and MTTH; build focus trees, GUIs, and maps.",
6
6
  "type": "module",
7
7
  "license": "Apache-2.0",
8
8
  "author": "HOI4 Agent Tools contributors",
@@ -22,6 +22,8 @@
22
22
  "clausewitz",
23
23
  "focus-trees",
24
24
  "event-chains",
25
+ "impact-analysis",
26
+ "decisions",
25
27
  "technology-trees",
26
28
  "doctrines",
27
29
  "ai-weights",
@@ -39,6 +41,8 @@
39
41
  "docs/README.md",
40
42
  "docs/setup.md",
41
43
  "docs/events.md",
44
+ "docs/analysis.md",
45
+ "docs/mechanics.md",
42
46
  "docs/technology.md",
43
47
  "docs/probability.md",
44
48
  "docs/research/probability-adapter-evidence.md",
@@ -1,5 +1,5 @@
1
1
  {
2
- "$id": "https://github.com/klimPaskov/hoi4-agent-tools/blob/v3.1.0/schemas/configuration.schema.json",
2
+ "$id": "https://github.com/klimPaskov/hoi4-agent-tools/blob/v3.3.0/schemas/configuration.schema.json",
3
3
  "$schema": "https://json-schema.org/draft/2020-12/schema",
4
4
  "type": "object",
5
5
  "properties": {
@@ -1,5 +1,5 @@
1
1
  {
2
- "$id": "https://github.com/klimPaskov/hoi4-agent-tools/blob/v3.1.0/schemas/continuous-focus-palette.schema.json",
2
+ "$id": "https://github.com/klimPaskov/hoi4-agent-tools/blob/v3.3.0/schemas/continuous-focus-palette.schema.json",
3
3
  "$schema": "https://json-schema.org/draft/2020-12/schema",
4
4
  "type": "object",
5
5
  "properties": {
@@ -1,5 +1,5 @@
1
1
  {
2
- "$id": "https://github.com/klimPaskov/hoi4-agent-tools/blob/v3.1.0/schemas/custom-weighted-pool.schema.json",
2
+ "$id": "https://github.com/klimPaskov/hoi4-agent-tools/blob/v3.3.0/schemas/custom-weighted-pool.schema.json",
3
3
  "$schema": "https://json-schema.org/draft/2020-12/schema",
4
4
  "type": "object",
5
5
  "properties": {