hoi4-agent-tools 4.0.4 → 4.0.5

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 (47) hide show
  1. package/CHANGELOG.md +8 -0
  2. package/dist/hoi4_agent_tools/gui/layout.js +61 -25
  3. package/dist/hoi4_agent_tools/gui/native-state.js +40 -1
  4. package/dist/hoi4_agent_tools/gui/source-graph.js +9 -6
  5. package/dist/hoi4_agent_tools/gui/studio.js +4 -1
  6. package/dist/hoi4_agent_tools/version.js +1 -1
  7. package/docs/gui.md +6 -2
  8. package/npm-shrinkwrap.json +2 -2
  9. package/package.json +1 -1
  10. package/schemas/configuration.schema.json +1 -1
  11. package/schemas/continuous-focus-palette.schema.json +1 -1
  12. package/schemas/custom-weighted-pool.schema.json +1 -1
  13. package/schemas/decision-inspect-input.schema.json +1 -1
  14. package/schemas/error-log-input.schema.json +1 -1
  15. package/schemas/event-feature-manifest.schema.json +1 -1
  16. package/schemas/focus-plan.schema.json +1 -1
  17. package/schemas/focus-planning-sidecar.schema.json +1 -1
  18. package/schemas/gui-animation-source.schema.json +1 -1
  19. package/schemas/gui-helper.schema.json +1 -1
  20. package/schemas/gui-scenario.schema.json +1 -1
  21. package/schemas/helper-expansion-request.schema.json +1 -1
  22. package/schemas/helper-expansion-summary.schema.json +1 -1
  23. package/schemas/impact-inspect-input.schema.json +1 -1
  24. package/schemas/map-operation.schema.json +1 -1
  25. package/schemas/mechanic-test-input.schema.json +1 -1
  26. package/schemas/mod-index-input.schema.json +1 -1
  27. package/schemas/operation-result.schema.json +1 -1
  28. package/schemas/package-check-input.schema.json +1 -1
  29. package/schemas/package-manifest.schema.json +1 -1
  30. package/schemas/probability-analysis-result.schema.json +1 -1
  31. package/schemas/probability-compare-input.schema.json +1 -1
  32. package/schemas/probability-evaluate-input.schema.json +1 -1
  33. package/schemas/probability-inspect-input.schema.json +1 -1
  34. package/schemas/probability-render-input.schema.json +1 -1
  35. package/schemas/probability-scenario-set.schema.json +1 -1
  36. package/schemas/probability-sequence-input.schema.json +1 -1
  37. package/schemas/probability-simulate-input.schema.json +1 -1
  38. package/schemas/probability-sweep-input.schema.json +1 -1
  39. package/schemas/reference-context-input.schema.json +1 -1
  40. package/schemas/reference-read-input.schema.json +1 -1
  41. package/schemas/reference-search-input.schema.json +1 -1
  42. package/schemas/scenario-suite.schema.json +1 -1
  43. package/schemas/scenario-test-input.schema.json +1 -1
  44. package/schemas/script-validate-input.schema.json +1 -1
  45. package/schemas/shared-scenario.schema.json +1 -1
  46. package/schemas/source-lookup-input.schema.json +1 -1
  47. package/server.json +2 -2
package/CHANGELOG.md CHANGED
@@ -2,6 +2,14 @@
2
2
 
3
3
  ## Unreleased
4
4
 
5
+ ## 4.0.5 - 2026-10-14
6
+
7
+ - Keep child anchors independent of parent `origo`, so centered native windows place their controls inside the frame.
8
+ - Preview division and HQ branches separately and close native selector overlays by default. Existing scenario values and visibility bindings select panels explicitly.
9
+ - Preserve dropdown button and expanded-panel boundaries, including closed visibility, settled positions, backgrounds, clipping and attached scrollbars.
10
+ - Render background-free scroll containers using their declared viewport bounds; retain findings for explicitly disabled clipping and invalid boundaries or references.
11
+ - Resolve public scrollbar templates despite unrelated private namesakes. Public tool schemas and dependency versions are unchanged.
12
+
5
13
  ## 4.0.4 - 2026-10-14
6
14
 
7
15
  - Preview individual GUI windows without redundant full symbol indexes, workspace-wide asset fallback or unbound country-flag inventories; reuse condition definitions across render variants.
@@ -629,11 +629,12 @@ function explicitElementVisibility(definition, scenario, rowValues) {
629
629
  visibilityValue(scripted));
630
630
  }
631
631
  /** Source visibility: `visible` and `show` mean shown when true, `hide` and `hidden` when false. */
