hoi4-agent-tools 3.1.0 → 3.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.
Files changed (57) hide show
  1. package/CHANGELOG.md +9 -0
  2. package/README.md +6 -2
  3. package/dist/hoi4_agent_tools/core/analysis-evidence.js +9 -0
  4. package/dist/hoi4_agent_tools/core/analysis-job-operations.js +38 -0
  5. package/dist/hoi4_agent_tools/core/condition-evaluator.js +16 -0
  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 +2 -0
  10. package/dist/hoi4_agent_tools/core/job-worker.js +2 -0
  11. package/dist/hoi4_agent_tools/core/operation-tasks.js +5 -0
  12. package/dist/hoi4_agent_tools/core/source-overlay.js +125 -0
  13. package/dist/hoi4_agent_tools/decision/ai.js +104 -0
  14. package/dist/hoi4_agent_tools/decision/comparison.js +106 -0
  15. package/dist/hoi4_agent_tools/decision/cost.js +177 -0
  16. package/dist/hoi4_agent_tools/decision/evaluation.js +256 -0
  17. package/dist/hoi4_agent_tools/decision/lifecycle.js +114 -0
  18. package/dist/hoi4_agent_tools/decision/service.js +172 -0
  19. package/dist/hoi4_agent_tools/decision/source-inventory.js +182 -0
  20. package/dist/hoi4_agent_tools/impact/scenario-suites.js +74 -0
  21. package/dist/hoi4_agent_tools/impact/service.js +127 -0
  22. package/dist/hoi4_agent_tools/mcp/server/create.js +2 -0
  23. package/dist/hoi4_agent_tools/mcp/server/instructions.js +1 -1
  24. package/dist/hoi4_agent_tools/mcp/server/request-lifecycle.js +2 -0
  25. package/dist/hoi4_agent_tools/mcp/server/task-tool-catalog.js +2 -0
  26. package/dist/hoi4_agent_tools/mcp/tools/analysis.js +65 -0
  27. package/dist/hoi4_agent_tools/schemas/analysis.js +228 -0
  28. package/dist/hoi4_agent_tools/version.js +1 -1
  29. package/docs/README.md +1 -0
  30. package/docs/analysis.md +100 -0
  31. package/docs/jobs.md +2 -1
  32. package/package.json +5 -2
  33. package/schemas/configuration.schema.json +1 -1
  34. package/schemas/continuous-focus-palette.schema.json +1 -1
  35. package/schemas/custom-weighted-pool.schema.json +1 -1
  36. package/schemas/decision-inspect-input.schema.json +290 -0
  37. package/schemas/event-feature-manifest.schema.json +1 -1
  38. package/schemas/focus-plan.schema.json +1 -1
  39. package/schemas/focus-planning-sidecar.schema.json +1 -1
  40. package/schemas/gui-animation-source.schema.json +1 -1
  41. package/schemas/gui-helper.schema.json +1 -1
  42. package/schemas/gui-scenario.schema.json +1 -1
  43. package/schemas/helper-expansion-request.schema.json +1 -1
  44. package/schemas/helper-expansion-summary.schema.json +1 -1
  45. package/schemas/impact-inspect-input.schema.json +203 -0
  46. package/schemas/map-operation.schema.json +1 -1
  47. package/schemas/operation-result.schema.json +1 -1
  48. package/schemas/probability-analysis-result.schema.json +1 -1
  49. package/schemas/probability-compare-input.schema.json +1 -1
  50. package/schemas/probability-evaluate-input.schema.json +1 -1
  51. package/schemas/probability-inspect-input.schema.json +1 -1
  52. package/schemas/probability-render-input.schema.json +1 -1
  53. package/schemas/probability-scenario-set.schema.json +1 -1
  54. package/schemas/probability-sequence-input.schema.json +1 -1
  55. package/schemas/probability-simulate-input.schema.json +1 -1
  56. package/schemas/probability-sweep-input.schema.json +1 -1
  57. package/server.json +3 -3
