hoi4-agent-tools 1.2.0 → 2.1.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 +21 -1
- package/README.md +6 -7
- package/dist/hoi4_agent_tools/core/artifacts.js +109 -4
- package/dist/hoi4_agent_tools/core/diagnostic-collector.js +28 -8
- package/dist/hoi4_agent_tools/core/diff.js +162 -4
- package/dist/hoi4_agent_tools/core/engine.js +2 -0
- package/dist/hoi4_agent_tools/core/index.js +17 -6
- package/dist/hoi4_agent_tools/core/render-budget.js +5 -3
- package/dist/hoi4_agent_tools/core/scanner.js +3 -2
- package/dist/hoi4_agent_tools/core/source/limits.js +4 -1
- package/dist/hoi4_agent_tools/core/workspace.js +31 -3
- package/dist/hoi4_agent_tools/event/graph.js +28 -6
- package/dist/hoi4_agent_tools/event/limits.js +1 -1
- package/dist/hoi4_agent_tools/event/service.js +103 -7
- package/dist/hoi4_agent_tools/focus/continuous-render.js +17 -8
- package/dist/hoi4_agent_tools/focus/presentation.js +96 -41
- package/dist/hoi4_agent_tools/focus/render.js +27 -16
- package/dist/hoi4_agent_tools/gui/assets.js +9 -2
- package/dist/hoi4_agent_tools/gui/inspection-artifact.js +99 -0
- package/dist/hoi4_agent_tools/gui/layout.js +126 -27
- package/dist/hoi4_agent_tools/gui/renderer.js +16 -0
- package/dist/hoi4_agent_tools/gui/source-graph.js +61 -28
- package/dist/hoi4_agent_tools/gui/studio.js +23 -8
- package/dist/hoi4_agent_tools/map/diagnostic-limit.js +90 -9
- package/dist/hoi4_agent_tools/map/model.js +22 -4
- package/dist/hoi4_agent_tools/map/service.js +4 -3
- package/dist/hoi4_agent_tools/map/validation.js +3 -2
- package/dist/hoi4_agent_tools/mcp/server/create.js +1 -3
- package/dist/hoi4_agent_tools/mcp/server/output-schemas.js +1 -1
- package/dist/hoi4_agent_tools/mcp/tools/event.js +6 -6
- package/dist/hoi4_agent_tools/mcp/tools/focus.js +149 -224
- package/dist/hoi4_agent_tools/mcp/tools/gui.js +35 -25
- package/dist/hoi4_agent_tools/mcp/tools/map.js +6 -3
- package/dist/hoi4_agent_tools/runtime.js +112 -2
- package/dist/hoi4_agent_tools/schemas/common.js +5 -1
- package/dist/hoi4_agent_tools/version.js +1 -1
- package/docs/events.md +4 -5
- package/docs/focus.md +5 -4
- package/docs/gui.md +5 -1
- package/docs/map.md +1 -1
- package/docs/setup.md +9 -6
- package/package.json +1 -1
- package/server.json +2 -2
- package/dist/hoi4_agent_tools/mcp/tools/mods.js +0 -54
|
@@ -1,9 +1,11 @@
|
|
|
1
|
+
import { stat } from 'node:fs/promises';
|
|
1
2
|
import path from 'node:path';
|
|
2
3
|
import { homedir } from 'node:os';
|
|
3
|
-
import { loadConfiguration } from './core/configuration.js';
|
|
4
|
+
import { loadConfiguration, serverConfigurationSchema, } from './core/configuration.js';
|
|
4
5
|
import { CoreEngine } from './core/engine.js';
|
|
5
6
|
import { ServiceError } from './core/result.js';
|
|
6
7
|
import { WorkspaceResolver } from './core/workspace.js';
|
|
8
|
+
import { CONFIG_VERSION } from './version.js';
|
|
7
9
|
export function defaultConfigurationPath() {
|
|
8
10
|
const configRoot = process.env.APPDATA ?? process.env.XDG_CONFIG_HOME ?? path.join(homedir(), '.config');
|
|
9
11
|
return path.join(configRoot, 'hoi4-agent-tools', 'config.json');
|
|
@@ -21,8 +23,116 @@ export function configurationPath(arguments_ = process.argv.slice(2)) {
|
|
|
21
23
|
return path.resolve(process.env.HOI4_AGENT_CONFIG);
|
|
22
24
|
return defaultConfigurationPath();
|
|
23
25
|
}
|
|
26
|
+
async function isDirectory(candidate) {
|
|
27
|
+
try {
|
|
28
|
+
return (await stat(candidate)).isDirectory();
|
|
29
|
+
}
|
|
30
|
+
catch {
|
|
31
|
+
return false;
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
async function isFile(candidate) {
|
|
35
|
+
try {
|
|
36
|
+
return (await stat(candidate)).isFile();
|
|
37
|
+
}
|
|
38
|
+
catch {
|
|
39
|
+
return false;
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
async function findCurrentModRoot(start = process.cwd()) {
|
|
43
|
+
for (let cursor = path.resolve(start);;) {
|
|
44
|
+
if ((await isFile(path.join(cursor, 'descriptor.mod'))) ||
|
|
45
|
+
((await isDirectory(path.join(cursor, 'common'))) &&
|
|
46
|
+
((await isDirectory(path.join(cursor, 'history'))) ||
|
|
47
|
+
(await isDirectory(path.join(cursor, 'interface'))) ||
|
|
48
|
+
(await isDirectory(path.join(cursor, 'map')))))) {
|
|
49
|
+
return cursor;
|
|
50
|
+
}
|
|
51
|
+
const parent = path.dirname(cursor);
|
|
52
|
+
if (parent === cursor)
|
|
53
|
+
break;
|
|
54
|
+
cursor = parent;
|
|
55
|
+
}
|
|
56
|
+
throw new ServiceError('AUTO_MOD_ROOT_NOT_FOUND', 'Start the MCP from inside a Hearts of Iron IV mod or configure a server workspace', { currentDirectory: path.resolve(start) });
|
|
57
|
+
}
|
|
58
|
+
async function firstExistingDirectory(candidates) {
|
|
59
|
+
for (const candidate of candidates) {
|
|
60
|
+
if (await isDirectory(candidate))
|
|
61
|
+
return path.resolve(candidate);
|
|
62
|
+
}
|
|
63
|
+
return undefined;
|
|
64
|
+
}
|
|
65
|
+
function automaticGameRootCandidates() {
|
|
66
|
+
const home = homedir();
|
|
67
|
+
return [
|
|
68
|
+
...(process.env.HOI4_GAME_ROOT === undefined ? [] : [process.env.HOI4_GAME_ROOT]),
|
|
69
|
+
path.join(process.env['ProgramFiles(x86)'] ?? 'C:\\Program Files (x86)', 'Steam', 'steamapps', 'common', 'Hearts of Iron IV'),
|
|
70
|
+
path.join(home, '.local', 'share', 'Steam', 'steamapps', 'common', 'Hearts of Iron IV'),
|
|
71
|
+
path.join(home, '.steam', 'steam', 'steamapps', 'common', 'Hearts of Iron IV'),
|
|
72
|
+
path.join(home, 'Library', 'Application Support', 'Steam', 'steamapps', 'common', 'Hearts of Iron IV'),
|
|
73
|
+
];
|
|
74
|
+
}
|
|
75
|
+
function automaticStorageRoots() {
|
|
76
|
+
const home = homedir();
|
|
77
|
+
const dataRoot = process.env.XDG_DATA_HOME ?? process.env.LOCALAPPDATA ?? path.join(home, '.local', 'share');
|
|
78
|
+
const stateRoot = process.env.XDG_STATE_HOME ?? process.env.LOCALAPPDATA ?? path.join(home, '.local', 'state');
|
|
79
|
+
return {
|
|
80
|
+
serverStateRoot: path.join(stateRoot, 'hoi4-agent-tools', 'state'),
|
|
81
|
+
workspaceStorageRoot: path.join(dataRoot, 'hoi4-agent-tools', 'workspaces'),
|
|
82
|
+
};
|
|
83
|
+
}
|
|
84
|
+
function automaticWorkspaceId(modRoot) {
|
|
85
|
+
const slug = path
|
|
86
|
+
.basename(modRoot)
|
|
87
|
+
.normalize('NFKD')
|
|
88
|
+
.toLowerCase()
|
|
89
|
+
.replace(/[^a-z0-9]+/gu, '_')
|
|
90
|
+
.replace(/^_+|_+$/gu, '')
|
|
91
|
+
.slice(0, 48);
|
|
92
|
+
return `auto_${slug.length === 0 ? 'mod' : slug}`;
|
|
93
|
+
}
|
|
94
|
+
/** Build an in-memory configuration when a local agent starts inside a mod. */
|
|
95
|
+
export async function automaticConfiguration(start = process.cwd()) {
|
|
96
|
+
const modRoot = await findCurrentModRoot(start);
|
|
97
|
+
const gameRoot = await firstExistingDirectory(automaticGameRootCandidates());
|
|
98
|
+
const storage = automaticStorageRoots();
|
|
99
|
+
return serverConfigurationSchema.parse({
|
|
100
|
+
version: CONFIG_VERSION,
|
|
101
|
+
serverStateRoot: storage.serverStateRoot,
|
|
102
|
+
workspaceStorageRoot: storage.workspaceStorageRoot,
|
|
103
|
+
...(gameRoot === undefined ? {} : { gameRoot }),
|
|
104
|
+
workspaces: [
|
|
105
|
+
{
|
|
106
|
+
id: automaticWorkspaceId(modRoot),
|
|
107
|
+
name: path.basename(modRoot),
|
|
108
|
+
root: modRoot,
|
|
109
|
+
},
|
|
110
|
+
],
|
|
111
|
+
});
|
|
112
|
+
}
|
|
113
|
+
async function configurationExists(configPath) {
|
|
114
|
+
try {
|
|
115
|
+
return (await stat(configPath)).isFile();
|
|
116
|
+
}
|
|
117
|
+
catch {
|
|
118
|
+
return false;
|
|
119
|
+
}
|
|
120
|
+
}
|
|
24
121
|
export async function createEngine(configPath = configurationPath()) {
|
|
25
|
-
|
|
122
|
+
let configuration;
|
|
123
|
+
try {
|
|
124
|
+
configuration = await loadConfiguration(configPath);
|
|
125
|
+
}
|
|
126
|
+
catch (error) {
|
|
127
|
+
const useAutomaticConfiguration = configPath === defaultConfigurationPath() &&
|
|
128
|
+
process.env.HOI4_AGENT_CONFIG === undefined &&
|
|
129
|
+
error instanceof ServiceError &&
|
|
130
|
+
error.code === 'CONFIG_READ_FAILED' &&
|
|
131
|
+
!(await configurationExists(configPath));
|
|
132
|
+
if (!useAutomaticConfiguration)
|
|
133
|
+
throw error;
|
|
134
|
+
configuration = await automaticConfiguration();
|
|
135
|
+
}
|
|
26
136
|
const resolver = await WorkspaceResolver.create(configuration);
|
|
27
137
|
const engine = new CoreEngine(resolver);
|
|
28
138
|
await engine.initialize();
|
|
@@ -1,5 +1,9 @@
|
|
|
1
1
|
import { z } from 'zod/v4';
|
|
2
|
-
|
|
2
|
+
/** Optional for local agents: omitted means the mod containing the MCP cwd. */
|
|
3
|
+
export const workspaceIdSchema = z
|
|
4
|
+
.string()
|
|
5
|
+
.regex(/^[a-z][a-z0-9_-]{0,63}$/u)
|
|
6
|
+
.default('current');
|
|
3
7
|
const diagnosticCodeSchema = z.string().min(1).max(256);
|
|
4
8
|
const diagnosticMessageSchema = z.string().max(4096);
|
|
5
9
|
const sourceDisplayPathSchema = z.string().min(1).max(4096);
|
|
@@ -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 = '1.
|
|
3
|
+
export const PACKAGE_VERSION = '2.1.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/events.md
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
|
|
3
3
|
The Event Chain Viewer analyzes event definitions and call sites across the active mod, configured dependencies, and vanilla sources. It is read-only: it does not rewrite event files or simulate the game.
|
|
4
4
|
|
|
5
|
-
|
|
5
|
+
Use the three event tools directly from the target mod.
|
|
6
6
|
|
|
7
7
|
## Inspect
|
|
8
8
|
|
|
@@ -16,7 +16,9 @@ Start with `hoi4.mods` to obtain the workspace ID, then use the three event tool
|
|
|
16
16
|
- `lint`: find missing targets, unreachable events, suspicious cycles, conflicting definitions, invalid timing, and unresolved dynamic calls.
|
|
17
17
|
- `impact`: identify callers, descendants, state dependencies, and files affected by a proposed event change.
|
|
18
18
|
|
|
19
|
-
Use narrow identifiers, direction, and depth limits when the task concerns one chain.
|
|
19
|
+
Use narrow identifiers, direction, and depth limits when the task concerns one chain. Broad scans build the structural event graph without expanding every scripted helper into duplicate paths. Focused trace, path, state, impact, and render calls expand helper relationships when needed.
|
|
20
|
+
|
|
21
|
+
The compact response summarizes the result. Small scan resources contain the complete graph; very large scan resources contain exact totals, grouped inventories, representative diagnostics, and the revision needed for focused follow-up queries. This keeps an agent's prompt and artifact storage bounded without reducing the results of those focused queries.
|
|
20
22
|
|
|
21
23
|
Selectors use one of these forms:
|
|
22
24
|
|
|
@@ -37,7 +39,6 @@ Example `hoi4.event_inspect` arguments:
|
|
|
37
39
|
|
|
38
40
|
```json
|
|
39
41
|
{
|
|
40
|
-
"workspaceId": "my-mod",
|
|
41
42
|
"mode": "trace",
|
|
42
43
|
"selector": { "kind": "event", "eventId": "namespace.1" },
|
|
43
44
|
"direction": "downstream",
|
|
@@ -61,7 +62,6 @@ Example `hoi4.event_render` arguments:
|
|
|
61
62
|
|
|
62
63
|
```json
|
|
63
64
|
{
|
|
64
|
-
"workspaceId": "my-mod",
|
|
65
65
|
"view": "neighborhood",
|
|
66
66
|
"selector": { "kind": "event", "eventId": "namespace.1" },
|
|
67
67
|
"direction": "both",
|
|
@@ -83,7 +83,6 @@ Example `hoi4.event_compare` arguments:
|
|
|
83
83
|
|
|
84
84
|
```json
|
|
85
85
|
{
|
|
86
|
-
"workspaceId": "my-mod",
|
|
87
86
|
"proposedSources": [
|
|
88
87
|
{
|
|
89
88
|
"relativePath": "events/example.txt",
|
package/docs/focus.md
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
# Focus trees
|
|
2
2
|
|
|
3
|
-
Use `hoi4.focus_inspect`, `hoi4.focus_render`, and `hoi4.focus_rewrite` for national focus trees and continuous focus palettes.
|
|
3
|
+
Use `hoi4.focus_inspect`, `hoi4.focus_render`, `hoi4.focus_raster`, and `hoi4.focus_rewrite` for national focus trees and continuous focus palettes.
|
|
4
4
|
|
|
5
5
|
## Create a tree
|
|
6
6
|
|
|
@@ -14,7 +14,7 @@ A complete plan should include:
|
|
|
14
14
|
- focus positions, convergence points, and shared support branches;
|
|
15
15
|
- titles, descriptions, icons, filters, and AI behavior.
|
|
16
16
|
|
|
17
|
-
For a missing target, call `hoi4.focus_rewrite` with `createIfMissing: true`. Review the proposed and final artifacts returned by the rewrite, then inspect and render the result. Do not call a tree complete with placeholder rewards, missing localisation, missing icons, or absent AI choices.
|
|
17
|
+
For a missing target, call `hoi4.focus_rewrite` with `createIfMissing: true`. Review the proposed and final artifacts returned by the rewrite, then inspect and render the result. Call `hoi4.focus_raster` when the review needs decoded source icons and a deterministic PNG. Do not call a tree complete with placeholder rewards, missing localisation, missing icons, or absent AI choices.
|
|
18
18
|
|
|
19
19
|
## Clean an existing tree
|
|
20
20
|
|
|
@@ -22,7 +22,6 @@ For a layout-only cleanup of an existing national tree, call `hoi4.focus_rewrite
|
|
|
22
22
|
|
|
23
23
|
```json
|
|
24
24
|
{
|
|
25
|
-
"workspaceId": "my-mod",
|
|
26
25
|
"relativePath": "common/national_focus/my_tree.txt",
|
|
27
26
|
"treeId": "my_tree",
|
|
28
27
|
"layoutMode": "compact"
|
|
@@ -47,4 +46,6 @@ If malformed or unsupported script makes a requested change ambiguous, the rewri
|
|
|
47
46
|
|
|
48
47
|
Inspection and rendering can report missing references, invalid prerequisite structure, duplicate or overlapping positions, insufficient spacing, long or crossing connectors, branch asymmetry, route conflicts, missing localisation or sprites, weak terminal branches, repeated rewards, and missing AI metadata. Renders are offline review artifacts, not game screenshots.
|
|
49
48
|
|
|
50
|
-
National trees with 200 or more focuses
|
|
49
|
+
`hoi4.focus_render` is the normal structural view and writes complete HTML, SVG, JSON, and source-map artifacts without decoding every icon or creating a PNG. `hoi4.focus_raster` adds decoded icons and the high-fidelity PNG. National trees with 200 or more focuses raster at half scale by default; pass `reviewScale` from `0.25` through `1` when a different PNG size is needed.
|
|
50
|
+
|
|
51
|
+
The public workflow is regression-tested with 1,024-focus creation, compact rewrites, deterministic repeat runs, inspection, vector rendering, and raster rendering. A separate 1,024-icon test decodes a distinct texture for every focus. Large source diffs use the same deterministic review-artifact path instead of blocking at the quadratic matrix size.
|
package/docs/gui.md
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
# Scripted GUIs
|
|
2
2
|
|
|
3
|
-
Use `hoi4.gui_inspect`, `hoi4.gui_render`, and `hoi4.gui_rewrite` for `.gui`, `.gfx`, `common/scripted_guis`, localisation, sprites, fonts, and linked decision entry points.
|
|
3
|
+
Use `hoi4.gui_inspect`, `hoi4.gui_render`, and `hoi4.gui_rewrite` for `.gui`, `.gfx`, `common/scripted_guis`, localisation, sprites, fonts, and linked decision entry points.
|
|
4
4
|
|
|
5
5
|
## Create a GUI
|
|
6
6
|
|
|
@@ -30,8 +30,12 @@ Rewrite once, then inspect and render the result.
|
|
|
30
30
|
|
|
31
31
|
Inspection checks missing assets and localisation, invalid sizes, overlap, clipping, overflow, conflicting click regions, invisible blockers, broken parents or contexts, list-row cuts, state conflicts, trigger/effect gaps, and resolution drift.
|
|
32
32
|
|
|
33
|
+
Broad inspection indexes localisation actually referenced by GUI source and returns a connected workspace projection when the complete source graph is very large. The resource records full and returned node and edge counts, so an agent can identify the relevant window without loading unrelated vanilla UI into its prompt. Rendering remains targeted to the selected root, state, and resolution.
|
|
34
|
+
|
|
33
35
|
## Offline preview limits
|
|
34
36
|
|
|
35
37
|
The renderer does not run the game engine. Each render includes a fidelity report that separates fields it models from fields it approximates, ignores, cannot resolve, or does not support. Treat that report as part of the review.
|
|
36
38
|
|
|
39
|
+
Unresolved numeric runtime values such as `[?variable|format]` render as `[X]`. Unresolved text-returning scripted or scoped localisation such as `[GetStatusText]`, `[FROM.GetName]`, and `[?leader_scope.GetName]` renders as `[dynamic_loc]`. Provide scenario values when the exact value matters. Supported HOI4 `§` localisation colour controls are applied to preview text and `§!` restores the default colour.
|
|
40
|
+
|
|
37
41
|
A rewrite stops if malformed or unsupported GUI script makes the requested change ambiguous. Runtime animation, masking, tiling, hardcoded controls, and dynamic values may require exact game precedents even when a useful offline preview is available.
|
package/docs/map.md
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
# Maps
|
|
2
2
|
|
|
3
|
-
Use `hoi4.map_inspect`, `hoi4.map_render`, and `hoi4.map_rewrite` for provinces, states, strategic regions, adjacency, supply nodes, railways, positions, ownership, cores, claims, resources, buildings, and localisation.
|
|
3
|
+
Use `hoi4.map_inspect`, `hoi4.map_render`, and `hoi4.map_rewrite` for provinces, states, strategic regions, adjacency, supply nodes, railways, positions, ownership, cores, claims, resources, buildings, and localisation.
|
|
4
4
|
|
|
5
5
|
## Create or reshape map content
|
|
6
6
|
|
package/docs/setup.md
CHANGED
|
@@ -2,18 +2,21 @@
|
|
|
2
2
|
|
|
3
3
|
HOI4 Agent Tools requires Node.js 22 or 24.
|
|
4
4
|
|
|
5
|
-
## Install
|
|
5
|
+
## Install
|
|
6
6
|
|
|
7
7
|
```bash
|
|
8
|
-
npm install --global hoi4-agent-tools
|
|
9
|
-
hoi4-agent-tools-setup --init
|
|
8
|
+
npm install --global hoi4-agent-tools
|
|
10
9
|
```
|
|
11
10
|
|
|
12
|
-
|
|
11
|
+
Set the MCP process working directory to the mod being edited. The server creates its local workspace in memory, keeps generated artifacts in the per-user data directory, and starts without a config file. The installed game is detected when available for vanilla references; it is not required for source inspection or offline rendering.
|
|
13
12
|
|
|
14
|
-
|
|
13
|
+
When the MCP server starts with its working directory inside a mod, every focus, GUI, map, and event call uses that mod automatically. Configured multi-mod or remote deployments can use explicit workspace selection.
|
|
15
14
|
|
|
16
|
-
##
|
|
15
|
+
## Optional persistent configuration
|
|
16
|
+
|
|
17
|
+
Use `--init` only when you need several mod roots, a fixed game path, or a shared/remote process:
|
|
18
|
+
|
|
19
|
+
### Configure explicit paths
|
|
17
20
|
|
|
18
21
|
Use explicit paths when discovery is incomplete or when you want to expose more than one mod root:
|
|
19
22
|
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "hoi4-agent-tools",
|
|
3
3
|
"mcpName": "io.github.klimPaskov/hoi4-agent-tools",
|
|
4
|
-
"version": "1.
|
|
4
|
+
"version": "2.1.0",
|
|
5
5
|
"description": "Analyze HOI4 event chains; create and clean focus trees, scripted GUIs, and maps with coding agents.",
|
|
6
6
|
"type": "module",
|
|
7
7
|
"license": "Apache-2.0",
|
package/server.json
CHANGED
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
"name": "io.github.klimPaskov/hoi4-agent-tools",
|
|
4
4
|
"title": "HOI4 Agent Tools",
|
|
5
5
|
"description": "Analyze HOI4 event chains; create and clean focus trees, scripted GUIs, and maps with coding agents.",
|
|
6
|
-
"version": "1.
|
|
6
|
+
"version": "2.1.0",
|
|
7
7
|
"repository": {
|
|
8
8
|
"url": "https://github.com/klimPaskov/hoi4-agent-tools",
|
|
9
9
|
"source": "github"
|
|
@@ -13,7 +13,7 @@
|
|
|
13
13
|
{
|
|
14
14
|
"registryType": "npm",
|
|
15
15
|
"identifier": "hoi4-agent-tools",
|
|
16
|
-
"version": "1.
|
|
16
|
+
"version": "2.1.0",
|
|
17
17
|
"transport": {
|
|
18
18
|
"type": "stdio"
|
|
19
19
|
}
|
|
@@ -1,54 +0,0 @@
|
|
|
1
|
-
import { z } from 'zod/v4';
|
|
2
|
-
import { compareCodeUnits } from '../../core/canonical.js';
|
|
3
|
-
import { emptyServiceResult } from '../../core/result.js';
|
|
4
|
-
import { nonNegativeIntegerSchema } from '../server/output-schemas.js';
|
|
5
|
-
import { errorResult, strictOperationResultSchema, toolResult } from '../server/result.js';
|
|
6
|
-
const modsOutputSchema = strictOperationResultSchema(z
|
|
7
|
-
.object({
|
|
8
|
-
count: nonNegativeIntegerSchema,
|
|
9
|
-
mods: z
|
|
10
|
-
.array(z
|
|
11
|
-
.object({
|
|
12
|
-
id: z.string().min(1).max(64),
|
|
13
|
-
name: z.string().min(1).max(256),
|
|
14
|
-
writable: z.boolean(),
|
|
15
|
-
})
|
|
16
|
-
.strict())
|
|
17
|
-
.max(1_000),
|
|
18
|
-
})
|
|
19
|
-
.strict());
|
|
20
|
-
export function registerModsTool(server, engine, context) {
|
|
21
|
-
server.registerTool('hoi4.mods', {
|
|
22
|
-
title: 'List available HOI4 mods',
|
|
23
|
-
description: 'List configured HOI4 mod workspaces, optionally selecting one by ID.',
|
|
24
|
-
inputSchema: z.object({ workspaceId: z.string().min(1).max(64).optional() }).strict(),
|
|
25
|
-
outputSchema: modsOutputSchema,
|
|
26
|
-
annotations: {
|
|
27
|
-
readOnlyHint: true,
|
|
28
|
-
destructiveHint: false,
|
|
29
|
-
idempotentHint: true,
|
|
30
|
-
openWorldHint: false,
|
|
31
|
-
},
|
|
32
|
-
}, ({ workspaceId }) => {
|
|
33
|
-
try {
|
|
34
|
-
const mods = (workspaceId === undefined
|
|
35
|
-
? engine.list(context.principal)
|
|
36
|
-
: [engine.status(workspaceId, context.principal)])
|
|
37
|
-
.filter(({ kind }) => kind === 'mod')
|
|
38
|
-
.sort((left, right) => compareCodeUnits(left.id, right.id));
|
|
39
|
-
const result = emptyServiceResult(workspaceId ?? '', {
|
|
40
|
-
count: mods.length,
|
|
41
|
-
mods: mods.map(({ id, name, writable }) => ({
|
|
42
|
-
id,
|
|
43
|
-
name,
|
|
44
|
-
writable,
|
|
45
|
-
})),
|
|
46
|
-
});
|
|
47
|
-
result.code = 'MODS_LISTED';
|
|
48
|
-
return toolResult(result);
|
|
49
|
-
}
|
|
50
|
-
catch (error) {
|
|
51
|
-
return errorResult(error, workspaceId ?? '');
|
|
52
|
-
}
|
|
53
|
-
});
|
|
54
|
-
}
|