hoi4-agent-tools 3.10.0 → 4.0.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 +109 -0
- package/README.md +115 -147
- package/dist/bin/http.js +10 -0
- package/dist/bin/setup.js +3 -2
- package/dist/bin/stdio.js +10 -0
- package/dist/hoi4_agent_tools/core/artifacts.js +40 -5
- package/dist/hoi4_agent_tools/core/canonical.js +18 -4
- package/dist/hoi4_agent_tools/core/configuration.js +7 -0
- package/dist/hoi4_agent_tools/core/domain-scan-patterns.js +12 -0
- package/dist/hoi4_agent_tools/core/domain-tools.js +65 -0
- package/dist/hoi4_agent_tools/core/domain-validation.js +5 -2
- package/dist/hoi4_agent_tools/core/engine.js +29 -2
- package/dist/hoi4_agent_tools/core/index.js +2 -2
- package/dist/hoi4_agent_tools/core/job-executor.js +14 -1
- package/dist/hoi4_agent_tools/core/job-operation-registration.js +15 -7
- package/dist/hoi4_agent_tools/core/job-store.js +78 -5
- package/dist/hoi4_agent_tools/core/job-transactions.js +31 -2
- package/dist/hoi4_agent_tools/core/job-worker-host.js +215 -116
- package/dist/hoi4_agent_tools/core/job-worker.js +90 -36
- package/dist/hoi4_agent_tools/core/operation-result.js +123 -10
- package/dist/hoi4_agent_tools/core/operation-tasks.js +49 -89
- package/dist/hoi4_agent_tools/core/persistent-analysis-cache.js +25 -21
- package/dist/hoi4_agent_tools/core/server-registry.js +22 -5
- package/dist/hoi4_agent_tools/core/shared-request-capacity.js +26 -1
- package/dist/hoi4_agent_tools/core/source/cache.js +20 -10
- package/dist/hoi4_agent_tools/core/source/lexer.js +11 -3
- package/dist/hoi4_agent_tools/core/transactions.js +114 -23
- package/dist/hoi4_agent_tools/core/workspace.js +84 -8
- package/dist/hoi4_agent_tools/decision/ai.js +1 -1
- package/dist/hoi4_agent_tools/decision/service.js +28 -0
- package/dist/hoi4_agent_tools/decision/source-inventory.js +7 -5
- package/dist/hoi4_agent_tools/event/job-operations.js +9 -5
- package/dist/hoi4_agent_tools/event/operations.js +14 -1
- package/dist/hoi4_agent_tools/focus/job-operations.js +1 -2
- package/dist/hoi4_agent_tools/focus/tool-operations.js +1 -1
- package/dist/hoi4_agent_tools/gui/validators.js +8 -6
- package/dist/hoi4_agent_tools/map/bmp.js +1 -1
- package/dist/hoi4_agent_tools/map/derived.js +748 -0
- package/dist/hoi4_agent_tools/map/job-operations.js +7 -3
- package/dist/hoi4_agent_tools/map/model.js +103 -0
- package/dist/hoi4_agent_tools/map/operations.js +427 -58
- package/dist/hoi4_agent_tools/map/references.js +483 -0
- package/dist/hoi4_agent_tools/map/service.js +136 -61
- package/dist/hoi4_agent_tools/map/tool-operations.js +2 -1
- package/dist/hoi4_agent_tools/map/validation.js +3 -0
- package/dist/hoi4_agent_tools/map/world.js +1280 -0
- package/dist/hoi4_agent_tools/mcp/server/argument-errors.js +72 -0
- package/dist/hoi4_agent_tools/mcp/server/create-modern-operations.js +23 -5
- package/dist/hoi4_agent_tools/mcp/server/create.js +7 -0
- package/dist/hoi4_agent_tools/mcp/server/request-lifecycle.js +24 -30
- package/dist/hoi4_agent_tools/mcp/server/tool-listing.js +45 -0
- package/dist/hoi4_agent_tools/mcp/tools/analysis.js +25 -5
- package/dist/hoi4_agent_tools/mcp/tools/event.js +18 -29
- package/dist/hoi4_agent_tools/mcp/tools/focus.js +4 -12
- package/dist/hoi4_agent_tools/mcp/tools/gui.js +3 -3
- package/dist/hoi4_agent_tools/mcp/tools/job.js +2 -2
- package/dist/hoi4_agent_tools/mcp/tools/map.js +13 -16
- package/dist/hoi4_agent_tools/mcp/tools/probability.js +42 -48
- package/dist/hoi4_agent_tools/mcp/tools/reference.js +22 -5
- package/dist/hoi4_agent_tools/mcp/tools/technology.js +16 -29
- package/dist/hoi4_agent_tools/mcp/transports/http.js +28 -4
- package/dist/hoi4_agent_tools/mcp/transports/stdio-lifetime.js +31 -8
- package/dist/hoi4_agent_tools/probability/job-operations.js +4 -9
- package/dist/hoi4_agent_tools/probability/operations.js +175 -13
- package/dist/hoi4_agent_tools/probability/source-analysis.js +24 -1
- package/dist/hoi4_agent_tools/reference/error-log.js +359 -0
- package/dist/hoi4_agent_tools/reference/known-mistakes.js +307 -0
- package/dist/hoi4_agent_tools/reference/known-mistakes.json +154 -0
- package/dist/hoi4_agent_tools/reference/mod-index.js +101 -0
- package/dist/hoi4_agent_tools/reference/operations.js +88 -19
- package/dist/hoi4_agent_tools/reference/player-text.js +4 -3
- package/dist/hoi4_agent_tools/reference/script-validation.js +19 -1
- package/dist/hoi4_agent_tools/reference/service.js +6 -0
- package/dist/hoi4_agent_tools/schemas/event.js +78 -19
- package/dist/hoi4_agent_tools/schemas/focus-requests.js +10 -0
- package/dist/hoi4_agent_tools/schemas/lenient-arguments.js +266 -0
- package/dist/hoi4_agent_tools/schemas/map-requests.js +63 -20
- package/dist/hoi4_agent_tools/schemas/map.js +122 -3
- package/dist/hoi4_agent_tools/schemas/mod-tools.js +181 -0
- package/dist/hoi4_agent_tools/schemas/probability-requests.js +119 -9
- package/dist/hoi4_agent_tools/schemas/reference.js +13 -0
- package/dist/hoi4_agent_tools/schemas/scenarios.js +1 -3
- package/dist/hoi4_agent_tools/schemas/script-validation.js +13 -6
- package/dist/hoi4_agent_tools/schemas/technology.js +79 -21
- package/dist/hoi4_agent_tools/technology/job-operations.js +3 -4
- package/dist/hoi4_agent_tools/technology/operations.js +14 -1
- package/dist/hoi4_agent_tools/version.js +1 -1
- package/docs/README.md +7 -4
- package/docs/analysis.md +13 -0
- package/docs/configuration.md +281 -0
- package/docs/development.md +24 -2
- package/docs/events.md +27 -3
- package/docs/examples.md +6 -6
- package/docs/focus.md +125 -4
- package/docs/gui.md +98 -17
- package/docs/helper-expansion.md +8 -8
- package/docs/http.md +3 -1
- package/docs/jobs.md +19 -13
- package/docs/map.md +197 -6
- package/docs/mechanics.md +4 -0
- package/docs/probability.md +42 -15
- package/docs/reference.md +71 -4
- package/docs/setup.md +44 -11
- package/docs/technology.md +26 -1
- package/docs/third-party-notices.md +11 -0
- package/docs/tools.md +151 -42
- package/docs/troubleshooting.md +61 -0
- package/examples/clients/codex-config.toml +5 -2
- package/examples/clients/generic.json +2 -2
- package/examples/config/config.json +7 -0
- package/npm-shrinkwrap.json +151 -156
- package/package.json +13 -8
- package/schemas/configuration.schema.json +144 -128
- package/schemas/continuous-focus-palette.schema.json +1 -1
- package/schemas/custom-weighted-pool.schema.json +1 -1
- package/schemas/decision-inspect-input.schema.json +1 -1
- package/schemas/error-log-input.schema.json +55 -0
- package/schemas/event-feature-manifest.schema.json +1 -1
- package/schemas/focus-plan.schema.json +1 -1
- package/schemas/focus-planning-sidecar.schema.json +1 -1
- package/schemas/gui-animation-source.schema.json +1 -1
- package/schemas/gui-helper.schema.json +1 -1
- package/schemas/gui-scenario.schema.json +1 -1
- package/schemas/helper-expansion-request.schema.json +1 -1
- package/schemas/helper-expansion-summary.schema.json +1 -1
- package/schemas/impact-inspect-input.schema.json +1 -1
- package/schemas/map-operation.schema.json +597 -126
- package/schemas/mechanic-test-input.schema.json +1 -1
- package/schemas/mod-index-input.schema.json +51 -0
- package/schemas/operation-result.schema.json +2 -2
- package/schemas/package-check-input.schema.json +1 -1
- package/schemas/package-manifest.schema.json +1 -1
- package/schemas/probability-analysis-result.schema.json +1 -1
- package/schemas/probability-compare-input.schema.json +1 -1
- package/schemas/probability-evaluate-input.schema.json +1 -1
- package/schemas/probability-inspect-input.schema.json +1 -1
- package/schemas/probability-render-input.schema.json +1 -1
- package/schemas/probability-scenario-set.schema.json +1 -1
- package/schemas/probability-sequence-input.schema.json +1 -1
- package/schemas/probability-simulate-input.schema.json +1 -1
- package/schemas/probability-sweep-input.schema.json +1 -1
- package/schemas/reference-context-input.schema.json +1 -1
- package/schemas/reference-read-input.schema.json +1 -1
- package/schemas/reference-search-input.schema.json +1 -1
- package/schemas/scenario-suite.schema.json +3 -5
- package/schemas/scenario-test-input.schema.json +3 -5
- package/schemas/script-validate-input.schema.json +1 -1
- package/schemas/shared-scenario.schema.json +1 -1
- package/schemas/source-lookup-input.schema.json +1 -1
- package/server.json +3 -3
|
@@ -2,7 +2,7 @@ import { z } from 'zod/v4';
|
|
|
2
2
|
import { IdleCacheLifetime } from '../core/idle-cache-lifetime.js';
|
|
3
3
|
import { errorResult, toolResult } from '../core/operation-result.js';
|
|
4
4
|
import { ServiceError } from '../core/result.js';
|
|
5
|
-
import {
|
|
5
|
+
import { MAP_VIEW_FIELDS, mapInspectRequestSchema, mapRewriteRequestSchema, } from '../schemas/map-requests.js';
|
|
6
6
|
import { AgentNudger } from './service.js';
|
|
7
7
|
import { inspectMap, completeMapRewrite, normalizeMapInspectRequest, normalizeMapRenderRequest, normalizeMapRewriteRequest, prepareMapRewrite, renderMapView, } from './tool-operations.js';
|
|
8
8
|
const wireResult = z.record(z.string(), z.json());
|
|
@@ -43,8 +43,12 @@ export function registerMapJobs(operations, engine) {
|
|
|
43
43
|
}
|
|
44
44
|
});
|
|
45
45
|
}
|
|
46
|
-
register('hoi4.map_inspect', mapInspectRequestSchema, normalizeMapInspectRequest, (nudger, input, context) =>
|
|
47
|
-
|
|
46
|
+
register('hoi4.map_inspect', mapInspectRequestSchema, normalizeMapInspectRequest, (nudger, input, context) => MAP_VIEW_FIELDS.some((field) => input[field] !== undefined)
|
|
47
|
+
? renderMapView(nudger, normalizeMapRenderRequest({
|
|
48
|
+
workspaceId: input.workspaceId,
|
|
49
|
+
...Object.fromEntries(MAP_VIEW_FIELDS.flatMap((field) => input[field] === undefined ? [] : [[field, input[field]]])),
|
|
50
|
+
}), context)
|
|
51
|
+
: inspectMap(engine, nudger, input, context));
|
|
48
52
|
operations.registerWrite('hoi4.map_rewrite', mapRewriteRequestSchema, async (input, context) => {
|
|
49
53
|
if (input.workspaceId !== 'current' && input.workspaceId !== context.workspaceId)
|
|
50
54
|
throw new ServiceError('JOB_ARGUMENT_SCOPE_MISMATCH', 'The request workspace does not match the authorized job workspace');
|
|
@@ -485,6 +485,73 @@ export function parseTerrainCategories(files, diagnostics) {
|
|
|
485
485
|
}
|
|
486
486
|
return categories;
|
|
487
487
|
}
|
|
488
|
+
/**
|
|
489
|
+
* When no building definitions are scanned, these state buildings are levels rather than slot
|
|
490
|
+
* counts, as in the base game: a split keeps the level in both states and a merge keeps the
|
|
491
|
+
* highest level.
|
|
492
|
+
*/
|
|
493
|
+
export const LEVEL_STATE_BUILDINGS = new Set([
|
|
494
|
+
'infrastructure',
|
|
495
|
+
'air_base',
|
|
496
|
+
'anti_air_building',
|
|
497
|
+
'radar_station',
|
|
498
|
+
]);
|
|
499
|
+
/** Building types and spawn points from the active `common/buildings` files. */
|
|
500
|
+
export function parseBuildingDefinitions(files, diagnostics) {
|
|
501
|
+
const definitions = new Map();
|
|
502
|
+
const spawnPoints = new Map();
|
|
503
|
+
const yes = (block, key) => firstScalar(block, key)?.value === 'yes';
|
|
504
|
+
const numberIn = (block, key) => {
|
|
505
|
+
if (block === undefined)
|
|
506
|
+
return undefined;
|
|
507
|
+
const value = Number(firstScalar(block, key)?.value);
|
|
508
|
+
return Number.isFinite(value) ? value : undefined;
|
|
509
|
+
};
|
|
510
|
+
for (const file of [...files].sort((left, right) => compareCodeUnits(normalizedPath(left.relativePath), normalizedPath(right.relativePath)))) {
|
|
511
|
+
const document = parseClausewitz(file.bytes, file.displayPath);
|
|
512
|
+
addMapDiagnostics(diagnostics, document.diagnostics);
|
|
513
|
+
for (const entry of document.root.entries) {
|
|
514
|
+
if (entry.type !== 'assignment' || entry.value.type !== 'block')
|
|
515
|
+
continue;
|
|
516
|
+
if (entry.key.value === 'buildings') {
|
|
517
|
+
for (const building of entry.value.entries) {
|
|
518
|
+
if (building.type !== 'assignment' || building.value.type !== 'block')
|
|
519
|
+
continue;
|
|
520
|
+
const block = building.value;
|
|
521
|
+
const levelCap = assignments(block, 'level_cap')[0]?.value;
|
|
522
|
+
const cap = levelCap?.type === 'block' ? levelCap : undefined;
|
|
523
|
+
const provinceMax = numberIn(cap, 'province_max') ?? numberIn(block, 'province_max');
|
|
524
|
+
const stateMax = numberIn(cap, 'state_max') ?? numberIn(block, 'state_max');
|
|
525
|
+
const spawnPoint = firstScalar(block, 'spawn_point')?.value;
|
|
526
|
+
definitions.set(building.key.value, {
|
|
527
|
+
name: building.key.value,
|
|
528
|
+
sharesSlots: yes(block, 'shares_slots') || (cap !== undefined && yes(cap, 'shares_slots')),
|
|
529
|
+
provincial: yes(block, 'provincial') || provinceMax !== undefined,
|
|
530
|
+
...(stateMax === undefined ? {} : { stateMax }),
|
|
531
|
+
...(provinceMax === undefined ? {} : { provinceMax }),
|
|
532
|
+
showOnMap: numberIn(block, 'show_on_map') ?? 0,
|
|
533
|
+
onlyCoastal: yes(block, 'only_costal'),
|
|
534
|
+
...(spawnPoint === undefined ? {} : { spawnPoint }),
|
|
535
|
+
});
|
|
536
|
+
}
|
|
537
|
+
}
|
|
538
|
+
else if (entry.key.value === 'spawn_points') {
|
|
539
|
+
for (const point of entry.value.entries) {
|
|
540
|
+
if (point.type !== 'assignment' || point.value.type !== 'block')
|
|
541
|
+
continue;
|
|
542
|
+
spawnPoints.set(point.key.value, {
|
|
543
|
+
name: point.key.value,
|
|
544
|
+
provincial: firstScalar(point.value, 'type')?.value === 'province',
|
|
545
|
+
max: numberIn(point.value, 'max') ?? 1,
|
|
546
|
+
onlyCoastal: yes(point.value, 'only_costal'),
|
|
547
|
+
autoNudged: !yes(point.value, 'disable_auto_nudging'),
|
|
548
|
+
});
|
|
549
|
+
}
|
|
550
|
+
}
|
|
551
|
+
}
|
|
552
|
+
}
|
|
553
|
+
return { definitions, spawnPoints };
|
|
554
|
+
}
|
|
488
555
|
/** Continent names in `continent.txt`; their one-based positions are the continent IDs. */
|
|
489
556
|
export function parseContinents(file, diagnostics) {
|
|
490
557
|
const document = parseClausewitz(file.bytes, file.displayPath);
|
|
@@ -1040,8 +1107,39 @@ export class MapWorkspaceIndex {
|
|
|
1040
1107
|
continents;
|
|
1041
1108
|
/** Terrain categories when any `common/terrain` file was read. */
|
|
1042
1109
|
terrainCategories;
|
|
1110
|
+
/** Building types from `common/buildings`; empty when none were scanned. */
|
|
1111
|
+
buildingDefinitions;
|
|
1112
|
+
buildingSpawnPoints;
|
|
1043
1113
|
supplyNodeFile;
|
|
1044
1114
|
railwayFile;
|
|
1115
|
+
/** The active heightmap, when the scan included it; decoded on first use. */
|
|
1116
|
+
heightmapFile;
|
|
1117
|
+
#heightmap;
|
|
1118
|
+
/**
|
|
1119
|
+
* Map height (the Y coordinate) at a bitmap pixel: the heightmap value divided by ten, as the
|
|
1120
|
+
* game reads it. Without a readable heightmap of the province map's size, sea level (9.5).
|
|
1121
|
+
*/
|
|
1122
|
+
heightAt(x, y) {
|
|
1123
|
+
if (this.#heightmap === undefined) {
|
|
1124
|
+
this.#heightmap = null;
|
|
1125
|
+
if (this.heightmapFile !== undefined)
|
|
1126
|
+
try {
|
|
1127
|
+
const decoded = BmpImage.decode(this.heightmapFile.bytes);
|
|
1128
|
+
if (decoded.bitsPerPixel === 8 &&
|
|
1129
|
+
decoded.width === this.raster?.width &&
|
|
1130
|
+
decoded.height === this.raster.height)
|
|
1131
|
+
this.#heightmap = decoded;
|
|
1132
|
+
}
|
|
1133
|
+
catch {
|
|
1134
|
+
this.#heightmap = null;
|
|
1135
|
+
}
|
|
1136
|
+
}
|
|
1137
|
+
if (this.#heightmap === null)
|
|
1138
|
+
return 9.5;
|
|
1139
|
+
const index = this.#heightmap.paletteIndexAt(Math.min(Math.max(0, Math.floor(x)), this.#heightmap.width - 1), Math.min(Math.max(0, Math.floor(y)), this.#heightmap.height - 1));
|
|
1140
|
+
const color = this.#heightmap.palette[index];
|
|
1141
|
+
return (color === undefined ? index : color.r) / 10;
|
|
1142
|
+
}
|
|
1045
1143
|
constructor(files, sourceRoots = defaultMapIndexSourceRoots, sharedIndex = SymbolIndex.build(files)) {
|
|
1046
1144
|
this.sourceFiles = [...files];
|
|
1047
1145
|
this.sharedIndex = sharedIndex;
|
|
@@ -1198,6 +1296,11 @@ export class MapWorkspaceIndex {
|
|
|
1198
1296
|
terrainFiles.length === 0
|
|
1199
1297
|
? undefined
|
|
1200
1298
|
: parseTerrainCategories(terrainFiles, this.diagnostics);
|
|
1299
|
+
this.heightmapFile = mapFile(this.activeFiles, defaultMapSelectorValue(this.defaultMapFile, 'heightmap', 'heightmap.bmp'), this.sourceRoots.map);
|
|
1300
|
+
const buildingFiles = this.activeFiles.all.filter((file) => /^common\/buildings\/[^/]+\.txt$/iu.test(normalizedPath(file.relativePath)));
|
|
1301
|
+
const buildings = parseBuildingDefinitions(buildingFiles, []);
|
|
1302
|
+
this.buildingDefinitions = buildings.definitions;
|
|
1303
|
+
this.buildingSpawnPoints = buildings.spawnPoints;
|
|
1201
1304
|
this.adjacencyFile = mapFile(this.activeFiles, defaultMapSelectorValue(this.defaultMapFile, 'adjacencies', 'adjacencies.csv'), this.sourceRoots.map);
|
|
1202
1305
|
this.adjacencies =
|
|
1203
1306
|
this.adjacencyFile === undefined
|