hoi4-agent-tools 2.3.5 → 2.3.9

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 (34) hide show
  1. package/CHANGELOG.md +19 -0
  2. package/dist/hoi4_agent_tools/core/workspace.js +48 -3
  3. package/dist/hoi4_agent_tools/mcp/server/base-tools.js +6 -0
  4. package/dist/hoi4_agent_tools/mcp/server/create.js +28 -7
  5. package/dist/hoi4_agent_tools/mcp/tools/chaosx.js +3 -2
  6. package/dist/hoi4_agent_tools/mcp/tools/event.js +4 -3
  7. package/dist/hoi4_agent_tools/mcp/tools/focus.js +4 -4
  8. package/dist/hoi4_agent_tools/mcp/tools/gui.js +4 -4
  9. package/dist/hoi4_agent_tools/mcp/tools/map.js +4 -4
  10. package/dist/hoi4_agent_tools/mcp/tools/probability.js +10 -9
  11. package/dist/hoi4_agent_tools/mcp/tools/technology.js +4 -3
  12. package/dist/hoi4_agent_tools/version.js +1 -1
  13. package/package.json +5 -3
  14. package/schemas/configuration.schema.json +1 -1
  15. package/schemas/continuous-focus-palette.schema.json +1 -1
  16. package/schemas/custom-weighted-pool.schema.json +1 -1
  17. package/schemas/event-feature-manifest.schema.json +1 -1
  18. package/schemas/focus-plan.schema.json +1 -1
  19. package/schemas/focus-planning-sidecar.schema.json +1 -1
  20. package/schemas/gui-animation-source.schema.json +1 -1
  21. package/schemas/gui-helper.schema.json +1 -1
  22. package/schemas/gui-scenario.schema.json +1 -1
  23. package/schemas/map-operation.schema.json +1 -1
  24. package/schemas/operation-result.schema.json +1 -1
  25. package/schemas/probability-analysis-result.schema.json +1 -1
  26. package/schemas/probability-compare-input.schema.json +1 -1
  27. package/schemas/probability-evaluate-input.schema.json +1 -1
  28. package/schemas/probability-inspect-input.schema.json +1 -1
  29. package/schemas/probability-render-input.schema.json +1 -1
  30. package/schemas/probability-scenario-set.schema.json +1 -1
  31. package/schemas/probability-sequence-input.schema.json +1 -1
  32. package/schemas/probability-simulate-input.schema.json +1 -1
  33. package/schemas/probability-sweep-input.schema.json +1 -1
  34. package/server.json +2 -2
package/CHANGELOG.md CHANGED
@@ -1,5 +1,24 @@
1
1
  # Changelog
2
2
 
3
+ ## 2.3.9 - 2026-08-04
4
+
5
+ - Bound omitted-workspace tool calls to the connected MCP client's active filesystem root instead of the server process's original working directory.
6
+ - Added cross-workspace regression coverage proving an Ireland client root cannot be misdirected to a Slop Redux server working directory.
7
+
8
+ ## 2.3.8 - 2026-08-04
9
+
10
+ - Regenerated the clean-install lockfile with the release-pinned npm so optional native runtime metadata is complete in CI.
11
+
12
+ ## 2.3.7 - 2026-08-04
13
+
14
+ - Updated patched transitive URL, address, CORS, and glob dependencies after new npm advisories blocked the 2.3.6 publication gate.
15
+
16
+ ## 2.3.6 - 2026-08-04
17
+
18
+ - Resolved discovered mod workspaces by their normalized directory or display name so coding agents do not need internal hashed registration IDs.
19
+ - Accepted prior automatic and discovered workspace IDs when they uniquely identify the same mod after configuration or path changes.
20
+ - Verified focus, GUI, map, event, technology, and weighted-logic inspection against an external `ireland_total_overhaul` mod workspace.
21
+
3
22
  ## 2.3.5 - 2026-08-02
4
23
 
5
24
  - Replaced all-domain scans in focus, map, probability, rewrite validation, and country-asset discovery with domain-specific source inventories.
@@ -61,6 +61,30 @@ function discoveredWorkspaceId(rootPath) {
61
61
  const identityPath = process.platform === 'win32' ? rootPath.toLowerCase() : rootPath;
62
62
  return `mod_${slug.length === 0 ? 'workspace' : slug}_${sha256Bytes(identityPath).slice(0, 12)}`;
63
63
  }
