hoi4-agent-tools 2.3.9 → 2.3.10

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,10 @@
1
1
  # Changelog
2
2
 
3
+ ## 2.3.10 - 2026-08-04
4
+
5
+ - Routed focus operations to the unique discovered mod containing a requested source when a stale client root points at another mod.
6
+ - Added regression coverage for a stale client context requesting Ireland's focus source without a workspace selector.
7
+
3
8
  ## 2.3.9 - 2026-08-04
4
9
 
5
10
  - Bound omitted-workspace tool calls to the connected MCP client's active filesystem root instead of the server process's original working directory.
@@ -261,6 +261,30 @@ export class WorkspaceResolver {
261
261
  }
262
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
263
  }
264
+ /** Find one mod containing an existing source path when a stale client root selected another mod. */
265
+ async resolveUniqueModSourceWorkspaceId(relativePath, principal, signal) {
266
+ const matches = [];
267
+ for (const workspace of this.list(principal)) {
268
+ signal?.throwIfAborted();
269
+ if (workspace.registration.kind !== 'mod')
270
+ continue;
271
+ try {
272
+ const resolved = await this.resolvePath(workspace.id, relativePath, 'read', ['mod'], principal);
273
+ signal?.throwIfAborted();
274
+ if ((await lstat(resolved.path)).isFile())
275
+ matches.push(workspace.id);
276
+ }
277
+ catch (error) {
278
+ if (error.name === 'AbortError')
279
+ throw error;
280
+ }
281
+ }
282
+ if (matches.length === 0)
283
+ return undefined;
284
+ if (matches.length === 1)
285
+ return matches[0];
286
+ throw new ServiceError('WORKSPACE_SOURCE_AMBIGUOUS', `The requested source exists in more than one mod workspace: ${relativePath}`, { relativePath, workspaceIds: matches });
287
+ }
264
288
  resolveWorkspaceId(workspaceId, principal) {
265
289
  if (workspaceId === CURRENT_WORKSPACE_ID)
266
290
  return this.resolveCurrentWorkspaceId(principal);
@@ -1,4 +1,5 @@
1
1
  import { boundedSourceHashEvidence, publicArtifactLink } from '../../core/artifacts.js';
2
+ import { lstat } from 'node:fs/promises';
2
3
  import { canonicalJson } from '../../core/canonical.js';
3
4
  import { exactChangedFilePatterns, focusDomainScanPatterns, } from '../../core/domain-scan-patterns.js';
4
5
  import { ServiceError } from '../../core/result.js';
@@ -14,6 +15,22 @@ export async function resolveServerWorkspaceId(engine, context, workspaceId, sig
14
15
  }
15
16
  return engine.resolver.resolveWorkspaceId(workspaceId, context.principal);
16
17
  }
