hoi4-agent-tools 2.5.1 → 2.5.2

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 CHANGED
@@ -1,5 +1,16 @@
1
1
  # Changelog
2
2
 
3
+ ## Unreleased
4
+
5
+ No unreleased changes.
6
+
7
+ ## 2.5.2 - 2026-08-15
8
+
9
+ - Distinguished HOI4 small and large technology layouts in graph data and source-positioned folder renders, including exact 72×72 small items selected by `force_use_small_tech_layout`.
10
+ - Reverified the public Technology Tree Viewer MCP workflow across
11
+ `hoi4.tech_inspect`, `hoi4.tech_render`, and `hoi4.tech_compare` before
12
+ publication.
13
+
3
14
  ## 2.5.1 - 2026-08-13
4
15
 
5
16
  - Published artifact contents and provenance manifests atomically across independent MCP processes, preventing event, probability, GUI, and other concurrent inspections from observing partially written manifests.
@@ -92,6 +92,7 @@ function technologyMetadata(technology) {
92
92
  researchCost: technology.researchCost ?? null,
93
93
  doctrineName: technology.doctrineName ?? null,
94
94
  hidden: technology.hidden,
95
+ layoutSize: technology.layoutSize,
95
96
  folders: technology.folders,
96
97
  categories: technology.categories,
97
98
  tags: technology.tags,
@@ -5,8 +5,10 @@ import { ServiceError } from '../core/result.js';
5
5
  import { DeterministicSvgTextRenderer } from '../core/svg-text.js';
6
6
  import { traceTechnology } from './queries.js';
7
7
  const MAX_RENDER_NODES = 2_000;
8
- const NODE_WIDTH = 210;
9
- const NODE_HEIGHT = 76;
8
+ const LARGE_NODE_WIDTH = 183;
9
+ const LARGE_NODE_HEIGHT = 84;
10
+ const SMALL_NODE_WIDTH = 72;
11
+ const SMALL_NODE_HEIGHT = 72;
10
12
  const GAP_X = 42;
11
13
  const GAP_Y = 42;
12
14
  const GENERATED_NODE_WIDTH = 180;
@@ -44,6 +46,7 @@ function technologyNode(graph, technologyId, placement) {
44
46
  kind: technology.kind,
45
47
  sourcePath: technology.source.path,
46
48
  sourceLine: technology.source.location.start.line,
49
+ layoutSize: technology.layoutSize,
47
50
  ...(placement === undefined ? {} : { placement }),
48
51
  };
49
52
  }
@@ -415,17 +418,22 @@ function issueKey(issue) {
415
418
  return sha256Bytes(canonicalJson({ code: issue.code, details: issue.details })).slice(0, 20);
416
419
  }