632
- function declaredVisibility(attributes) {
632
+ function declaredVisibility(attributes, fallback = true) {
633
633
  const visible = scalarBoolean(property(attributes, 'visible', 'show'));
634
634
  if (visible !== undefined)
635
635
  return visible;
636
- return !(scalarBoolean(property(attributes, 'hide', 'hidden')) ?? false);
636
+ const hidden = scalarBoolean(property(attributes, 'hide', 'hidden'));
637
+ return hidden === undefined ? fallback : !hidden;
637
638
  }
638
639
  function clippedByChain(chain) {
639
640
  let result;
@@ -694,7 +695,7 @@ function refreshSceneClips(context) {
694
695
  }
695
696
  }
696
697
  function attachedScrollbars(definition, context) {
697
- if (!/^(?:containerwindowtype|windowtype)$/iu.test(definition.elementType))
698
+ if (!/^(?:containerwindowtype|windowtype|expandedwindow)$/iu.test(definition.elementType))
698
699
  return [];
699
700
  const result = [];
700
701
  const add = (candidate, horizontal, reference) => {
@@ -718,8 +719,10 @@ function attachedScrollbars(definition, context) {
718
719
  for (const horizontal of [false, true]) {
719
720
  const name = scalarString(property(definition.attributes, horizontal ? 'horizontalScrollbar' : 'verticalScrollbar'));
720
721
  if (name !== undefined) {
721
- const candidate = context.elementsByName.get(name);
722
- add(candidate?.parentId === undefined ? candidate : undefined, horizontal, name);
722
+ const candidate = context.elementsByNameCandidates
723
+ .get(name)
724
+ ?.find((element) => element.parentId === undefined);
725
+ add(candidate, horizontal, name);
723
726
  }
724
727
  }
725
728
  for (const id of definition.childIds) {
@@ -1218,10 +1221,13 @@ async function layoutElement(definition, parentRect, inheritedClip, parentScale,
1218
1221
  const clipChain = inheritedClipChain ?? (inheritedClip === undefined ? [] : [inheritedClip]);
1219
1222
  const localScale = scalarNumber(property(definition.attributes, 'scale'), 1) ?? 1;
1220
1223
  const scale = parentScale * localScale;
1221
- const shownPosition = depth === 0 ? objectProperty(property(definition.attributes, 'show_position')) : undefined;
1224
+ const expandedWindow = definition.elementType.toLowerCase() === 'expandedwindow';
1225
+ const shownPosition = depth === 0 || expandedWindow
1226
+ ? objectProperty(property(definition.attributes, 'show_position'))
1227
+ : undefined;
1222
1228
  const position = shownPosition ?? objectProperty(property(definition.attributes, 'position'));
1223
1229
  if (shownPosition !== undefined) {
1224
- addFidelity(fidelity, 'modelled', 'window_show_position', 'The requested root window uses its declared settled show position.', definition);
1230
+ addFidelity(fidelity, 'modelled', 'window_show_position', 'The requested window uses its declared settled show position.', definition);
1225
1231
  }
1226
1232
  const size = objectProperty(property(definition.attributes, 'size'));
1227
1233
  const scriptedX = rowValues?.[`${definition.name}.x`] ??
@@ -1277,13 +1283,19 @@ async function layoutElement(definition, parentRect, inheritedClip, parentScale,
1277
1283
  width = Math.max(0, parentRect.width - localX + width);
1278
1284
  if (height < 0)
1279
1285
  height = Math.max(0, parentRect.height - localY + height);
1280
- const explicitlyVisible = explicitElementVisibility(definition, scenario, rowValues);
1286
+ const explicitlyVisible = explicitElementVisibility(definition, scenario, rowValues) ??
1287
+ context.nativeVisibility.get(definition.id);
1281
1288
  const unresolvedVisibilityReason = context.unresolvedElementVisibility.get(definition.name);
1282
1289
  const parentSceneElement = parentInstanceId === undefined ? undefined : context.instancesById.get(parentInstanceId);
1283
1290
  const parentUnresolvedVisibility = parentSceneElement?.visibilityStatus === 'unresolved'
1284
1291
  ? parentSceneElement.visibilityStatusReason
1285
1292
  : undefined;
1286
- const sourceVisible = declaredVisibility(definition.attributes);
1293
+ const dropdown = definition.parentId === undefined ? undefined : context.elementsById.get(definition.parentId);
1294
+ const sourceVisible = declaredVisibility(definition.attributes, !expandedWindow ||
1295
+ depth === 0 ||
1296
+ visibilityValue(rowValues?.[`${dropdown?.name}.expanded`] ?? scenario.values[`${dropdown?.name}.expanded`]) === true);
1297
+ if (expandedWindow)
1298
+ addFidelity(fidelity, 'modelled', 'native_dropdown', 'Dropdown expansion is closed by default; bind <dropdown>.expanded or explicit panel visibility to show its settled position.', definition);
1287
1299
  const resolveVisibleAppearance = inheritedVisible && (explicitlyVisible ?? sourceVisible);
1288
1300
  const scriptedEnabled = rowValues?.[`${definition.name}.enabled`] ??
1289
1301
  scenario.values[`${definition.name}.enabled`] ??
@@ -1619,12 +1631,13 @@ async function layoutElement(definition, parentRect, inheritedClip, parentScale,
1619
1631
  else if (origoAxes.vertical === 'bottom')
1620
1632
  y -= height;
1621
1633
  const unclippedRect = { x, y, width: Math.max(0, width), height: Math.max(0, height) };
1622
- const ownClipping = scalarBoolean(property(definition.attributes, 'clipping')) ??
1623
- (backgrounds.length > 0 && /(?:containerwindow|windowtype)/iu.test(definition.elementType));
1624
1634
  let scrollbars = attachedScrollbars(definition, context);
1625
- if (scrollbars.length > 0 && (!ownClipping || backgrounds.length === 0)) {
1626
- diagnostics.push(diagnostic('GUI_SCROLLBAR_CONTAINER_BOUNDARY_MISSING', 'warning', `Container ${definition.name} needs a background and clipping for attached scrolling.`, definition));
1627
- addFidelity(fidelity, 'unsupported', 'attached_scrollbar', 'The container has no active clipped background boundary.', definition);
1635
+ const ownClipping = scalarBoolean(property(definition.attributes, 'clipping')) ??
1636
+ ((backgrounds.length > 0 || scrollbars.length > 0) &&
1637
+ /(?:containerwindow|windowtype|expandedwindow)/iu.test(definition.elementType));
1638
+ if (scrollbars.length > 0 && (!ownClipping || width <= 0 || height <= 0)) {
1639
+ diagnostics.push(diagnostic('GUI_SCROLLBAR_CONTAINER_BOUNDARY_MISSING', 'warning', `Container ${definition.name} needs a positive-sized clipping boundary for attached scrolling.`, definition));
1640
+ addFidelity(fidelity, 'unsupported', 'attached_scrollbar', 'The container has no active clipping boundary.', definition);
1628
1641
  scrollbars = [];
1629
1642
  }
1630
1643
  const margin = scrollbars.length === 0 ? undefined : objectProperty(property(definition.attributes, 'margin'));
@@ -1835,10 +1848,12 @@ async function layoutElement(definition, parentRect, inheritedClip, parentScale,
1835
1848
  const childDefinitions = await scrollbarChildren(definition, definition.childIds
1836
1849
  .map((id) => context.elementsById.get(id))
1837
1850
  .filter((element) => element !== undefined)
1838
- .filter((element) => !/^(?:containerwindowtype|windowtype)$/iu.test(definition.elementType) ||
1851
+ .filter((element) => !/^(?:containerwindowtype|windowtype|expandedwindow)$/iu.test(definition.elementType) ||
1839
1852
  element.elementType.toLowerCase() !== 'extendedscrollbartype')
1840
- .sort((left, right) => (scalarNumber(property(left.attributes, 'priority'), 0) ?? 0) -
1841
- (scalarNumber(property(right.attributes, 'priority'), 0) ?? 0) ||
1853
+ .sort((left, right) => Number(context.nativeForeground.has(left.id)) -
1854
+ Number(context.nativeForeground.has(right.id)) ||
1855
+ (scalarNumber(property(left.attributes, 'priority'), 0) ?? 0) -
1856
+ (scalarNumber(property(right.attributes, 'priority'), 0) ?? 0) ||
1842
1857
  left.definitionOrder - right.definitionOrder), unclippedRect, scale, context, rowValues);
1843
1858
  const rowList = rowValues?.[`${definition.name}.list`];
1844
1859
  let rows = (typeof rowList === 'string' ? scenario.lists[rowList] : undefined) ??
@@ -1908,7 +1923,7 @@ async function layoutElement(definition, parentRect, inheritedClip, parentScale,
1908
1923
  ...(slotWidth === undefined ? {} : { width: slotWidth }),
1909
1924
  ...(slotHeight === undefined ? {} : { height: slotHeight }),
1910
1925
  };
1911
- await layoutElement(child, shiftedParent, childClip, scale, depth + 1, context, rowSuffix(index), index, row, instanceId, origo, resolveVisibleAppearance, childClipChain);
1926
+ await layoutElement(child, shiftedParent, childClip, scale, depth + 1, context, rowSuffix(index), index, row, instanceId, 'upper_left', resolveVisibleAppearance, childClipChain);
1912
1927
  const rendered = context.instancesById.get(`${child.id}${rowSuffix(index)}`);
1913
1928
  rowHeight = Math.max(rowHeight, rendered?.unclippedRect.height ?? 0);
1914
1929
  }
@@ -1960,7 +1975,7 @@ async function layoutElement(definition, parentRect, inheritedClip, parentScale,
1960
1975
  ...(slotWidth === undefined ? {} : { width: slotWidth }),
1961
1976
  ...(slotHeight === undefined ? {} : { height: slotHeight }),
1962
1977
  };
1963
- await layoutElement(template, shiftedParent, childClip, scale, depth + 1, context, rowSuffix(index), index, row, instanceId, origo, resolveVisibleAppearance, childClipChain);
1978
+ await layoutElement(template, shiftedParent, childClip, scale, depth + 1, context, rowSuffix(index), index, row, instanceId, 'upper_left', resolveVisibleAppearance, childClipChain);
1964
1979
  const rendered = context.instancesById.get(`${template.id}${rowSuffix(index)}`);
1965
1980
  rowY += Math.max(slotHeight ?? 0, rendered?.unclippedRect.height ?? 0) + spacingY;
1966
1981
  renderedRows += 1;
@@ -1970,7 +1985,7 @@ async function layoutElement(definition, parentRect, inheritedClip, parentScale,
1970
1985
  else {
1971
1986
  for (const child of childDefinitions) {
1972
1987
  context.work.spend('nested child expansion');
1973
- await layoutElement(child, childParentRect, childClip, scale, depth + 1, context, instanceSuffix, rowIndex, rowValues, instanceId, origo, resolveVisibleAppearance, childClipChain);
1988
+ await layoutElement(child, childParentRect, childClip, scale, depth + 1, context, instanceSuffix, rowIndex, rowValues, instanceId, 'upper_left', resolveVisibleAppearance, childClipChain);
1974
1989
  }
1975
1990
  }
1976
1991
  const childOutput = context.output.slice(firstChildOutput);
@@ -2195,10 +2210,14 @@ export async function buildGuiScene(graph, scannedFiles, windowName, scenario, c
2195
2210
  if (native !== undefined) {
2196
2211
  for (const note of native.notes)
2197
2212
  addFidelity(fidelity, 'modelled', 'native_window_state', note);
2198
- const { sources } = native.state;
2199
- if (native.state.tag === undefined ||
2200
- sources.faction === 'default' ||
2201
- sources.balanceOfPower === 'default')
2213
+ for (const note of native.approximations ?? [])
2214
+ addFidelity(fidelity, 'approximated', 'native_window_state', note);
2215
+ const sources = native.state?.sources;
2216
+ if (native.state !== undefined &&
2217
+ sources !== undefined &&
2218
+ (native.state.tag === undefined ||
2219
+ sources.faction === 'default' ||
2220
+ sources.balanceOfPower === 'default'))
2202
2221
  addFidelity(fidelity, 'approximated', 'native_window_state', native.state.tag === undefined
2203
2222
  ? 'The scenario names no country, so the window shows the state of a country in no faction and without a balance of power; set country.tag or the country faction, balanceOfPower and ideology facts.'
2204
2223
  : `No history for ${native.state.tag} was available, so its faction and balance of power default to none; set country.faction, country.balanceOfPower and country.ideology to override.`);
@@ -2211,7 +2230,6 @@ export async function buildGuiScene(graph, scannedFiles, windowName, scenario, c
2211
2230
  ...scenario.values,
2212
2231
  },
2213
2232
  visibility: {
2214
- ...(native?.visibility ?? {}),
2215
2233
  ...scriptedWindowVisibility,
2216
2234
  ...constantElementVisibility,
2217
2235
  ...scenario.visibility,
@@ -2229,6 +2247,24 @@ export async function buildGuiScene(graph, scannedFiles, windowName, scenario, c
2229
2247
  elementsByNameCandidates.set(element.name, candidates);
2230
2248
  }
2231
2249
  const context = {
2250
+ nativeForeground: new Set(graph.elements
2251
+ .filter((element) => element.parentId === root.id && native?.foreground?.includes(element.name))
2252
+ .map(({ id }) => id)),
2253
+ nativeVisibility: new Map(graph.elements.flatMap((element) => {
2254
+ const visible = native?.visibility[element.name];
2255
+ if (visible === undefined)
2256
+ return [];
2257
+ // The designer reuses names (including division_title) inside selector panels.
2258
+ // Its branch decisions apply to root controls, not identically named descendants.
2259
+ if (windowName === 'countrydivisiondesignerview' && element.parentId !== root.id) {
2260
+ const parent = element.parentId === undefined ? undefined : elementsById.get(element.parentId);
2261
+ if (element.name !== 'hq_badge' ||
2262
+ parent?.name !== 'template_emblem_slot' ||
2263
+ parent.parentId !== root.id)
2264
+ return [];
2265
+ }
2266
+ return [[element.id, visible]];
2267
+ })),
2232
2268
  graph,
2233
2269
  scenario: layoutScenario,
2234
2270
  catalog,
@@ -205,13 +205,52 @@ export function resolveNativeCountryState(scenario, files) {
205
205
  }
206
206
  /** Whether any native decision can apply to this window, so the country state is worth resolving. */
207
207
  export function windowHasNativeState(windowName, elementNames) {
208
- return (NATIVE_BRANCHES[windowName] !== undefined ||
208
+ return (windowName === 'countrydivisiondesignerview' ||
209
+ NATIVE_BRANCHES[windowName] !== undefined ||
209
210
  Object.keys(IDEOLOGY_FRAME_ICONS).some((name) => elementNames.has(name)));
210
211
  }
211
212
  /** The engine-selected branches and frames for a scene, below any explicit scenario input. */
212
213
  export function nativeWindowState(windowName, elementNames, scenario, files) {
213
214
  if (!windowHasNativeState(windowName, elementNames))
214
215
  return undefined;
216
+ if (windowName === 'countrydivisiondesignerview') {
217
+ const hq = scenario.values['countrydivisiondesignerview.hq'] === true;
218
+ const panel = scenario.values['countrydivisiondesignerview.panel'];
219
+ const visibility = {};
220
+ for (const name of ['hq_overlay_images', 'subunits_hq', 'hq_view', 'hq_title', 'hq_badge'])
221
+ if (elementNames.has(name))
222
+ visibility[name] = hq;
223
+ for (const name of [
224
+ 'subunits',
225
+ 'non_hq_view',
226
+ 'division_title',
227
+ 'division_composition_label',
228
+ 'combat_width_view',
229
+ ])
230
+ if (elementNames.has(name))
231
+ visibility[name] = !hq;
232
+ const selectors = [
233
+ 'designerregimentswindow',
234
+ 'division_equipment_view',
235
+ 'div_templ_custom_icon_view',
236
+ 'div_template_select_model',
237
+ 'niche_icon_selector',
238
+ ];
239
+ for (const name of selectors)
240
+ if (elementNames.has(name))
241
+ visibility[name] = panel === name;
242
+ return {
243
+ visibility,
244
+ values: {},
245
+ foreground: selectors,
246
+ notes: [
247
+ `Division designer uses the ${hq ? 'HQ' : 'division'} branch and only the explicitly selected native selector panel.`,
248
+ ],
249
+ approximations: [
250
+ 'Native division state is a preview convention: defaults to a division with selectors closed. Set values countrydivisiondesignerview.hq and countrydivisiondesignerview.panel, or explicit element visibility. Engine-populated rows and statistics require scenario bindings.',
251
+ ],
252
+ };
253
+ }
215
254
  const state = resolveNativeCountryState(scenario, files);
216
255
  const visibility = {};
217
256
  const values = {};
@@ -119,7 +119,7 @@ export function guiElementAttributeFidelity(key, elementType) {
119
119
  if (elementType?.toLowerCase() === 'extendedscrollbartype' &&
120
120
  ['horizontal', 'slider', 'track', 'decreaseButton', 'increaseButton'].some((candidate) => candidate.toLowerCase() === key.toLowerCase()))
121
121
  return 'modelled';
122
- if (/^(?:containerwindowtype|windowtype)$/iu.test(elementType ?? '') &&
122
+ if (/^(?:containerwindowtype|windowtype|expandedwindow)$/iu.test(elementType ?? '') &&
123
123
  ['verticalScrollbar', 'horizontalScrollbar', 'autohide_scrollbars', 'margin'].some((candidate) => candidate.toLowerCase() === key.toLowerCase()))
124
124
  return 'structural';
125
125
  if (elementType?.toLowerCase() === 'scrollbartype' &&
@@ -298,9 +298,12 @@ function nestedSizeFrom(block, key) {
298
298
  function raw(document, node) {
299
299
  return document.text.slice(node.start, node.end);
300
300
  }
301
- function isGuiElement(assignment) {
301
+ function isGuiElement(assignment, parentType) {
302
302
  if (assignment.value.type !== 'block')
303
303
  return false;
304
+ if (parentType?.toLowerCase() === 'dropdownboxtype' &&
305
+ /^(?:expandedwindow|expandbutton)$/iu.test(assignment.key.value))
306
+ return true;
304
307
  if (explicitGuiElementTypes.has(assignment.key.value.toLowerCase()))
305
308
  return true;
306
309
  return (/type$/iu.test(assignment.key.value) && firstScalar(assignment.value, 'name') !== undefined);
@@ -363,11 +366,11 @@ function indexGuiElements(document, file, fileNodeId, nodes, edges, elements) {
363
366
  const constants = constantsFor(document);
364
367
  const firstFileElement = elements.length;
365
368
  let order = 0;
366
- const walk = (block, parentId) => {
369
+ const walk = (block, parentId, parentType) => {
367
370
  for (const assignment of assignments(block)) {
368
371
  if (assignment.value.type !== 'block')
369
372
  continue;
370
- if (isGuiElement(assignment)) {
373
+ if (isGuiElement(assignment, parentType)) {
371
374
  const name = firstScalar(assignment.value, 'name')?.value;
372
375
  if (name === undefined)
373
376
  continue;
@@ -386,7 +389,7 @@ function indexGuiElements(document, file, fileNodeId, nodes, edges, elements) {
386
389
  childIds: [],
387
390
  attributes: attributes,
388
391
  unsupportedAttributes: assignments(assignment.value)
389
- .filter((child) => !isGuiElement(child))
392
+ .filter((child) => !isGuiElement(child, assignment.key.value))
390
393
  .map(({ key }) => key.value)
391
394
  .filter((key) => guiElementAttributeFidelity(key, assignment.key.value) === 'unsupported')
392
395
  .sort((a, b) => compareCodeUnits(a, b)),
@@ -409,7 +412,7 @@ function indexGuiElements(document, file, fileNodeId, nodes, edges, elements) {
409
412
  addEdge(edges, 'contains', parentId ?? fileNodeId, id, true, {}, element.location);
410
413
  if (parentId !== undefined)
411
414
  addEdge(edges, 'parent', id, parentId, true, {}, element.location);
412
- walk(assignment.value, id);
415
+ walk(assignment.value, id, assignment.key.value);
413
416
  }
414
417
  else {
415
418
  walk(assignment.value, parentId);
@@ -1048,7 +1048,10 @@ export class ScriptedGuiStudio {
1048
1048
  const requiredNames = new Set([windowName, ...additionalTemplateNames]);
1049
1049
  for (const element of selectedLayoutElements)
1050
1050
  collectNamedAttributes(element.attributes, new Set(['verticalScrollbar', 'horizontalScrollbar', 'scrollbarType', 'scrollbartype']), requiredNames);
1051
- const availableNames = new Set(layoutGraph.elements.map(({ name }) => name));
1051
+ // Scrollbar and row references name public templates, not private controls with the same name.
1052
+ const availableNames = new Set(layoutGraph.elements.filter(({ parentId }) => parentId === undefined).map(({ name }) => name));
1053
+ if (layoutGraph.elements.some(({ name }) => name === windowName))
1054
+ availableNames.add(windowName);
1052
1055
  if ([...requiredNames].some((name) => !availableNames.has(name))) {
1053
1056
  const gameLayouts = await this.scanner.scan(workspace, {
1054
1057
  patterns: layoutPatterns,
@@ -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 = '4.0.4';
3
+ export const PACKAGE_VERSION = '4.0.5';
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/gui.md CHANGED
@@ -75,7 +75,7 @@ Bitmap text uses the language-appropriate HOI4 font definition and its real glyp
75
75
 
76
76
  `uiScale` is the in-game UI scale, not an image zoom. Use `1` for native pixel geometry at any screen resolution. Bitmap-font glyphs come directly from the real atlas without a sharpening, threshold, opacity-gain, or reconstructed-edge pass. Native-size coverage is unchanged. Enlarged coverage uses restrained Lanczos2 interpolation to avoid blocky pixel replication without running a sharpening filter. Downscaling uses nearest-neighbour sampling. Bitmap placement is snapped to the output pixel grid, and bitmap colours use alpha masks, so native, fractional-scale, local, and VPS renders remain deterministic.
77
77
 
78
- Layout follows Clausewitz orientation and element-origin anchors, including `CENTER_LEFT`, `CENTER_RIGHT`, `CENTER_UP`, `CENTER_DOWN`, `origo`, `centerposition`, inherited container coordinate origins, local scale, and both `%` and `%%` relative dimensions. Text boxes use native font metrics together with `maxWidth`, `maxHeight`, alignment, wrapping, and `fixedsize` clipping. Cornered tile sprites use fixed nine-slice borders and optional center tiling; progress bars composite their filled and background textures; masked shields composite their background and mask textures.
78
+ Layout follows Clausewitz orientation and element-origin anchors, including `CENTER_LEFT`, `CENTER_RIGHT`, `CENTER_UP`, `CENTER_DOWN`, `origo`, `centerposition`, local scale, and both `%` and `%%` relative dimensions. Children default to their parent's upper-left corner independently of the parent's `origo`. Text boxes use native font metrics together with `maxWidth`, `maxHeight`, alignment, wrapping, and `fixedsize` clipping. Cornered tile sprites use fixed nine-slice borders and optional center tiling; progress bars composite their filled and background textures; masked shields composite their background and mask textures.
79
79
 
80
80
  A single-percent dimension is a proportional extent; a double-percent dimension names the far edge in the parent and subtracts the element's resolved anchor position.
81
81
  For example, a centered root at y=423 with `height=85%%` in a 1440-pixel viewport ends at y=1224 and has height 801, rather than height 1224.
@@ -100,7 +100,11 @@ Supply `values["container.scrollX"]` and `values["container.scrollY"]` in native
100
100
  The existing `scrollOffsets` map remains a vertical-offset shorthand, including names with row-instance suffixes.
101
101
  `minimum-value` and `maximum-value` scenarios sample content endpoints.
102
102
  The scene element's `scroll` record exposes its viewport, measured content dimensions, applied offsets and maximum offsets in output pixels after UI scaling.
103
- Missing, wrong-axis, duplicate or privately scoped scrollbar references and unclipped/background-less containers produce explicit findings rather than invented templates.
103
+ Missing, wrong-axis, duplicate or privately scoped scrollbar references, nonpositive viewport sizes and explicitly unclipped containers produce findings rather than invented templates. An attached scrollbar establishes a clipped viewport by default, without requiring a decorative background; explicit `clipping = no` is diagnosed. A public template remains usable when an unrelated private child has the same name.
104
+
105
+ Native `dropDownBoxType` controls retain their `expandButton` and `expandedWindow` children. Expanded panels default to closed. Set `scenario.values["dropdown_name.expanded"] = true` to open one dropdown at its settled `show_position`; explicit panel visibility also works. A panel source ID can distinguish repeated `expanded_window` names. Its background, descendants, clipping and attached scrollbar share the panel's visibility. Animation between open and closed positions is not simulated.
106
+
107
+ `countrydivisiondesignerview` defaults to the ordinary division branch with its native selector panels closed. Set `scenario.values["countrydivisiondesignerview.hq"] = true` for the HQ branch. Set `scenario.values["countrydivisiondesignerview.panel"]` to `designerregimentswindow`, `division_equipment_view`, `div_templ_custom_icon_view`, `div_template_select_model` or `niche_icon_selector` to open that selector in front of ordinary root controls. Explicit element visibility or `name.visible` values override these defaults. The fidelity report identifies this preview convention; engine-populated rows, statistics and conditional icons still need explicit scenario bindings. No live division state is inferred.
104
108
 
105
109
  Scripted-GUI composition follows `parent_scripted_gui` chains even when the linked child window is a top-level sibling in the `.gui` file. Literal `always = yes` and `always = no` visibility and click-enabled blocks are applied automatically. A scenario's `values` object supplies concrete runtime values in one place: variable names resolve numeric text, scripted-localisation names resolve dynamic labels, a progress-bar element name sets its fill value, and element keys ending in `.image`, `.frame`, `.x`, `.y`, `.visible`, or `.enabled` update that visual property. Scripted-GUI property expressions such as `image = "[GetMeterSprite]"` or `x = meter_fill_width` consume matching scenario values automatically. Dynamic text is parsed after scenario and scripted-localisation substitution, so a runtime string containing `£command_power` or `£[GetResourceIcon]` renders the resolved inline HOI4 text icon instead of literal marker text. Dynamic lists instantiate their declared `entry_container` or `country_scope_entry_container`; each scenario row can select the country template with `countryScope`, choose an explicit `entryContainer`, provide `countryTag` and `ideology` for `GetFlag`, and supply row-scoped text, image, frame, position, visibility, and enabled values. Masked country sprites use the actual mask and overlay dimensions, so custom flag sizes are discovered from GFX assets rather than assumed by the renderer.
106
110
 
@@ -1,12 +1,12 @@
1
1
  {
2
2
  "name": "hoi4-agent-tools",
3
- "version": "4.0.4",
3
+ "version": "4.0.5",
4
4
  "lockfileVersion": 3,
5
5
  "requires": true,
6
6
  "packages": {
7
7
  "": {
8
8
  "name": "hoi4-agent-tools",
9
- "version": "4.0.4",
9
+ "version": "4.0.5",
10
10
  "license": "Apache-2.0",
11
11
  "dependencies": {
12
12
  "@fontsource-variable/roboto": "5.3.0",
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": "4.0.4",
4
+ "version": "4.0.5",
5
5
  "description": "Build HOI4 mods: focus trees, events, decisions, worlds, GUI previews, docs and AI balance.",
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/v4.0.4/schemas/configuration.schema.json",
2
+ "$id": "https://github.com/klimPaskov/hoi4-agent-tools/blob/v4.0.5/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/v4.0.4/schemas/continuous-focus-palette.schema.json",
2
+ "$id": "https://github.com/klimPaskov/hoi4-agent-tools/blob/v4.0.5/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/v4.0.4/schemas/custom-weighted-pool.schema.json",
2
+ "$id": "https://github.com/klimPaskov/hoi4-agent-tools/blob/v4.0.5/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/v4.0.4/schemas/decision-inspect-input.schema.json",
2
+ "$id": "https://github.com/klimPaskov/hoi4-agent-tools/blob/v4.0.5/schemas/decision-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/v4.0.4/schemas/error-log-input.schema.json",
2
+ "$id": "https://github.com/klimPaskov/hoi4-agent-tools/blob/v4.0.5/schemas/error-log-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/v4.0.4/schemas/event-feature-manifest.schema.json",
2
+ "$id": "https://github.com/klimPaskov/hoi4-agent-tools/blob/v4.0.5/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/v4.0.4/schemas/focus-plan.schema.json",
2
+ "$id": "https://github.com/klimPaskov/hoi4-agent-tools/blob/v4.0.5/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/v4.0.4/schemas/focus-planning-sidecar.schema.json",
2
+ "$id": "https://github.com/klimPaskov/hoi4-agent-tools/blob/v4.0.5/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/v4.0.4/schemas/gui-animation-source.schema.json",
2
+ "$id": "https://github.com/klimPaskov/hoi4-agent-tools/blob/v4.0.5/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/v4.0.4/schemas/gui-helper.schema.json",
2
+ "$id": "https://github.com/klimPaskov/hoi4-agent-tools/blob/v4.0.5/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/v4.0.4/schemas/gui-scenario.schema.json",
2
+ "$id": "https://github.com/klimPaskov/hoi4-agent-tools/blob/v4.0.5/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/v4.0.4/schemas/helper-expansion-request.schema.json",
2
+ "$id": "https://github.com/klimPaskov/hoi4-agent-tools/blob/v4.0.5/schemas/helper-expansion-request.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/v4.0.4/schemas/helper-expansion-summary.schema.json",
2
+ "$id": "https://github.com/klimPaskov/hoi4-agent-tools/blob/v4.0.5/schemas/helper-expansion-summary.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/v4.0.4/schemas/impact-inspect-input.schema.json",
2
+ "$id": "https://github.com/klimPaskov/hoi4-agent-tools/blob/v4.0.5/schemas/impact-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/v4.0.4/schemas/map-operation.schema.json",
2
+ "$id": "https://github.com/klimPaskov/hoi4-agent-tools/blob/v4.0.5/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/v4.0.4/schemas/mechanic-test-input.schema.json",
2
+ "$id": "https://github.com/klimPaskov/hoi4-agent-tools/blob/v4.0.5/schemas/mechanic-test-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/v4.0.4/schemas/mod-index-input.schema.json",
2
+ "$id": "https://github.com/klimPaskov/hoi4-agent-tools/blob/v4.0.5/schemas/mod-index-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/v4.0.4/schemas/operation-result.schema.json",
2
+ "$id": "https://github.com/klimPaskov/hoi4-agent-tools/blob/v4.0.5/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/v4.0.4/schemas/package-check-input.schema.json",
2
+ "$id": "https://github.com/klimPaskov/hoi4-agent-tools/blob/v4.0.5/schemas/package-check-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/v4.0.4/schemas/package-manifest.schema.json",
2
+ "$id": "https://github.com/klimPaskov/hoi4-agent-tools/blob/v4.0.5/schemas/package-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/v4.0.4/schemas/probability-analysis-result.schema.json",
2
+ "$id": "https://github.com/klimPaskov/hoi4-agent-tools/blob/v4.0.5/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/v4.0.4/schemas/probability-compare-input.schema.json",
2
+ "$id": "https://github.com/klimPaskov/hoi4-agent-tools/blob/v4.0.5/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/v4.0.4/schemas/probability-evaluate-input.schema.json",
2
+ "$id": "https://github.com/klimPaskov/hoi4-agent-tools/blob/v4.0.5/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/v4.0.4/schemas/probability-inspect-input.schema.json",
2
+ "$id": "https://github.com/klimPaskov/hoi4-agent-tools/blob/v4.0.5/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/v4.0.4/schemas/probability-render-input.schema.json",
2
+ "$id": "https://github.com/klimPaskov/hoi4-agent-tools/blob/v4.0.5/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/v4.0.4/schemas/probability-scenario-set.schema.json",
2
+ "$id": "https://github.com/klimPaskov/hoi4-agent-tools/blob/v4.0.5/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/v4.0.4/schemas/probability-sequence-input.schema.json",
2
+ "$id": "https://github.com/klimPaskov/hoi4-agent-tools/blob/v4.0.5/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/v4.0.4/schemas/probability-simulate-input.schema.json",
2
+ "$id": "https://github.com/klimPaskov/hoi4-agent-tools/blob/v4.0.5/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/v4.0.4/schemas/probability-sweep-input.schema.json",
2
+ "$id": "https://github.com/klimPaskov/hoi4-agent-tools/blob/v4.0.5/schemas/probability-sweep-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/v4.0.4/schemas/reference-context-input.schema.json",
2
+ "$id": "https://github.com/klimPaskov/hoi4-agent-tools/blob/v4.0.5/schemas/reference-context-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/v4.0.4/schemas/reference-read-input.schema.json",
2
+ "$id": "https://github.com/klimPaskov/hoi4-agent-tools/blob/v4.0.5/schemas/reference-read-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/v4.0.4/schemas/reference-search-input.schema.json",
2
+ "$id": "https://github.com/klimPaskov/hoi4-agent-tools/blob/v4.0.5/schemas/reference-search-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/v4.0.4/schemas/scenario-suite.schema.json",
2
+ "$id": "https://github.com/klimPaskov/hoi4-agent-tools/blob/v4.0.5/schemas/scenario-suite.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/v4.0.4/schemas/scenario-test-input.schema.json",
2
+ "$id": "https://github.com/klimPaskov/hoi4-agent-tools/blob/v4.0.5/schemas/scenario-test-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/v4.0.4/schemas/script-validate-input.schema.json",
2
+ "$id": "https://github.com/klimPaskov/hoi4-agent-tools/blob/v4.0.5/schemas/script-validate-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/v4.0.4/schemas/shared-scenario.schema.json",
2
+ "$id": "https://github.com/klimPaskov/hoi4-agent-tools/blob/v4.0.5/schemas/shared-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/v4.0.4/schemas/source-lookup-input.schema.json",
2
+ "$id": "https://github.com/klimPaskov/hoi4-agent-tools/blob/v4.0.5/schemas/source-lookup-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": "Build HOI4 mods: focus trees, events, decisions, worlds, GUI previews, docs and AI balance.",
6
- "version": "4.0.4",
6
+ "version": "4.0.5",
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": "4.0.4",
16
+ "version": "4.0.5",
17
17
  "transport": {
18
18
  "type": "stdio"
19
19
  }