64
+ function workspaceAliasSlug(value) {
65
+ return value
66
+ .normalize('NFKD')
67
+ .toLowerCase()
68
+ .replace(/[^a-z0-9]+/gu, '_')
69
+ .replace(/^_+|_+$/gu, '')
70
+ .slice(0, 48);
71
+ }
72
+ function workspaceAliases(workspace) {
73
+ const slug = workspaceAliasSlug(path.basename(workspace.modRoot));
74
+ const nameSlug = workspaceAliasSlug(workspace.name);
75
+ return new Set([
76
+ slug,
77
+ nameSlug,
78
+ `auto_${slug}`,
79
+ `auto_${nameSlug}`,
80
+ `mod_${slug}`,
81
+ `mod_${nameSlug}`,
82
+ ]);
83
+ }
84
+ function requestedWorkspaceAlias(value) {
85
+ const staleDiscovered = /^mod_(.+)_[a-f0-9]{12}$/u.exec(value);
86
+ return staleDiscovered?.[1] ?? value;
87
+ }
64
88
  /**
65
89
  * Hash the resolved root topology without persisting canonical host paths. Canonicalization happens
66
90
  * before this function is called, so filesystem aliases converge on the same stable identity.
@@ -225,10 +249,31 @@ export class WorkspaceResolver {
225
249
  return workspaces[0].id;
226
250
  throw new ServiceError('WORKSPACE_CONTEXT_REQUIRED', 'The MCP working directory does not identify one writable mod workspace', { currentDirectory, workspaceIds: workspaces.map(({ id }) => id) });
227
251
  }
252
+ /** Resolve the active mod from filesystem roots advertised by the connected MCP client. */
253
+ async resolveClientWorkspaceId(rootPaths, principal) {
254
+ const canonicalRoots = await Promise.all(rootPaths.map((rootPath) => canonicalPath(rootPath)));
255
+ const matches = this.list(principal).filter((workspace) => workspace.registration.kind === 'mod' &&
256
+ canonicalRoots.some((rootPath) => isWithin(workspace.modRoot, rootPath) || isWithin(rootPath, workspace.modRoot)));
257
+ if (matches.length === 1)
258
+ return matches[0].id;
259
+ if (matches.length === 0) {
260
+ throw new ServiceError('WORKSPACE_CONTEXT_NOT_FOUND', 'The active MCP client roots do not identify a registered HOI4 mod workspace');
261
+ }
262
+ throw new ServiceError('WORKSPACE_CONTEXT_AMBIGUOUS', 'The active MCP client roots identify more than one HOI4 mod workspace', { workspaceIds: matches.map(({ id }) => id) });
263
+ }
228
264
  resolveWorkspaceId(workspaceId, principal) {
229
- return workspaceId === CURRENT_WORKSPACE_ID
230
- ? this.resolveCurrentWorkspaceId(principal)
231
- : workspaceId;
265
+ if (workspaceId === CURRENT_WORKSPACE_ID)
266
+ return this.resolveCurrentWorkspaceId(principal);
267
+ if (this.#byId.has(workspaceId))
268
+ return workspaceId;
269
+ const alias = requestedWorkspaceAlias(workspaceId);
270
+ const matches = this.list(principal).filter((workspace) => workspace.registration.kind === 'mod' && workspaceAliases(workspace).has(alias));
271
+ if (matches.length === 1)
272
+ return matches[0].id;
273
+ if (matches.length > 1) {
274
+ throw new ServiceError('WORKSPACE_CONTEXT_AMBIGUOUS', `More than one mod workspace matches: ${workspaceId}`, { workspaceId, workspaceIds: matches.map(({ id }) => id) });
275
+ }
276
+ return workspaceId;
232
277
  }
233
278
  serverState() {
234
279
  return this.#serverState;
@@ -8,6 +8,12 @@ import { importContinuousFocusPalettes, importFocusTrees, layoutFocusTreeAsync,
8
8
  import { ScriptedGuiStudio } from '../../gui/index.js';
9
9
  import { AgentNudger, attributeMapValidationDiagnostics } from '../../map/index.js';
10
10
  import { PACKAGE_VERSION } from '../../version.js';
11
+ export async function resolveServerWorkspaceId(engine, context, workspaceId, signal) {
12
+ if (workspaceId === 'current' && context.resolveCurrentWorkspaceId !== undefined) {
13
+ return context.resolveCurrentWorkspaceId(signal);
14
+ }
15
+ return engine.resolver.resolveWorkspaceId(workspaceId, context.principal);
16
+ }
11
17
  export function requireServerScope(context, scope) {
12
18
  if (context.scopes !== undefined && !context.scopes.includes(scope)) {
13
19
  throw new ServiceError('AUTH_SCOPE_REQUIRED', `This operation requires the ${scope} scope`, {
@@ -1,4 +1,5 @@
1
1
  import { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';
2
+ import { fileURLToPath } from 'node:url';
2
3
  import { PACKAGE_NAME, PACKAGE_VERSION } from '../../version.js';
3
4
  import { registerFocusTools } from '../tools/focus.js';
4
5
  import { registerGuiTools } from '../tools/gui.js';
@@ -17,12 +18,32 @@ export function createMcpServer(engine, context = {}) {
17
18
  capabilities: { logging: {} },
18
19
  instructions: SERVER_INSTRUCTIONS,
19
20
  });
20
- registerFocusTools(server, engine, context);
21
- registerGuiTools(server, engine, context);
22
- registerMapTools(server, engine, context);
23
- registerEventTools(server, engine, context);
24
- registerTechnologyTools(server, engine, context);
25
- registerProbabilityTools(server, engine, context);
26
- registerMcpResources(server, engine, context);
21
+ const serverContext = {
22
+ ...context,
23
+ resolveCurrentWorkspaceId: async (signal) => {
24
+ const capabilities = server.server.getClientCapabilities();
25
+ if (capabilities?.roots === undefined) {
26
+ return engine.resolver.resolveCurrentWorkspaceId(context.principal);
27
+ }
28
+ const listed = await server.server.listRoots(undefined, signal === undefined ? undefined : { signal });
29
+ const rootPaths = listed.roots.flatMap(({ uri }) => {
30
+ try {
31
+ const parsed = new URL(uri);
32
+ return parsed.protocol === 'file:' ? [fileURLToPath(parsed)] : [];
33
+ }
34
+ catch {
35
+ return [];
36
+ }
37
+ });
38
+ return engine.resolver.resolveClientWorkspaceId(rootPaths, context.principal);
39
+ },
40
+ };
41
+ registerFocusTools(server, engine, serverContext);
42
+ registerGuiTools(server, engine, serverContext);
43
+ registerMapTools(server, engine, serverContext);
44
+ registerEventTools(server, engine, serverContext);
45
+ registerTechnologyTools(server, engine, serverContext);
46
+ registerProbabilityTools(server, engine, serverContext);
47
+ registerMcpResources(server, engine, serverContext);
27
48
  return server;
28
49
  }
@@ -11,6 +11,7 @@ import { GuiAssetCatalog } from '../../gui/assets.js';
11
11
  import { ScriptedGuiStudio } from '../../gui/index.js';
12
12
  import { buildGuiSourceGraph } from '../../gui/source-graph.js';
13
13
  import { PACKAGE_VERSION } from '../../version.js';
14
+ import { resolveServerWorkspaceId } from '../server/base-tools.js';
14
15
  import { compactValidatedInputSchema } from '../server/context-schemas.js';
15
16
  import { nonNegativeIntegerSchema, sha256Schema } from '../server/output-schemas.js';
16
17
  import { progressReporter } from '../server/progress.js';
@@ -341,7 +342,7 @@ export function registerChaosxTools(server, engine, context) {
341
342
  outputSchema: chaosxVisualRevisionOutput,
342
343
  annotations: readOnly,
343
344
  }, async (input, extra) => {
344
- const workspaceId = engine.resolver.resolveWorkspaceId(input.workspaceId, context.principal);
345
+ const workspaceId = await resolveServerWorkspaceId(engine, context, input.workspaceId, extra.signal);
345
346
  try {
346
347
  const progress = progressReporter(extra);
347
348
  await progress.report(0, 2, 'Checking ChaosX scripted-GUI sources');
@@ -379,7 +380,7 @@ export function registerChaosxTools(server, engine, context) {
379
380
  outputSchema: chaosxCountryAssetsOutput,
380
381
  annotations: artifactProducing,
381
382
  }, async (input, extra) => {
382
- const workspaceId = engine.resolver.resolveWorkspaceId(input.workspaceId, context.principal);
383
+ const workspaceId = await resolveServerWorkspaceId(engine, context, input.workspaceId, extra.signal);
383
384
  try {
384
385
  const progress = progressReporter(extra);
385
386
  await progress.report(0, 3, 'Resolving ChaosX country assets');
@@ -9,6 +9,7 @@ import { compactValidatedInputSchema } from '../server/context-schemas.js';
9
9
  import { nonNegativeIntegerSchema, sha256Schema } from '../server/output-schemas.js';
10
10
  import { progressReporter } from '../server/progress.js';
11
11
  import { errorResult, setInlineFilesScanned, strictOperationResultSchema, toolResult, } from '../server/result.js';
12
+ import { resolveServerWorkspaceId } from '../server/base-tools.js';
12
13
  const nestedSelectorSchema = compactValidatedInputSchema(eventSelectorSchema, 'Event selector; see docs/events.md.');
13
14
  const nestedStateSubjectSchema = compactValidatedInputSchema(eventStateSubjectSchema, 'State kind and name.');
14
15
  const nestedImpactSubjectSchema = compactValidatedInputSchema(eventImpactSubjectSchema, 'Impact kind and name.');
@@ -311,7 +312,7 @@ export function registerEventTools(server, engine, context) {
311
312
  outputSchema: eventInspectOutputSchema,
312
313
  annotations: readOnlyEventTool,
313
314
  }, async (input, extra) => {
314
- const workspaceId = engine.resolver.resolveWorkspaceId(input.workspaceId, context.principal);
315
+ const workspaceId = await resolveServerWorkspaceId(engine, context, input.workspaceId, extra.signal);
315
316
  try {
316
317
  const progress = progressReporter(extra);
317
318
  await progress.report(0, 3, 'Analyzing event chain');
@@ -350,7 +351,7 @@ export function registerEventTools(server, engine, context) {
350
351
  outputSchema: eventRenderOutputSchema,
351
352
  annotations: readOnlyEventTool,
352
353
  }, async (input, extra) => {
353
- const workspaceId = engine.resolver.resolveWorkspaceId(input.workspaceId, context.principal);
354
+ const workspaceId = await resolveServerWorkspaceId(engine, context, input.workspaceId, extra.signal);
354
355
  try {
355
356
  const progress = progressReporter(extra);
356
357
  await progress.report(0, 3, 'Rendering event-chain view');
@@ -396,7 +397,7 @@ export function registerEventTools(server, engine, context) {
396
397
  outputSchema: eventCompareOutputSchema,
397
398
  annotations: readOnlyEventTool,
398
399
  }, async (input, extra) => {
399
- const workspaceId = engine.resolver.resolveWorkspaceId(input.workspaceId, context.principal);
400
+ const workspaceId = await resolveServerWorkspaceId(engine, context, input.workspaceId, extra.signal);
400
401
  try {
401
402
  const progress = progressReporter(extra);
402
403
  await progress.report(0, 3, 'Comparing event-chain graphs');
@@ -13,7 +13,7 @@ import { PACKAGE_VERSION } from '../../version.js';
13
13
  import { nonNegativeIntegerSchema, renderHashesSchema, sha256Schema, } from '../server/output-schemas.js';
14
14
  import { progressReporter } from '../server/progress.js';
15
15
  import { errorResult, setInlineFilesScanned, strictOperationResultSchema, toolResult, } from '../server/result.js';
16
- import { requireServerScope } from '../server/base-tools.js';
16
+ import { requireServerScope, resolveServerWorkspaceId, } from '../server/base-tools.js';
17
17
  import { compactValidatedInputSchema } from '../server/context-schemas.js';
18
18
  import { autonomousFailureContext, autonomousResultArtifacts, executePlannedTransaction, } from '../server/transaction-execution.js';
19
19
  const focusInspectOutputSchema = strictOperationResultSchema(z
@@ -347,7 +347,7 @@ export async function computeFocusVisualRevisions(engine, context, workspaceId,
347
347
  }
348
348
  async function executeFocusVisualTool(engine, workbench, context, input, extra, rasterize) {
349
349
  const { workspaceId: requestedWorkspaceId, relativePath } = input;
350
- const workspaceId = engine.resolver.resolveWorkspaceId(requestedWorkspaceId, context.principal);
350
+ const workspaceId = await resolveServerWorkspaceId(engine, context, requestedWorkspaceId, extra.signal);
351
351
  const outputName = rasterize ? 'raster' : 'render';
352
352
  try {
353
353
  const progress = progressReporter(extra);
@@ -607,7 +607,7 @@ export function registerFocusTools(server, engine, context) {
607
607
  annotations: artifactProducing,
608
608
  }, async (input, extra) => {
609
609
  const { workspaceId: requestedWorkspaceId, relativePath } = input;
610
- const workspaceId = engine.resolver.resolveWorkspaceId(requestedWorkspaceId, context.principal);
610
+ const workspaceId = await resolveServerWorkspaceId(engine, context, requestedWorkspaceId, extra.signal);
611
611
  try {
612
612
  const progress = progressReporter(extra);
613
613
  await progress.report(0, 3, 'Building shared workspace index');
@@ -845,7 +845,7 @@ export function registerFocusTools(server, engine, context) {
845
845
  },
846
846
  }, async (input, extra) => {
847
847
  const { workspaceId: requestedWorkspaceId, relativePath, createIfMissing, horizontalSpacing, verticalSpacing, padding, reviewScale, } = input;
848
- const workspaceId = engine.resolver.resolveWorkspaceId(requestedWorkspaceId, context.principal);
848
+ const workspaceId = await resolveServerWorkspaceId(engine, context, requestedWorkspaceId, extra.signal);
849
849
  try {
850
850
  requireServerScope(context, 'hoi4:write');
851
851
  const progress = progressReporter(extra);
@@ -8,7 +8,7 @@ import { GuiHelperDocumentSchema, GuiPreviewScenarioSchema, GUI_TEXT_PACKAGE_MAX
8
8
  import { encodeGuiInspectionArtifact, projectGuiGraphForArtifact, } from '../../gui/inspection-artifact.js';
9
9
  import { workspaceIdSchema, workspaceRelativePathSchema } from '../../schemas/common.js';
10
10
  import { PACKAGE_VERSION } from '../../version.js';
11
- import { requireServerScope } from '../server/base-tools.js';
11
+ import { requireServerScope, resolveServerWorkspaceId, } from '../server/base-tools.js';
12
12
  import { compactValidatedInputSchema } from '../server/context-schemas.js';
13
13
  import { autonomousFailureContext, autonomousResultArtifacts, executePlannedTransaction, } from '../server/transaction-execution.js';
14
14
  import { indexSkippedSourceSchema, nonNegativeIntegerSchema, sha256Schema, } from '../server/output-schemas.js';
@@ -151,7 +151,7 @@ export function registerGuiTools(server, engine, context) {
151
151
  outputSchema: guiScanOutputSchema,
152
152
  annotations: artifactProducing,
153
153
  }, async ({ workspaceId: requestedWorkspaceId, windowName, scenario, relatedScenarios }, extra) => {
154
- const workspaceId = engine.resolver.resolveWorkspaceId(requestedWorkspaceId, context.principal);
154
+ const workspaceId = await resolveServerWorkspaceId(engine, context, requestedWorkspaceId, extra.signal);
155
155
  try {
156
156
  const progress = progressReporter(extra);
157
157
  await progress.report(0, 3, 'Building GUI source graph');
@@ -262,7 +262,7 @@ export function registerGuiTools(server, engine, context) {
262
262
  }
263
263
  });
264
264
  const render = async (input, extra, code) => {
265
- const workspaceId = engine.resolver.resolveWorkspaceId(input.workspaceId, context.principal);
265
+ const workspaceId = await resolveServerWorkspaceId(engine, context, input.workspaceId, extra.signal);
266
266
  const { windowName } = input;
267
267
  try {
268
268
  const progress = progressReporter(extra);
@@ -453,7 +453,7 @@ export function registerGuiTools(server, engine, context) {
453
453
  openWorldHint: false,
454
454
  },
455
455
  }, async (input, extra) => {
456
- const workspaceId = engine.resolver.resolveWorkspaceId(input.workspaceId, context.principal);
456
+ const workspaceId = await resolveServerWorkspaceId(engine, context, input.workspaceId, extra.signal);
457
457
  const { relativePath, windowName, scenario } = input;
458
458
  try {
459
459
  requireServerScope(context, 'hoi4:write');
@@ -6,7 +6,7 @@ import { AgentNudger, allocateMapIdentifiersAsync, exportProvinceGeometryRowRuns
6
6
  import { workspaceIdSchema } from '../../schemas/common.js';
7
7
  import { mapAllocationRequestSchema, mapOperationSchema } from '../../schemas/map.js';
8
8
  import { PACKAGE_VERSION } from '../../version.js';
9
- import { requireServerScope } from '../server/base-tools.js';
9
+ import { requireServerScope, resolveServerWorkspaceId, } from '../server/base-tools.js';
10
10
  import { compactValidatedInputSchema } from '../server/context-schemas.js';
11
11
  import { autonomousFailureContext, autonomousResultArtifacts, executePlannedTransaction, } from '../server/transaction-execution.js';
12
12
  import { allocationEvidenceSchema, bitmapRenderHashesSchema, nonNegativeIntegerSchema, operationBlockerDataSchema, sha256Schema, } from '../server/output-schemas.js';
@@ -365,7 +365,7 @@ export function registerMapTools(server, engine, context) {
365
365
  outputSchema: mapWorkspaceInspectOutputSchema,
366
366
  annotations: artifactProducing,
367
367
  }, async ({ workspaceId: requestedWorkspaceId, provinceIds, stateIds, regionIds, allocationRequests }, extra) => {
368
- const workspaceId = engine.resolver.resolveWorkspaceId(requestedWorkspaceId, context.principal);
368
+ const workspaceId = await resolveServerWorkspaceId(engine, context, requestedWorkspaceId, extra.signal);
369
369
  try {
370
370
  const progress = progressReporter(extra);
371
371
  await progress.report(0, 3, 'Inspecting and validating the map');
@@ -512,7 +512,7 @@ export function registerMapTools(server, engine, context) {
512
512
  outputSchema: mapRenderOutputSchema,
513
513
  annotations: artifactProducing,
514
514
  }, async ({ workspaceId: requestedWorkspaceId, layer, overlays, scale }, extra) => {
515
- const workspaceId = engine.resolver.resolveWorkspaceId(requestedWorkspaceId, context.principal);
515
+ const workspaceId = await resolveServerWorkspaceId(engine, context, requestedWorkspaceId, extra.signal);
516
516
  try {
517
517
  const progress = progressReporter(extra);
518
518
  await progress.report(0, 3, 'Rendering offline map layer');
@@ -558,7 +558,7 @@ export function registerMapTools(server, engine, context) {
558
558
  openWorldHint: false,
559
559
  },
560
560
  }, async ({ workspaceId: requestedWorkspaceId, operations, diffScale }, extra) => {
561
- const workspaceId = engine.resolver.resolveWorkspaceId(requestedWorkspaceId, context.principal);
561
+ const workspaceId = await resolveServerWorkspaceId(engine, context, requestedWorkspaceId, extra.signal);
562
562
  try {
563
563
  requireServerScope(context, 'hoi4:write');
564
564
  const progress = progressReporter(extra);
@@ -3,6 +3,7 @@ import { emptyServiceResult } from '../../core/result.js';
3
3
  import { ProbabilityAnalyzer, } from '../../probability/service.js';
4
4
  import { customWeightedPoolManifestSchema, probabilityAcceptanceBandSchema, probabilityAdapterIdSchema, probabilityDiagnosticThresholdsSchema, probabilityMetricSchema, probabilityOutputSchema, probabilityRenderFilterSchema, probabilityScenarioSetSchema, probabilitySamplingMethodSchema, probabilitySourceSchema, } from '../../schemas/probability.js';
5
5
  import { workspaceIdSchema } from '../../schemas/common.js';
6
+ import { resolveServerWorkspaceId } from '../server/base-tools.js';
6
7
  import { compactValidatedInputSchema } from '../server/context-schemas.js';
7
8
  import { nonNegativeIntegerSchema, sha256Schema } from '../server/output-schemas.js';
8
9
  import { progressReporter } from '../server/progress.js';
@@ -150,9 +151,9 @@ const readOnly = {
150
151
  idempotentHint: true,
151
152
  openWorldHint: false,
152
153
  };
153
- function requestContext(engine, context, workspaceId, refresh, signal) {
154
+ async function requestContext(engine, context, workspaceId, refresh, signal) {
154
155
  return {
155
- workspaceId: engine.resolver.resolveWorkspaceId(workspaceId, context.principal),
156
+ workspaceId: await resolveServerWorkspaceId(engine, context, workspaceId, signal),
156
157
  ...(context.principal === undefined ? {} : { principal: context.principal }),
157
158
  ...(refresh === undefined ? {} : { refresh }),
158
159
  signal,
@@ -216,7 +217,7 @@ export function registerProbabilityTools(server, engine, context) {
216
217
  annotations: readOnly,
217
218
  }, async (input, extra) => {
218
219
  const progress = progressReporter(extra);
219
- const base = requestContext(engine, context, input.workspaceId, input.refresh, progress.signal);
220
+ const base = await requestContext(engine, context, input.workspaceId, input.refresh, progress.signal);
220
221
  try {
221
222
  await progress.report(0, 2, 'Inspecting weighted source');
222
223
  const inspected = await analyzer.inspect(base, input.adapter, input.source, input.candidatePool);
@@ -255,7 +256,7 @@ export function registerProbabilityTools(server, engine, context) {
255
256
  annotations: readOnly,
256
257
  }, async (input, extra) => {
257
258
  const progress = progressReporter(extra);
258
- const base = requestContext(engine, context, input.workspaceId, input.refresh, progress.signal);
259
+ const base = await requestContext(engine, context, input.workspaceId, input.refresh, progress.signal);
259
260
  try {
260
261
  await progress.report(0, 3, 'Scanning and evaluating weighted source');
261
262
  const request = {
@@ -279,7 +280,7 @@ export function registerProbabilityTools(server, engine, context) {
279
280
  annotations: readOnly,
280
281
  }, async (input, extra) => {
281
282
  const progress = progressReporter(extra);
282
- const base = requestContext(engine, context, input.workspaceId, input.refresh, progress.signal);
283
+ const base = await requestContext(engine, context, input.workspaceId, input.refresh, progress.signal);
283
284
  try {
284
285
  await progress.report(0, 3, 'Evaluating parameter sweep');
285
286
  const request = {
@@ -303,7 +304,7 @@ export function registerProbabilityTools(server, engine, context) {
303
304
  annotations: readOnly,
304
305
  }, async (input, extra) => {
305
306
  const progress = progressReporter(extra);
306
- const base = requestContext(engine, context, input.workspaceId, input.refresh, progress.signal);
307
+ const base = await requestContext(engine, context, input.workspaceId, input.refresh, progress.signal);
307
308
  try {
308
309
  await progress.report(0, input.samples, 'Sampling uncertain scenarios');
309
310
  const request = {
@@ -327,7 +328,7 @@ export function registerProbabilityTools(server, engine, context) {
327
328
  annotations: readOnly,
328
329
  }, async (input, extra) => {
329
330
  const progress = progressReporter(extra);
330
- const base = requestContext(engine, context, input.workspaceId, undefined, progress.signal);
331
+ const base = await requestContext(engine, context, input.workspaceId, undefined, progress.signal);
331
332
  try {
332
333
  await progress.report(0, input.maxSteps, 'Analyzing declared sequence');
333
334
  const request = {
@@ -351,7 +352,7 @@ export function registerProbabilityTools(server, engine, context) {
351
352
  annotations: readOnly,
352
353
  }, async (input, extra) => {
353
354
  const progress = progressReporter(extra);
354
- const base = requestContext(engine, context, input.workspaceId, input.refresh, progress.signal);
355
+ const base = await requestContext(engine, context, input.workspaceId, input.refresh, progress.signal);
355
356
  try {
356
357
  await progress.report(0, 4, 'Comparing weighted source');
357
358
  const request = {
@@ -375,7 +376,7 @@ export function registerProbabilityTools(server, engine, context) {
375
376
  annotations: readOnly,
376
377
  }, async (input, extra) => {
377
378
  const progress = progressReporter(extra);
378
- const base = requestContext(engine, context, input.workspaceId, undefined, progress.signal);
379
+ const base = await requestContext(engine, context, input.workspaceId, undefined, progress.signal);
379
380
  try {
380
381
  await progress.report(0, input.outputs.length, 'Rendering analysis resources');
381
382
  const request = {
@@ -9,6 +9,7 @@ import { compactValidatedInputSchema } from '../server/context-schemas.js';
9
9
  import { nonNegativeIntegerSchema, sha256Schema } from '../server/output-schemas.js';
10
10
  import { progressReporter } from '../server/progress.js';
11
11
  import { errorResult, setInlineFilesScanned, strictOperationResultSchema, toolResult, } from '../server/result.js';
12
+ import { resolveServerWorkspaceId } from '../server/base-tools.js';
12
13
  const technologyMode = z.enum([
13
14
  'scan',
14
15
  'folders',
@@ -244,7 +245,7 @@ export function registerTechnologyTools(server, engine, context) {
244
245
  outputSchema: analysisOutput,
245
246
  annotations: readOnly,
246
247
  }, async (input, extra) => {
247
- const workspaceId = engine.resolver.resolveWorkspaceId(input.workspaceId, context.principal);
248
+ const workspaceId = await resolveServerWorkspaceId(engine, context, input.workspaceId, extra.signal);
248
249
  try {
249
250
  const progress = progressReporter(extra);
250
251
  await progress.report(0, 2, 'Analyzing technologies');
@@ -273,7 +274,7 @@ export function registerTechnologyTools(server, engine, context) {
273
274
  outputSchema: renderOutput,
274
275
  annotations: readOnly,
275
276
  }, async (input, extra) => {
276
- const workspaceId = engine.resolver.resolveWorkspaceId(input.workspaceId, context.principal);
277
+ const workspaceId = await resolveServerWorkspaceId(engine, context, input.workspaceId, extra.signal);
277
278
  try {
278
279
  const progress = progressReporter(extra);
279
280
  const request = {
@@ -317,7 +318,7 @@ export function registerTechnologyTools(server, engine, context) {
317
318
  outputSchema: compareOutput,
318
319
  annotations: readOnly,
319
320
  }, async (input, extra) => {
320
- const workspaceId = engine.resolver.resolveWorkspaceId(input.workspaceId, context.principal);
321
+ const workspaceId = await resolveServerWorkspaceId(engine, context, input.workspaceId, extra.signal);
321
322
  try {
322
323
  const progress = progressReporter(extra);
323
324
  const request = {
@@ -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.3.5';
3
+ export const PACKAGE_VERSION = '2.3.9';
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/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.3.5",
4
+ "version": "2.3.9",
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",
@@ -126,8 +126,10 @@
126
126
  },
127
127
  "overrides": {
128
128
  "@hono/node-server": "2.0.11",
129
- "brace-expansion": "5.0.8",
130
- "fast-uri": "3.1.4",
129
+ "brace-expansion": "5.0.9",
130
+ "fast-uri": "3.1.5",
131
+ "hono": "4.13.0",
132
+ "ip-address": "10.4.0",
131
133
  "postcss": "8.5.23",
132
134
  "shell-quote": "1.10.0"
133
135
  },
@@ -1,5 +1,5 @@
1
1
  {
2
- "$id": "https://github.com/klimPaskov/hoi4-agent-tools/blob/v2.3.5/schemas/configuration.schema.json",
2
+ "$id": "https://github.com/klimPaskov/hoi4-agent-tools/blob/v2.3.9/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.3.5/schemas/continuous-focus-palette.schema.json",
2
+ "$id": "https://github.com/klimPaskov/hoi4-agent-tools/blob/v2.3.9/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.3.5/schemas/custom-weighted-pool.schema.json",
2
+ "$id": "https://github.com/klimPaskov/hoi4-agent-tools/blob/v2.3.9/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.3.5/schemas/event-feature-manifest.schema.json",
2
+ "$id": "https://github.com/klimPaskov/hoi4-agent-tools/blob/v2.3.9/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.3.5/schemas/focus-plan.schema.json",
2
+ "$id": "https://github.com/klimPaskov/hoi4-agent-tools/blob/v2.3.9/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.3.5/schemas/focus-planning-sidecar.schema.json",
2
+ "$id": "https://github.com/klimPaskov/hoi4-agent-tools/blob/v2.3.9/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.3.5/schemas/gui-animation-source.schema.json",
2
+ "$id": "https://github.com/klimPaskov/hoi4-agent-tools/blob/v2.3.9/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.3.5/schemas/gui-helper.schema.json",
2
+ "$id": "https://github.com/klimPaskov/hoi4-agent-tools/blob/v2.3.9/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.3.5/schemas/gui-scenario.schema.json",
2
+ "$id": "https://github.com/klimPaskov/hoi4-agent-tools/blob/v2.3.9/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.3.5/schemas/map-operation.schema.json",
2
+ "$id": "https://github.com/klimPaskov/hoi4-agent-tools/blob/v2.3.9/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.3.5/schemas/operation-result.schema.json",
2
+ "$id": "https://github.com/klimPaskov/hoi4-agent-tools/blob/v2.3.9/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.3.5/schemas/probability-analysis-result.schema.json",
2
+ "$id": "https://github.com/klimPaskov/hoi4-agent-tools/blob/v2.3.9/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.3.5/schemas/probability-compare-input.schema.json",
2
+ "$id": "https://github.com/klimPaskov/hoi4-agent-tools/blob/v2.3.9/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.3.5/schemas/probability-evaluate-input.schema.json",
2
+ "$id": "https://github.com/klimPaskov/hoi4-agent-tools/blob/v2.3.9/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.3.5/schemas/probability-inspect-input.schema.json",
2
+ "$id": "https://github.com/klimPaskov/hoi4-agent-tools/blob/v2.3.9/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.3.5/schemas/probability-render-input.schema.json",
2
+ "$id": "https://github.com/klimPaskov/hoi4-agent-tools/blob/v2.3.9/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.3.5/schemas/probability-scenario-set.schema.json",
2
+ "$id": "https://github.com/klimPaskov/hoi4-agent-tools/blob/v2.3.9/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.3.5/schemas/probability-sequence-input.schema.json",
2
+ "$id": "https://github.com/klimPaskov/hoi4-agent-tools/blob/v2.3.9/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.3.5/schemas/probability-simulate-input.schema.json",
2
+ "$id": "https://github.com/klimPaskov/hoi4-agent-tools/blob/v2.3.9/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.3.5/schemas/probability-sweep-input.schema.json",
2
+ "$id": "https://github.com/klimPaskov/hoi4-agent-tools/blob/v2.3.9/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.3.5",
6
+ "version": "2.3.9",
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.3.5",
16
+ "version": "2.3.9",
17
17
  "transport": {
18
18
  "type": "stdio"
19
19
  }