417
420
  function layoutFolder(nodes) {
421
+ const dimensions = (node) => node.layoutSize === 'small'
422
+ ? { width: SMALL_NODE_WIDTH, height: SMALL_NODE_HEIGHT }
423
+ : { width: LARGE_NODE_WIDTH, height: LARGE_NODE_HEIGHT };
418
424
  const sourcePixel = nodes.filter(({ placement }) => placement?.pixelX !== undefined && placement.pixelY !== undefined);
419
425
  if (sourcePixel.length === nodes.length && sourcePixel.length > 0) {
420
426
  const minimumX = Math.min(...sourcePixel.map(({ placement }) => placement.pixelX));
421
427
  const minimumY = Math.min(...sourcePixel.map(({ placement }) => placement.pixelY));
422
- return sourcePixel.map((node) => ({
423
- ...node,
424
- x: PADDING + node.placement.pixelX - minimumX,
425
- y: HEADER_HEIGHT + PADDING + node.placement.pixelY - minimumY,
426
- width: NODE_WIDTH,
427
- height: NODE_HEIGHT,
428
- }));
428
+ return sourcePixel.map((node) => {
429
+ const size = dimensions(node);
430
+ return {
431
+ ...node,
432
+ x: PADDING + node.placement.pixelX - minimumX,
433
+ y: HEADER_HEIGHT + PADDING + node.placement.pixelY - minimumY,
434
+ ...size,
435
+ };
436
+ });
429
437
  }
430
438
  const branchRoots = [
431
439
  ...new Set(nodes.map(({ placement }) => placement?.branchRootId ?? '<unresolved>')),
@@ -434,9 +442,12 @@ function layoutFolder(nodes) {
434
442
  return nodes.map((node, index) => {
435
443
  const placement = node.placement;
436
444
  const lane = lanes.get(placement?.branchRootId ?? '<unresolved>') ?? 0;
437
- const x = PADDING + lane * 680 + (placement?.x ?? index % 3) * (NODE_WIDTH + GAP_X);
438
- const y = HEADER_HEIGHT + PADDING + (placement?.y ?? Math.floor(index / 3)) * (NODE_HEIGHT + GAP_Y);
439
- return { ...node, x, y, width: NODE_WIDTH, height: NODE_HEIGHT };
445
+ const size = dimensions(node);
446
+ const x = PADDING + lane * 680 + (placement?.x ?? index % 3) * (LARGE_NODE_WIDTH + GAP_X);
447
+ const y = HEADER_HEIGHT +
448
+ PADDING +
449
+ (placement?.y ?? Math.floor(index / 3)) * (LARGE_NODE_HEIGHT + GAP_Y);
450
+ return { ...node, x, y, ...size };
440
451
  });
441
452
  }
442
453
  function layoutGenerated(nodes, edges) {
@@ -527,8 +538,8 @@ function colours(kind) {
527
538
  }[kind];
528
539
  }
529
540
  function svgFor(titleText, positioned, edges, sourceAccurate) {
530
- const maximumX = Math.max(PADDING + NODE_WIDTH, ...positioned.map(({ x, width }) => x + width));
531
- const maximumY = Math.max(HEADER_HEIGHT + NODE_HEIGHT, ...positioned.map(({ y, height }) => y + height));
541
+ const maximumX = Math.max(PADDING + LARGE_NODE_WIDTH, ...positioned.map(({ x, width }) => x + width));
542
+ const maximumY = Math.max(HEADER_HEIGHT + LARGE_NODE_HEIGHT, ...positioned.map(({ y, height }) => y + height));
532
543
  const width = Math.ceil(maximumX + PADDING);
533
544
  const height = Math.ceil(maximumY + PADDING);
534
545
  if (width > 16_384 || height > 16_384 || width * height > RENDER_MAX_PIXELS)
@@ -554,24 +565,29 @@ function svgFor(titleText, positioned, edges, sourceAccurate) {
554
565
  });
555
566
  const nodeSvg = positioned.map((node) => {
556
567
  const colour = colours(node.kind);
557
- const label = node.label.length > 34 ? `${node.label.slice(0, 31)}…` : node.label;
568
+ const small = node.layoutSize === 'small';
569
+ const labelLimit = small ? 12 : 34;
570
+ const label = node.label.length > labelLimit
571
+ ? `${node.label.slice(0, Math.max(1, labelLimit - 1))}…`
572
+ : node.label;
558
573
  const subtitle = node.subtitle.length > 48 ? `${node.subtitle.slice(0, 45)}…` : node.subtitle;
559
574
  const labelSvg = text.render(label, {
560
- x: node.x + 12,
561
- y: node.y + 30,
562
- fontSize: 15,
575
+ x: node.x + (small ? 6 : 12),
576
+ y: node.y + (small ? 27 : 30),
577
+ fontSize: small ? 9 : 15,
563
578
  fill: '#f1f5f8',
564
579
  weight: 600,
565
- targetWidth: Math.min(node.width - 24, Math.max(1, text.measure(label, 15))),
580
+ targetWidth: Math.min(node.width - (small ? 12 : 24), Math.max(1, text.measure(label, small ? 9 : 15))),
566
581
  });
567
- const subtitleSvg = text.render(subtitle, {
568
- x: node.x + 12,
569
- y: node.y + 56,
570
- fontSize: 11,
582
+ const subtitleSvg = text.render(small ? 'SMALL' : subtitle, {
583
+ x: node.x + (small ? 6 : 12),
584
+ y: node.y + (small ? 51 : 58),
585
+ fontSize: small ? 8 : 11,
571
586
  fill: '#b8c4ce',
572
- targetWidth: Math.min(node.width - 24, Math.max(1, text.measure(subtitle, 11))),
587
+ targetWidth: Math.min(node.width - (small ? 12 : 24), Math.max(1, text.measure(small ? 'SMALL' : subtitle, small ? 8 : 11))),
573
588
  });
574
- return `<g data-node-id="${escapeXml(node.id)}"${node.sourcePath === undefined ? '' : ` data-source-path="${escapeXml(node.sourcePath)}" data-source-line="${node.sourceLine ?? 1}"`}><rect x="${node.x}" y="${node.y}" width="${node.width}" height="${node.height}" rx="8" fill="${colour.fill}" stroke="${colour.stroke}" stroke-width="2"/><title>${escapeXml(`${node.id}${node.sourcePath === undefined ? '' : ` · ${node.sourcePath}:${node.sourceLine ?? 1}`}`)}</title>${labelSvg}${subtitleSvg}</g>`;
589
+ const layoutAttribute = node.layoutSize === undefined ? '' : ` data-layout-size="${node.layoutSize}"`;
590
+ return `<g data-node-id="${escapeXml(node.id)}"${layoutAttribute}${node.sourcePath === undefined ? '' : ` data-source-path="${escapeXml(node.sourcePath)}" data-source-line="${node.sourceLine ?? 1}"`}><rect x="${node.x}" y="${node.y}" width="${node.width}" height="${node.height}" rx="8" fill="${colour.fill}" stroke="${colour.stroke}" stroke-width="2"/><title>${escapeXml(`${node.id}${node.layoutSize === undefined ? '' : ` · ${node.layoutSize} layout`}${node.sourcePath === undefined ? '' : ` · ${node.sourcePath}:${node.sourceLine ?? 1}`}`)}</title>${labelSvg}${subtitleSvg}</g>`;
575
591
  });
576
592
  const title = text.render(titleText, {
577
593
  x: PADDING,
@@ -348,6 +348,13 @@ function parseTechnologyDefinitions(file, document, fragment) {
348
348
  .map(({ key }) => key.value)
349
349
  .filter((key) => !technologyStructuralFields.has(key) && !key.startsWith('@'))),
350
350
  ].sort(compareCodeUnits);
351
+ const layoutExpression = firstValue(block, 'force_use_small_tech_layout');
352
+ const smallLayout = booleanValue(layoutExpression);
353
+ const layoutSize = layoutExpression === undefined || smallLayout === false
354
+ ? 'large'
355
+ : smallLayout === true
356
+ ? 'small'
357
+ : 'unknown';
351
358
  const unsupportedFields = fragment.placements
352
359
  .filter(({ technologyId, xExpression, yExpression }) => technologyId === id && (xExpression !== undefined || yExpression !== undefined))
353
360
  .map((placement) => ({
@@ -355,7 +362,17 @@ function parseTechnologyDefinitions(file, document, fragment) {
355
362
  expression: `${placement.xExpression ?? placement.x ?? '?'}:${placement.yExpression ?? placement.y ?? '?'}`,
356
363
  location: placement.location,
357
364
  reason: 'The source coordinate expression is not a resolvable file-local numeric constant',
358
- }));
365
+ }))
366
+ .concat(layoutSize === 'unknown'
367
+ ? [
368
+ {
369
+ field: 'force_use_small_tech_layout',
370
+ expression: layoutExpression,
371
+ location: nodeLocation(document, block, id),
372
+ reason: 'The technology layout-size expression is not a literal yes or no',
373
+ },
374
+ ]
375
+ : []);
359
376
  const doctrine = booleanValue(firstValue(block, 'doctrine')) === true;
360
377
  fragment.technologies.push({
361
378
  id,
@@ -372,6 +389,7 @@ function parseTechnologyDefinitions(file, document, fragment) {
372
389
  ? {}
373
390
  : { doctrineName: firstValue(block, 'doctrine_name') }),
374
391
  hidden: hiddenStatus(block),
392
+ layoutSize,
375
393
  folders: [...new Set(folders)].sort(compareCodeUnits),
376
394
  categories: [...new Set(categories)].sort(compareCodeUnits),
377
395
  tags: [...new Set(tags)].sort(compareCodeUnits),
@@ -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 = '2.5.1';
3
+ export const PACKAGE_VERSION = '2.5.2';
4
4
  export const MCP_PROTOCOL_VERSION = LATEST_PROTOCOL_VERSION;
5
5
  export const CONFIG_VERSION = 1;
6
6
  export const TRANSACTION_VERSION = 1;
@@ -51,7 +51,7 @@ Game-backed and otherwise large workspaces automatically use focused analysis mo
51
51
 
52
52
  `hoi4.tech_render` returns authoritative JSON with deterministic SVG and PNG resources; set `includeHtml` when a bundled static report is useful. Available views are `summary`, `folder`, `dependencies`, `technology`, `doctrine`, `exclusive`, `memberships`, `bonuses`, `grants`, `unlocks`, `metadata`, `assets`, and `unresolved`.
53
53
 
54
- Folder renders use the actual folder assignments, gridbox geometry, and technology coordinates found in source. Dependency and other semantic views are explicitly labelled as generated analysis layouts. Missing sprites, textures, or localisation remain identifiable from JSON and vector output even when no icon raster is decoded.
54
+ Folder renders use the actual folder assignments, gridbox geometry, technology coordinates, and HOI4 item size found in source. Technologies with `force_use_small_tech_layout = yes` render as 72×72 small items; normal technologies render as large items. The authoritative JSON and SVG expose `layoutSize` for every technology. Dependency and other semantic views are explicitly labelled as generated analysis layouts. Missing sprites, textures, or localisation remain identifiable from JSON and vector output even when no icon raster is decoded.
55
55
 
56
56
  Example folder render:
57
57
 
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": "2.5.1",
4
+ "version": "2.5.2",
5
5
  "description": "Analyze HOI4 events, tech trees, AI weights, and MTTH; build focus trees, GUIs, and maps.",
6
6
  "type": "module",
7
7
  "license": "Apache-2.0",
@@ -1,5 +1,5 @@
1
1
  {
2
- "$id": "https://github.com/klimPaskov/hoi4-agent-tools/blob/v2.5.1/schemas/configuration.schema.json",
2
+ "$id": "https://github.com/klimPaskov/hoi4-agent-tools/blob/v2.5.2/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/v2.5.1/schemas/continuous-focus-palette.schema.json",
2
+ "$id": "https://github.com/klimPaskov/hoi4-agent-tools/blob/v2.5.2/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/v2.5.1/schemas/custom-weighted-pool.schema.json",
2
+ "$id": "https://github.com/klimPaskov/hoi4-agent-tools/blob/v2.5.2/schemas/custom-weighted-pool.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/v2.5.1/schemas/event-feature-manifest.schema.json",
2
+ "$id": "https://github.com/klimPaskov/hoi4-agent-tools/blob/v2.5.2/schemas/event-feature-manifest.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/v2.5.1/schemas/focus-plan.schema.json",
2
+ "$id": "https://github.com/klimPaskov/hoi4-agent-tools/blob/v2.5.2/schemas/focus-plan.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/v2.5.1/schemas/focus-planning-sidecar.schema.json",
2
+ "$id": "https://github.com/klimPaskov/hoi4-agent-tools/blob/v2.5.2/schemas/focus-planning-sidecar.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/v2.5.1/schemas/gui-animation-source.schema.json",
2
+ "$id": "https://github.com/klimPaskov/hoi4-agent-tools/blob/v2.5.2/schemas/gui-animation-source.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/v2.5.1/schemas/gui-helper.schema.json",
2
+ "$id": "https://github.com/klimPaskov/hoi4-agent-tools/blob/v2.5.2/schemas/gui-helper.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/v2.5.1/schemas/gui-scenario.schema.json",
2
+ "$id": "https://github.com/klimPaskov/hoi4-agent-tools/blob/v2.5.2/schemas/gui-scenario.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/v2.5.1/schemas/map-operation.schema.json",
2
+ "$id": "https://github.com/klimPaskov/hoi4-agent-tools/blob/v2.5.2/schemas/map-operation.schema.json",
3
3
  "$schema": "https://json-schema.org/draft/2020-12/schema",
4
4
  "oneOf": [
5
5
  {
@@ -1,5 +1,5 @@
1
1
  {
2
- "$id": "https://github.com/klimPaskov/hoi4-agent-tools/blob/v2.5.1/schemas/operation-result.schema.json",
2
+ "$id": "https://github.com/klimPaskov/hoi4-agent-tools/blob/v2.5.2/schemas/operation-result.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/v2.5.1/schemas/probability-analysis-result.schema.json",
2
+ "$id": "https://github.com/klimPaskov/hoi4-agent-tools/blob/v2.5.2/schemas/probability-analysis-result.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/v2.5.1/schemas/probability-compare-input.schema.json",
2
+ "$id": "https://github.com/klimPaskov/hoi4-agent-tools/blob/v2.5.2/schemas/probability-compare-input.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/v2.5.1/schemas/probability-evaluate-input.schema.json",
2
+ "$id": "https://github.com/klimPaskov/hoi4-agent-tools/blob/v2.5.2/schemas/probability-evaluate-input.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/v2.5.1/schemas/probability-inspect-input.schema.json",
2
+ "$id": "https://github.com/klimPaskov/hoi4-agent-tools/blob/v2.5.2/schemas/probability-inspect-input.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/v2.5.1/schemas/probability-render-input.schema.json",
2
+ "$id": "https://github.com/klimPaskov/hoi4-agent-tools/blob/v2.5.2/schemas/probability-render-input.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/v2.5.1/schemas/probability-scenario-set.schema.json",
2
+ "$id": "https://github.com/klimPaskov/hoi4-agent-tools/blob/v2.5.2/schemas/probability-scenario-set.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/v2.5.1/schemas/probability-sequence-input.schema.json",
2
+ "$id": "https://github.com/klimPaskov/hoi4-agent-tools/blob/v2.5.2/schemas/probability-sequence-input.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/v2.5.1/schemas/probability-simulate-input.schema.json",
2
+ "$id": "https://github.com/klimPaskov/hoi4-agent-tools/blob/v2.5.2/schemas/probability-simulate-input.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/v2.5.1/schemas/probability-sweep-input.schema.json",
2
+ "$id": "https://github.com/klimPaskov/hoi4-agent-tools/blob/v2.5.2/schemas/probability-sweep-input.schema.json",
3
3
  "$schema": "https://json-schema.org/draft/2020-12/schema",
4
4
  "type": "object",
5
5
  "properties": {
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 events, tech trees, AI weights, and MTTH; build focus trees, GUIs, and maps.",
6
- "version": "2.5.1",
6
+ "version": "2.5.2",
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": "2.5.1",
16
+ "version": "2.5.2",
17
17
  "transport": {
18
18
  "type": "stdio"
19
19
  }