18
+ export async function resolveServerWorkspaceForSource(engine, context, workspaceId, relativePath, signal) {
19
+ const resolvedWorkspaceId = await resolveServerWorkspaceId(engine, context, workspaceId, signal);
20
+ if (workspaceId !== 'current' || relativePath === undefined)
21
+ return resolvedWorkspaceId;
22
+ try {
23
+ const resolved = await engine.resolver.resolvePath(resolvedWorkspaceId, relativePath, 'read', ['mod'], context.principal);
24
+ signal?.throwIfAborted();
25
+ if ((await lstat(resolved.path)).isFile())
26
+ return resolvedWorkspaceId;
27
+ }
28
+ catch (error) {
29
+ if (error.name === 'AbortError')
30
+ throw error;
31
+ }
32
+ return ((await engine.resolver.resolveUniqueModSourceWorkspaceId(relativePath, context.principal, signal)) ?? resolvedWorkspaceId);
33
+ }
17
34
  export function requireServerScope(context, scope) {
18
35
  if (context.scopes !== undefined && !context.scopes.includes(scope)) {
19
36
  throw new ServiceError('AUTH_SCOPE_REQUIRED', `This operation requires the ${scope} scope`, {
@@ -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, resolveServerWorkspaceId, } from '../server/base-tools.js';
16
+ import { requireServerScope, resolveServerWorkspaceForSource, } 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 = await resolveServerWorkspaceId(engine, context, requestedWorkspaceId, extra.signal);
350
+ const workspaceId = await resolveServerWorkspaceForSource(engine, context, requestedWorkspaceId, relativePath, 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 = await resolveServerWorkspaceId(engine, context, requestedWorkspaceId, extra.signal);
610
+ const workspaceId = await resolveServerWorkspaceForSource(engine, context, requestedWorkspaceId, relativePath, 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 = await resolveServerWorkspaceId(engine, context, requestedWorkspaceId, extra.signal);
848
+ const workspaceId = await resolveServerWorkspaceForSource(engine, context, requestedWorkspaceId, relativePath, extra.signal);
849
849
  try {
850
850
  requireServerScope(context, 'hoi4:write');
851
851
  const progress = progressReporter(extra);
@@ -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.9';
3
+ export const PACKAGE_VERSION = '2.3.10';
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.9",
4
+ "version": "2.3.10",
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.3.9/schemas/configuration.schema.json",
2
+ "$id": "https://github.com/klimPaskov/hoi4-agent-tools/blob/v2.3.10/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.9/schemas/continuous-focus-palette.schema.json",
2
+ "$id": "https://github.com/klimPaskov/hoi4-agent-tools/blob/v2.3.10/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.9/schemas/custom-weighted-pool.schema.json",
2
+ "$id": "https://github.com/klimPaskov/hoi4-agent-tools/blob/v2.3.10/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.9/schemas/event-feature-manifest.schema.json",
2
+ "$id": "https://github.com/klimPaskov/hoi4-agent-tools/blob/v2.3.10/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.9/schemas/focus-plan.schema.json",
2
+ "$id": "https://github.com/klimPaskov/hoi4-agent-tools/blob/v2.3.10/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.9/schemas/focus-planning-sidecar.schema.json",
2
+ "$id": "https://github.com/klimPaskov/hoi4-agent-tools/blob/v2.3.10/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.9/schemas/gui-animation-source.schema.json",
2
+ "$id": "https://github.com/klimPaskov/hoi4-agent-tools/blob/v2.3.10/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.9/schemas/gui-helper.schema.json",
2
+ "$id": "https://github.com/klimPaskov/hoi4-agent-tools/blob/v2.3.10/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.9/schemas/gui-scenario.schema.json",
2
+ "$id": "https://github.com/klimPaskov/hoi4-agent-tools/blob/v2.3.10/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.9/schemas/map-operation.schema.json",
2
+ "$id": "https://github.com/klimPaskov/hoi4-agent-tools/blob/v2.3.10/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.9/schemas/operation-result.schema.json",
2
+ "$id": "https://github.com/klimPaskov/hoi4-agent-tools/blob/v2.3.10/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.9/schemas/probability-analysis-result.schema.json",
2
+ "$id": "https://github.com/klimPaskov/hoi4-agent-tools/blob/v2.3.10/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.9/schemas/probability-compare-input.schema.json",
2
+ "$id": "https://github.com/klimPaskov/hoi4-agent-tools/blob/v2.3.10/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.9/schemas/probability-evaluate-input.schema.json",
2
+ "$id": "https://github.com/klimPaskov/hoi4-agent-tools/blob/v2.3.10/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.9/schemas/probability-inspect-input.schema.json",
2
+ "$id": "https://github.com/klimPaskov/hoi4-agent-tools/blob/v2.3.10/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.9/schemas/probability-render-input.schema.json",
2
+ "$id": "https://github.com/klimPaskov/hoi4-agent-tools/blob/v2.3.10/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.9/schemas/probability-scenario-set.schema.json",
2
+ "$id": "https://github.com/klimPaskov/hoi4-agent-tools/blob/v2.3.10/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.9/schemas/probability-sequence-input.schema.json",
2
+ "$id": "https://github.com/klimPaskov/hoi4-agent-tools/blob/v2.3.10/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.9/schemas/probability-simulate-input.schema.json",
2
+ "$id": "https://github.com/klimPaskov/hoi4-agent-tools/blob/v2.3.10/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.9/schemas/probability-sweep-input.schema.json",
2
+ "$id": "https://github.com/klimPaskov/hoi4-agent-tools/blob/v2.3.10/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.9",
6
+ "version": "2.3.10",
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.9",
16
+ "version": "2.3.10",
17
17
  "transport": {
18
18
  "type": "stdio"
19
19
  }