@@ -0,0 +1,228 @@
1
+ import { z } from 'zod/v4';
2
+ import { workspaceIdSchema, workspaceRelativePathSchema } from './common.js';
3
+ const symbolKindSchema = z.enum([
4
+ 'focus_tree',
5
+ 'focus',
6
+ 'continuous_focus_palette',
7
+ 'continuous_focus',
8
+ 'decision',
9
+ 'decision_category',
10
+ 'event',
11
+ 'idea',
12
+ 'leader',
13
+ 'formable',
14
+ 'scripted_effect',
15
+ 'scripted_trigger',
16
+ 'script_constant',
17
+ 'mtth_variable',
18
+ 'ai_strategy',
19
+ 'ai_strategy_plan',
20
+ 'sprite',
21
+ 'texture',
22
+ 'gui_element',
23
+ 'scripted_gui',
24
+ 'technology',
25
+ 'technology_folder',
26
+ 'technology_category',
27
+ 'technology_tag',
28
+ 'equipment',
29
+ 'equipment_module',
30
+ 'sub_unit',
31
+ 'unit_category',
32
+ 'building',
33
+ 'ability',
34
+ 'combat_tactic',
35
+ 'doctrine_folder',
36
+ 'grand_doctrine',
37
+ 'doctrine_track',
38
+ 'subdoctrine',
39
+ 'localisation',
40
+ 'variable',
41
+ 'flag',
42
+ 'event_target',
43
+ 'state',
44
+ 'province',
45
+ 'province_color',
46
+ 'strategic_region',
47
+ 'adjacency',
48
+ 'supply_node',
49
+ 'railway',
50
+ ]);
51
+ export const impactSymbolSelectorSchema = z
52
+ .object({
53
+ kind: symbolKindSchema,
54
+ id: z.string().min(1).max(512),
55
+ })
56
+ .strict();
57
+ const sourceDisplayPathSchema = z
58
+ .string()
59
+ .min(1)
60
+ .max(4096)
61
+ .refine((value) => {
62
+ const separator = value.indexOf(':');
63
+ if (separator < 1)
64
+ return false;
65
+ const root = value.slice(0, separator);
66
+ if (!/^(?:mod|game|fixture|dependency-[0-9]+)$/u.test(root))
67
+ return false;
68
+ return workspaceRelativePathSchema.safeParse(value.slice(separator + 1)).success;
69
+ }, 'Use a scanned source display path under an authorized workspace root');
70
+ export const proposedAnalysisSourceSchema = z
71
+ .object({
72
+ relativePath: workspaceRelativePathSchema,
73
+ content: z
74
+ .string()
75
+ .max(8 * 1024 * 1024)
76
+ .nullable(),
77
+ })
78
+ .strict();
79
+ const scenarioScalarSchema = z.union([z.string().max(4096), z.number(), z.boolean(), z.null()]);
80
+ const scenarioValueSchema = z.union([
81
+ scenarioScalarSchema,
82
+ z.array(scenarioScalarSchema).max(10_000),
83
+ ]);
84
+ const scenarioStateSchema = z
85
+ .record(z.string().min(1).max(1024), scenarioValueSchema)
86
+ .refine((state) => Object.keys(state).length <= 10_000, 'Scenario state has too many keys');
87
+ const scopeBindingSchema = z
88
+ .object({
89
+ id: z.string().min(1).max(512),
90
+ type: z
91
+ .enum([
92
+ 'country',
93
+ 'state',
94
+ 'character',
95
+ 'unit_leader',
96
+ 'operative',
97
+ 'strategic_region',
98
+ 'province',
99
+ 'unknown',
100
+ ])
101
+ .optional(),
102
+ actor: z.string().max(256).optional(),
103
+ state: scenarioStateSchema,
104
+ flags: z.array(z.string().min(1).max(512)).max(10_000).optional(),
105
+ eventTargets: z.record(z.string().max(512), z.string().max(512)).optional(),
106
+ weight: z.union([z.number(), z.string().max(1024)]).optional(),
107
+ })
108
+ .strict();
109
+ export const declaredConditionScenarioSchema = z
110
+ .object({
111
+ id: z.string().min(1).max(512),
112
+ actor: z.string().max(256).optional(),
113
+ date: z.string().max(64).optional(),
114
+ state: scenarioStateSchema,
115
+ flags: z.array(z.string().min(1).max(512)).max(10_000).optional(),
116
+ eventTargets: z.record(z.string().max(512), z.string().max(512)).optional(),
117
+ scopes: z
118
+ .record(z.string().min(1).max(128), scopeBindingSchema)
119
+ .refine((scopes) => Object.keys(scopes).length <= 64, 'Too many declared scopes')
120
+ .optional(),
121
+ candidateOverrides: z.record(z.string().max(512), z.boolean()).optional(),
122
+ closedFlags: z.boolean().optional(),
123
+ })
124
+ .strict();
125
+ export const impactInspectRequestSchema = z
126
+ .object({
127
+ workspaceId: workspaceIdSchema,
128
+ symbols: z.array(impactSymbolSelectorSchema).max(64).default([]),
129
+ changedFiles: z.array(sourceDisplayPathSchema).max(64).default([]),
130
+ scenarioSuites: z
131
+ .array(workspaceRelativePathSchema.refine((value) => value.toLowerCase().endsWith('.json'), 'Scenario suite path must name a JSON file'))
132
+ .max(32)
133
+ .default([]),
134
+ proposedSources: z.array(proposedAnalysisSourceSchema).min(1).max(64).optional(),
135
+ maxNodes: z.number().int().min(1).max(50_000).optional(),
136
+ maxEdges: z.number().int().min(1).max(100_000).optional(),
137
+ maxDepth: z.number().int().min(1).max(64).optional(),
138
+ expectedRevision: z
139
+ .string()
140
+ .regex(/^[a-f0-9]{64}$/u)
141
+ .optional(),
142
+ refresh: z.boolean().default(false),
143
+ })
144
+ .strict()
145
+ .superRefine((input, context) => {
146
+ if (input.symbols.length === 0 &&
147
+ input.changedFiles.length === 0 &&
148
+ input.proposedSources === undefined)
149
+ context.addIssue({
150
+ code: 'custom',
151
+ message: 'Impact inspection requires a symbol, changed file, or proposed source',
152
+ });
153
+ });
154
+ export const decisionInspectRequestSchema = z
155
+ .object({
156
+ workspaceId: workspaceIdSchema,
157
+ mode: z.enum(['inventory', 'inspect', 'compare']).default('inventory'),
158
+ id: z.string().min(1).max(512).optional(),
159
+ scenarios: z.array(declaredConditionScenarioSchema).max(64).default([]),
160
+ proposedSources: z.array(proposedAnalysisSourceSchema).min(1).max(64).optional(),
161
+ expectedRevision: z
162
+ .string()
163
+ .regex(/^[a-f0-9]{64}$/u)
164
+ .optional(),
165
+ refresh: z.boolean().default(false),
166
+ })
167
+ .strict()
168
+ .superRefine((input, context) => {
169
+ const ids = new Set();
170
+ for (const [index, scenario] of input.scenarios.entries()) {
171
+ if (ids.has(scenario.id))
172
+ context.addIssue({
173
+ code: 'custom',
174
+ path: ['scenarios', index, 'id'],
175
+ message: 'Scenario IDs must be unique',
176
+ });
177
+ ids.add(scenario.id);
178
+ }
179
+ if (input.mode === 'inventory') {
180
+ if (input.proposedSources !== undefined)
181
+ context.addIssue({
182
+ code: 'custom',
183
+ path: ['proposedSources'],
184
+ message: 'Inventory mode does not accept proposed sources',
185
+ });
186
+ return;
187
+ }
188
+ if (input.id === undefined)
189
+ context.addIssue({
190
+ code: 'custom',
191
+ path: ['id'],
192
+ message: 'Decision inspection requires an identifier',
193
+ });
194
+ if (input.scenarios.length === 0)
195
+ context.addIssue({
196
+ code: 'custom',
197
+ path: ['scenarios'],
198
+ message: 'Decision inspection requires declared scenarios',
199
+ });
200
+ if (input.mode === 'compare' && input.proposedSources === undefined)
201
+ context.addIssue({
202
+ code: 'custom',
203
+ path: ['proposedSources'],
204
+ message: 'Decision comparison requires proposed sources',
205
+ });
206
+ if (input.mode === 'inspect' && input.proposedSources !== undefined)
207
+ context.addIssue({
208
+ code: 'custom',
209
+ path: ['proposedSources'],
210
+ message: 'Use compare mode for proposed sources',
211
+ });
212
+ });
213
+ /** A reference projection of future scenario suites; Stage 3 reads but never executes it. */
214
+ export const impactScenarioSuiteReferenceSchema = z
215
+ .object({
216
+ schemaVersion: z.literal('1.0'),
217
+ id: z.string().min(1).max(512),
218
+ cases: z
219
+ .array(z
220
+ .object({
221
+ id: z.string().min(1).max(512),
222
+ sourceSelectors: z.array(impactSymbolSelectorSchema).max(64).default([]),
223
+ sourceFiles: z.array(sourceDisplayPathSchema).max(64).default([]),
224
+ })
225
+ .loose())
226
+ .max(1_000),
227
+ })
228
+ .loose();
@@ -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.2.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,7 @@
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.
5
6
  - [Technology trees](technology.md): inspect, trace, lint, render, and compare technologies and doctrines.
6
7
  - [Bounded helper expansion](helper-expansion.md): resume source-linked event and technology helper paths with exact coverage boundaries.
7
8
  - [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`
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.2.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,7 @@
39
41
  "docs/README.md",
40
42
  "docs/setup.md",
41
43
  "docs/events.md",
44
+ "docs/analysis.md",
42
45
  "docs/technology.md",
43
46
  "docs/probability.md",
44
47
  "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.2.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.2.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.2.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": {