hoi4-agent-tools 3.0.5 → 3.0.6
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 +6 -0
- package/dist/hoi4_agent_tools/core/engine.js +5 -0
- package/dist/hoi4_agent_tools/core/idle-cache-lifetime.js +62 -0
- package/dist/hoi4_agent_tools/core/scanner.js +34 -7
- package/dist/hoi4_agent_tools/event/service.js +12 -1
- package/dist/hoi4_agent_tools/gui/assets.js +4 -3
- package/dist/hoi4_agent_tools/gui/studio.js +1 -0
- package/dist/hoi4_agent_tools/mcp/tools/chaosx.js +9 -0
- package/dist/hoi4_agent_tools/mcp/tools/event.js +14 -0
- package/dist/hoi4_agent_tools/mcp/tools/focus.js +12 -2
- package/dist/hoi4_agent_tools/mcp/tools/gui.js +14 -0
- package/dist/hoi4_agent_tools/mcp/tools/map.js +14 -0
- package/dist/hoi4_agent_tools/mcp/tools/probability.js +30 -0
- package/dist/hoi4_agent_tools/mcp/tools/technology.js +14 -0
- package/dist/hoi4_agent_tools/mcp/transports/bounded-stdio.js +21 -0
- package/dist/hoi4_agent_tools/probability/service.js +25 -2
- package/dist/hoi4_agent_tools/technology/service.js +12 -1
- package/dist/hoi4_agent_tools/version.js +1 -1
- package/docs/gui.md +1 -1
- package/docs/images/readme/chaos-meter-mcp.png +0 -0
- package/docs/images/readme/communist-insurgency-mcp.png +0 -0
- package/docs/images/readme/settings-advanced-mcp.png +0 -0
- package/docs/images/readme/settings-events-mcp.png +0 -0
- package/package.json +1 -1
- package/schemas/configuration.schema.json +1 -1
- package/schemas/continuous-focus-palette.schema.json +1 -1
- package/schemas/custom-weighted-pool.schema.json +1 -1
- package/schemas/event-feature-manifest.schema.json +1 -1
- package/schemas/focus-plan.schema.json +1 -1
- package/schemas/focus-planning-sidecar.schema.json +1 -1
- package/schemas/gui-animation-source.schema.json +1 -1
- package/schemas/gui-helper.schema.json +1 -1
- package/schemas/gui-scenario.schema.json +1 -1
- package/schemas/map-operation.schema.json +1 -1
- package/schemas/operation-result.schema.json +1 -1
- package/schemas/probability-analysis-result.schema.json +1 -1
- package/schemas/probability-compare-input.schema.json +1 -1
- package/schemas/probability-evaluate-input.schema.json +1 -1
- package/schemas/probability-inspect-input.schema.json +1 -1
- package/schemas/probability-render-input.schema.json +1 -1
- package/schemas/probability-scenario-set.schema.json +1 -1
- package/schemas/probability-sequence-input.schema.json +1 -1
- package/schemas/probability-simulate-input.schema.json +1 -1
- package/schemas/probability-sweep-input.schema.json +1 -1
- package/server.json +2 -2
package/CHANGELOG.md
CHANGED
|
@@ -4,6 +4,12 @@
|
|
|
4
4
|
|
|
5
5
|
No unreleased changes.
|
|
6
6
|
|
|
7
|
+
## 3.0.6 - 2026-09-01
|
|
8
|
+
|
|
9
|
+
- Prevent long-lived coding-agent tasks from exhausting the host and closing MCP transports. Stdio disconnects now abort in-flight requests, vanilla scan caches are byte-bounded, event and technology histories are reduced, probability results are bounded, and heavy domain caches are released after a concurrent-safe idle window.
|
|
10
|
+
- Improve enlarged HOI4 bitmap text with restrained Lanczos2 interpolation while leaving native atlas coverage unchanged. The renderer still applies no sharpening, thresholding, opacity gain, or reconstructed edges.
|
|
11
|
+
- Refresh the source-backed Chaos Meter, Communist Insurgency, and settings-window render examples with the production GUI route.
|
|
12
|
+
|
|
7
13
|
## 3.0.5 - 2026-09-01
|
|
8
14
|
|
|
9
15
|
- Remove enlarged-font edge reconstruction and per-glyph coverage normalization. HOI4 bitmap glyphs now use their decoded atlas samples with nearest-neighbour scaling and integer output placement, without synthetic sharpening, thresholding, gain adjustment, or invented edge pixels.
|
|
@@ -210,6 +210,11 @@ export class CoreEngine {
|
|
|
210
210
|
flight.controller.abort();
|
|
211
211
|
}
|
|
212
212
|
}
|
|
213
|
+
/** Drop completed scan buffers without invalidating revisions or interrupting active scans. */
|
|
214
|
+
releaseScanCaches() {
|
|
215
|
+
this.#scanCache.clear();
|
|
216
|
+
this.scanner.clearCaches();
|
|
217
|
+
}
|
|
213
218
|
/** Monotonic cache generation used by domain services to invalidate derived snapshots. */
|
|
214
219
|
generation(workspaceId) {
|
|
215
220
|
return this.#scanGenerations.get(workspaceId) ?? 0;
|
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
export const DEFAULT_IDLE_CACHE_RELEASE_MS = 30_000;
|
|
2
|
+
/** Keeps reusable analysis caches alive across an immediate tool sequence, then releases them. */
|
|
3
|
+
export class IdleCacheLifetime {
|
|
4
|
+
releaseCaches;
|
|
5
|
+
idleMs;
|
|
6
|
+
#active = 0;
|
|
7
|
+
#timer;
|
|
8
|
+
constructor(releaseCaches, idleMs = DEFAULT_IDLE_CACHE_RELEASE_MS) {
|
|
9
|
+
this.releaseCaches = releaseCaches;
|
|
10
|
+
this.idleMs = idleMs;
|
|
11
|
+
}
|
|
12
|
+
release() {
|
|
13
|
+
try {
|
|
14
|
+
this.releaseCaches();
|
|
15
|
+
}
|
|
16
|
+
catch (error) {
|
|
17
|
+
process.stderr.write(`${JSON.stringify({
|
|
18
|
+
event: 'cache_release_failed',
|
|
19
|
+
level: 'error',
|
|
20
|
+
message: error instanceof Error ? error.message : String(error),
|
|
21
|
+
})}\n`);
|
|
22
|
+
}
|
|
23
|
+
}
|
|
24
|
+
begin() {
|
|
25
|
+
if (this.#timer !== undefined) {
|
|
26
|
+
clearTimeout(this.#timer);
|
|
27
|
+
this.#timer = undefined;
|
|
28
|
+
}
|
|
29
|
+
this.#active += 1;
|
|
30
|
+
let ended = false;
|
|
31
|
+
return () => {
|
|
32
|
+
if (ended)
|
|
33
|
+
return;
|
|
34
|
+
ended = true;
|
|
35
|
+
this.#active = Math.max(0, this.#active - 1);
|
|
36
|
+
if (this.#active !== 0)
|
|
37
|
+
return;
|
|
38
|
+
this.#timer = setTimeout(() => {
|
|
39
|
+
this.#timer = undefined;
|
|
40
|
+
if (this.#active === 0)
|
|
41
|
+
this.release();
|
|
42
|
+
}, this.idleMs);
|
|
43
|
+
this.#timer.unref();
|
|
44
|
+
};
|
|
45
|
+
}
|
|
46
|
+
async run(operation) {
|
|
47
|
+
const end = this.begin();
|
|
48
|
+
try {
|
|
49
|
+
return await operation();
|
|
50
|
+
}
|
|
51
|
+
finally {
|
|
52
|
+
end();
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
clearNow() {
|
|
56
|
+
if (this.#timer !== undefined)
|
|
57
|
+
clearTimeout(this.#timer);
|
|
58
|
+
this.#timer = undefined;
|
|
59
|
+
if (this.#active === 0)
|
|
60
|
+
this.release();
|
|
61
|
+
}
|
|
62
|
+
}
|
|
@@ -29,12 +29,15 @@ export class WorkspaceScanner {
|
|
|
29
29
|
#sourceCache = new Map();
|
|
30
30
|
#gameScanCache = new Map();
|
|
31
31
|
#sourceCacheBytes = 0;
|
|
32
|
+
#gameScanCacheBytes = 0;
|
|
32
33
|
#sourceCacheMaxBytes;
|
|
34
|
+
#gameScanCacheMaxBytes;
|
|
33
35
|
constructor(serverMaxFiles = DEFAULT_SCAN_MAX_FILES, serverMaxBytes = DEFAULT_SCAN_MAX_BYTES, serverMaxFileBytes = DEFAULT_SCAN_MAX_FILE_BYTES) {
|
|
34
36
|
this.serverMaxFiles = serverMaxFiles;
|
|
35
37
|
this.serverMaxBytes = serverMaxBytes;
|
|
36
38
|
this.serverMaxFileBytes = serverMaxFileBytes;
|
|
37
|
-
this.#sourceCacheMaxBytes = Math.max(
|
|
39
|
+
this.#sourceCacheMaxBytes = Math.max(1, Math.min(134_217_728, serverMaxBytes));
|
|
40
|
+
this.#gameScanCacheMaxBytes = Math.min(134_217_728, serverMaxBytes);
|
|
38
41
|
}
|
|
39
42
|
cacheKey(absolutePath) {
|
|
40
43
|
const resolved = path.resolve(absolutePath);
|
|
@@ -64,15 +67,39 @@ export class WorkspaceScanner {
|
|
|
64
67
|
});
|
|
65
68
|
}
|
|
66
69
|
retainGameScan(key, files) {
|
|
70
|
+
const bytes = files.reduce((total, file) => total + file.size, 0);
|
|
71
|
+
const previous = this.#gameScanCache.get(key);
|
|
72
|
+
if (previous !== undefined)
|
|
73
|
+
this.#gameScanCacheBytes -= previous.bytes;
|
|
67
74
|
this.#gameScanCache.delete(key);
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
75
|
+
if (bytes > this.#gameScanCacheMaxBytes)
|
|
76
|
+
return;
|
|
77
|
+
this.#gameScanCache.set(key, { files: files.map((file) => ({ ...file })), bytes });
|
|
78
|
+
this.#gameScanCacheBytes += bytes;
|
|
79
|
+
while (this.#gameScanCache.size > 8 || this.#gameScanCacheBytes > this.#gameScanCacheMaxBytes) {
|
|
80
|
+
const oldest = this.#gameScanCache.entries().next().value;
|
|
71
81
|
if (oldest === undefined)
|
|
72
82
|
break;
|
|
73
|
-
this.#gameScanCache.delete(oldest);
|
|
83
|
+
this.#gameScanCache.delete(oldest[0]);
|
|
84
|
+
this.#gameScanCacheBytes -= oldest[1].bytes;
|
|
74
85
|
}
|
|
75
86
|
}
|
|
87
|
+
/** Release retained source buffers after an idle MCP analysis batch. */
|
|
88
|
+
clearCaches() {
|
|
89
|
+
this.#sourceCache.clear();
|
|
90
|
+
this.#sourceCacheBytes = 0;
|
|
91
|
+
this.#gameScanCache.clear();
|
|
92
|
+
this.#gameScanCacheBytes = 0;
|
|
93
|
+
}
|
|
94
|
+
/** Cache accounting used by lifecycle and regression tests. */
|
|
95
|
+
cacheUsage() {
|
|
96
|
+
return {
|
|
97
|
+
sourceBytes: this.#sourceCacheBytes,
|
|
98
|
+
sourceEntries: this.#sourceCache.size,
|
|
99
|
+
gameScanBytes: this.#gameScanCacheBytes,
|
|
100
|
+
gameScanEntries: this.#gameScanCache.size,
|
|
101
|
+
};
|
|
102
|
+
}
|
|
76
103
|
async scan(workspace, options) {
|
|
77
104
|
options.signal?.throwIfAborted();
|
|
78
105
|
const maxFiles = options.maxFiles ?? this.serverMaxFiles;
|
|
@@ -102,13 +129,13 @@ export class WorkspaceScanner {
|
|
|
102
129
|
if (cachedGameFiles !== undefined && gameScanKey !== undefined) {
|
|
103
130
|
this.#gameScanCache.delete(gameScanKey);
|
|
104
131
|
this.#gameScanCache.set(gameScanKey, cachedGameFiles);
|
|
105
|
-
enumeratedFiles += cachedGameFiles.length;
|
|
132
|
+
enumeratedFiles += cachedGameFiles.files.length;
|
|
106
133
|
if (enumeratedFiles > maxFiles)
|
|
107
134
|
throw new ServiceError('SCAN_FILE_LIMIT', 'Scan exceeds the configured file limit', {
|
|
108
135
|
files: enumeratedFiles,
|
|
109
136
|
limit: maxFiles,
|
|
110
137
|
});
|
|
111
|
-
for (const file of cachedGameFiles) {
|
|
138
|
+
for (const file of cachedGameFiles.files) {
|
|
112
139
|
totalBytes += file.size;
|
|
113
140
|
if (totalBytes > maxBytes)
|
|
114
141
|
throw new ServiceError('SCAN_BYTE_LIMIT', 'Scan exceeds the configured byte limit', {
|
|
@@ -41,6 +41,10 @@ class BoundedEventFragmentCache {
|
|
|
41
41
|
this.#sourceBytes -= oldest[1].sourceBytes;
|
|
42
42
|
}
|
|
43
43
|
}
|
|
44
|
+
clear() {
|
|
45
|
+
this.#entries.clear();
|
|
46
|
+
this.#sourceBytes = 0;
|
|
47
|
+
}
|
|
44
48
|
}
|
|
45
49
|
function eventGraphCacheKey(workspaceId, projectHelpers, analysisMode = 'full') {
|
|
46
50
|
return `${workspaceId}\0${projectHelpers ? 'expanded' : 'structural'}\0${analysisMode}`;
|
|
@@ -208,7 +212,7 @@ function rememberGraph(state, workspaceId, graph) {
|
|
|
208
212
|
const history = state.history.get(workspaceId) ?? new Map();
|
|
209
213
|
history.delete(graph.revision);
|
|
210
214
|
history.set(graph.revision, graph);
|
|
211
|
-
while (history.size >
|
|
215
|
+
while (history.size > 2) {
|
|
212
216
|
const oldest = history.keys().next().value;
|
|
213
217
|
if (oldest === undefined)
|
|
214
218
|
break;
|
|
@@ -694,6 +698,13 @@ export class EventChainViewer {
|
|
|
694
698
|
this.engine = engine;
|
|
695
699
|
this.#state = sharedState(engine);
|
|
696
700
|
}
|
|
701
|
+
/** Release full source graphs retained between adjacent MCP calls. */
|
|
702
|
+
clearCaches() {
|
|
703
|
+
this.#state.current.clear();
|
|
704
|
+
this.#state.history.clear();
|
|
705
|
+
this.#state.fragments.clear();
|
|
706
|
+
this.engine.releaseScanCaches();
|
|
707
|
+
}
|
|
697
708
|
async scan(workspaceId, options = {}) {
|
|
698
709
|
options.signal?.throwIfAborted();
|
|
699
710
|
// Authorization is request-scoped. Never let a graph cached by one
|
|
@@ -928,11 +928,12 @@ export class GuiAssetCatalog {
|
|
|
928
928
|
limitInputPixels: RENDER_MAX_DECODED_PIXELS,
|
|
929
929
|
});
|
|
930
930
|
if (targetWidth !== extracted.info.width || targetHeight !== extracted.info.height) {
|
|
931
|
-
// BMFont pages are the font.
|
|
932
|
-
//
|
|
931
|
+
// BMFont pages are the font. A restrained two-lobe resample keeps enlarged text from
|
|
932
|
+
// becoming blocky without applying sharpening, thresholding, gain, or reconstructed
|
|
933
|
+
// contours. Native-size coverage remains byte-for-byte unchanged.
|
|
933
934
|
pipeline = pipeline.resize(targetWidth, targetHeight, {
|
|
934
935
|
fit: 'fill',
|
|
935
|
-
kernel: sharp.kernel.nearest,
|
|
936
|
+
kernel: scale > 1 ? sharp.kernel.lanczos2 : sharp.kernel.nearest,
|
|
936
937
|
});
|
|
937
938
|
}
|
|
938
939
|
return pipeline
|
|
@@ -722,6 +722,7 @@ export class ScriptedGuiStudio {
|
|
|
722
722
|
/** Release parsed GUI graphs after a bounded batch job has finished using the studio. */
|
|
723
723
|
clearCaches() {
|
|
724
724
|
this.#graphCache.clear();
|
|
725
|
+
this.engine.releaseScanCaches();
|
|
725
726
|
}
|
|
726
727
|
async scan(workspaceId, principal, signal, languages = ['l_english']) {
|
|
727
728
|
signal?.throwIfAborted();
|
|
@@ -4,6 +4,7 @@ import { z } from 'zod/v4';
|
|
|
4
4
|
import { publicArtifactLink } from '../../core/artifacts.js';
|
|
5
5
|
import { compareCodeUnits, hashCanonical } from '../../core/canonical.js';
|
|
6
6
|
import { countryAssetDiscoveryPatterns } from '../../core/domain-scan-patterns.js';
|
|
7
|
+
import { IdleCacheLifetime } from '../../core/idle-cache-lifetime.js';
|
|
7
8
|
import { emptyServiceResult } from '../../core/result.js';
|
|
8
9
|
import { RenderBudget } from '../../core/render-budget.js';
|
|
9
10
|
import { workspaceIdSchema } from '../../schemas/common.js';
|
|
@@ -335,6 +336,10 @@ async function resolveGuiRevision(engine, context, studio, cache, workspaceId, s
|
|
|
335
336
|
export function registerChaosxTools(server, engine, context) {
|
|
336
337
|
const guiStudio = new ScriptedGuiStudio(engine);
|
|
337
338
|
const guiRevisionCache = new Map();
|
|
339
|
+
const guiCacheLifetime = new IdleCacheLifetime(() => {
|
|
340
|
+
guiStudio.clearCaches();
|
|
341
|
+
guiRevisionCache.clear();
|
|
342
|
+
});
|
|
338
343
|
server.registerTool('chaosx.visual_revision', {
|
|
339
344
|
title: 'Check ChaosX visual revisions',
|
|
340
345
|
description: 'Private ChaosX cache-coherency endpoint. Computes exact scripted-GUI source revisions without rendering PNG artifacts.',
|
|
@@ -343,6 +348,7 @@ export function registerChaosxTools(server, engine, context) {
|
|
|
343
348
|
annotations: readOnly,
|
|
344
349
|
}, async (input, extra) => {
|
|
345
350
|
const workspaceId = await resolveServerWorkspaceId(engine, context, input.workspaceId, extra.signal);
|
|
351
|
+
const releaseCaches = guiCacheLifetime.begin();
|
|
346
352
|
try {
|
|
347
353
|
const progress = progressReporter(extra);
|
|
348
354
|
await progress.report(0, 2, 'Checking ChaosX scripted-GUI sources');
|
|
@@ -372,6 +378,9 @@ export function registerChaosxTools(server, engine, context) {
|
|
|
372
378
|
catch (error) {
|
|
373
379
|
return errorResult(error, workspaceId);
|
|
374
380
|
}
|
|
381
|
+
finally {
|
|
382
|
+
releaseCaches();
|
|
383
|
+
}
|
|
375
384
|
});
|
|
376
385
|
server.registerTool('chaosx.focus_country_assets', {
|
|
377
386
|
title: 'Render ChaosX focus country assets',
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { z } from 'zod/v4';
|
|
2
2
|
import { publicArtifactLink } from '../../core/artifacts.js';
|
|
3
3
|
import { compareCodeUnits } from '../../core/canonical.js';
|
|
4
|
+
import { IdleCacheLifetime } from '../../core/idle-cache-lifetime.js';
|
|
4
5
|
import { emptyServiceResult } from '../../core/result.js';
|
|
5
6
|
import { EventChainViewer, eventDiagnostics, } from '../../event/service.js';
|
|
6
7
|
import { eventDirectionSchema, eventGraphReferenceSchema, eventImpactSubjectSchema, eventInspectModeSchema, eventProposedSourceSchema, eventRenderViewSchema, eventSelectorSchema, eventStateSubjectSchema, } from '../../schemas/event.js';
|
|
@@ -305,6 +306,7 @@ function compareRequest(input, context, signal) {
|
|
|
305
306
|
}
|
|
306
307
|
export function registerEventTools(server, engine, context) {
|
|
307
308
|
const viewer = new EventChainViewer(engine);
|
|
309
|
+
const cacheLifetime = new IdleCacheLifetime(() => viewer.clearCaches());
|
|
308
310
|
server.registerTool('hoi4.event_inspect', {
|
|
309
311
|
title: 'Inspect event chains',
|
|
310
312
|
description: 'Scan, find roots, trace, explain paths, inspect state flow, lint, or assess impact. Full source-linked reports are resources.',
|
|
@@ -313,6 +315,7 @@ export function registerEventTools(server, engine, context) {
|
|
|
313
315
|
annotations: readOnlyEventTool,
|
|
314
316
|
}, async (input, extra) => {
|
|
315
317
|
const workspaceId = await resolveServerWorkspaceId(engine, context, input.workspaceId, extra.signal);
|
|
318
|
+
const releaseCaches = cacheLifetime.begin();
|
|
316
319
|
try {
|
|
317
320
|
const progress = progressReporter(extra);
|
|
318
321
|
await progress.report(0, 3, 'Analyzing event chain');
|
|
@@ -343,6 +346,9 @@ export function registerEventTools(server, engine, context) {
|
|
|
343
346
|
catch (error) {
|
|
344
347
|
return errorResult(error, workspaceId);
|
|
345
348
|
}
|
|
349
|
+
finally {
|
|
350
|
+
releaseCaches();
|
|
351
|
+
}
|
|
346
352
|
});
|
|
347
353
|
server.registerTool('hoi4.event_render', {
|
|
348
354
|
title: 'Render event chains',
|
|
@@ -352,6 +358,7 @@ export function registerEventTools(server, engine, context) {
|
|
|
352
358
|
annotations: readOnlyEventTool,
|
|
353
359
|
}, async (input, extra) => {
|
|
354
360
|
const workspaceId = await resolveServerWorkspaceId(engine, context, input.workspaceId, extra.signal);
|
|
361
|
+
const releaseCaches = cacheLifetime.begin();
|
|
355
362
|
try {
|
|
356
363
|
const progress = progressReporter(extra);
|
|
357
364
|
await progress.report(0, 3, 'Rendering event-chain view');
|
|
@@ -389,6 +396,9 @@ export function registerEventTools(server, engine, context) {
|
|
|
389
396
|
catch (error) {
|
|
390
397
|
return errorResult(error, workspaceId);
|
|
391
398
|
}
|
|
399
|
+
finally {
|
|
400
|
+
releaseCaches();
|
|
401
|
+
}
|
|
392
402
|
});
|
|
393
403
|
server.registerTool('hoi4.event_compare', {
|
|
394
404
|
title: 'Compare event chains',
|
|
@@ -398,6 +408,7 @@ export function registerEventTools(server, engine, context) {
|
|
|
398
408
|
annotations: readOnlyEventTool,
|
|
399
409
|
}, async (input, extra) => {
|
|
400
410
|
const workspaceId = await resolveServerWorkspaceId(engine, context, input.workspaceId, extra.signal);
|
|
411
|
+
const releaseCaches = cacheLifetime.begin();
|
|
401
412
|
try {
|
|
402
413
|
const progress = progressReporter(extra);
|
|
403
414
|
await progress.report(0, 3, 'Comparing event-chain graphs');
|
|
@@ -463,5 +474,8 @@ export function registerEventTools(server, engine, context) {
|
|
|
463
474
|
catch (error) {
|
|
464
475
|
return errorResult(error, workspaceId);
|
|
465
476
|
}
|
|
477
|
+
finally {
|
|
478
|
+
releaseCaches();
|
|
479
|
+
}
|
|
466
480
|
});
|
|
467
481
|
}
|
|
@@ -2,6 +2,7 @@ import { z } from 'zod/v4';
|
|
|
2
2
|
import { boundedSourceHashEvidence, publicArtifactLink } from '../../core/artifacts.js';
|
|
3
3
|
import { compareCodeUnits, canonicalJson, hashCanonical } from '../../core/canonical.js';
|
|
4
4
|
import { focusDomainScanPatterns } from '../../core/domain-scan-patterns.js';
|
|
5
|
+
import { IdleCacheLifetime } from '../../core/idle-cache-lifetime.js';
|
|
5
6
|
import { RenderBudget } from '../../core/render-budget.js';
|
|
6
7
|
import { emptyServiceResult, ServiceError } from '../../core/result.js';
|
|
7
8
|
import { parseClausewitz } from '../../core/source/index.js';
|
|
@@ -604,6 +605,7 @@ function validationFromDiagnostics(diagnostics) {
|
|
|
604
605
|
}
|
|
605
606
|
export function registerFocusTools(server, engine, context) {
|
|
606
607
|
const workbench = new FocusWorkbench(engine.resolver, engine.transactions, engine.artifacts);
|
|
608
|
+
const cacheLifetime = new IdleCacheLifetime(() => engine.releaseScanCaches());
|
|
607
609
|
server.registerTool('hoi4.focus_inspect', {
|
|
608
610
|
title: 'Inspect focus trees',
|
|
609
611
|
description: 'Inspect national trees or continuous palettes for creation and cleanup, including continuous-focus placement, complete plans, references, diagnostics, and stable layout decisions.',
|
|
@@ -613,6 +615,7 @@ export function registerFocusTools(server, engine, context) {
|
|
|
613
615
|
}, async (input, extra) => {
|
|
614
616
|
const { workspaceId: requestedWorkspaceId, relativePath } = input;
|
|
615
617
|
const workspaceId = await resolveServerWorkspaceForSource(engine, context, requestedWorkspaceId, relativePath, extra.signal);
|
|
618
|
+
const releaseCaches = cacheLifetime.begin();
|
|
616
619
|
try {
|
|
617
620
|
const progress = progressReporter(extra);
|
|
618
621
|
await progress.report(0, 3, 'Building shared workspace index');
|
|
@@ -824,6 +827,9 @@ export function registerFocusTools(server, engine, context) {
|
|
|
824
827
|
catch (error) {
|
|
825
828
|
return errorResult(error, workspaceId);
|
|
826
829
|
}
|
|
830
|
+
finally {
|
|
831
|
+
releaseCaches();
|
|
832
|
+
}
|
|
827
833
|
});
|
|
828
834
|
server.registerTool('hoi4.focus_render', {
|
|
829
835
|
title: 'Render focus review artifacts',
|
|
@@ -831,14 +837,14 @@ export function registerFocusTools(server, engine, context) {
|
|
|
831
837
|
inputSchema: focusRenderInput,
|
|
832
838
|
outputSchema: focusRenderOutputSchema,
|
|
833
839
|
annotations: artifactProducing,
|
|
834
|
-
}, (input, extra) => executeFocusVisualTool(engine, workbench, context, input, extra, false));
|
|
840
|
+
}, (input, extra) => cacheLifetime.run(() => executeFocusVisualTool(engine, workbench, context, input, extra, false)));
|
|
835
841
|
server.registerTool('hoi4.focus_raster', {
|
|
836
842
|
title: 'Rasterize focus review artifacts',
|
|
837
843
|
description: 'Produce the high-fidelity focus review with decoded source icons and deterministic PNG output. Use focus_render for the faster structural HTML, SVG, and JSON view.',
|
|
838
844
|
inputSchema: focusRenderInput,
|
|
839
845
|
outputSchema: focusRenderOutputSchema,
|
|
840
846
|
annotations: artifactProducing,
|
|
841
|
-
}, (input, extra) => executeFocusVisualTool(engine, workbench, context, input, extra, true));
|
|
847
|
+
}, (input, extra) => cacheLifetime.run(() => executeFocusVisualTool(engine, workbench, context, input, extra, true)));
|
|
842
848
|
server.registerTool('hoi4.focus_rewrite', {
|
|
843
849
|
title: 'Create or clean up focus content',
|
|
844
850
|
description: 'Create or clean up a national tree or continuous palette, validate it, and apply it in one call. Supply a complete plan; set layoutMode compact for automatic arrangement. Existing national trees can omit the plan and use treeId plus layoutMode compact. Set createIfMissing for a new file.',
|
|
@@ -853,6 +859,7 @@ export function registerFocusTools(server, engine, context) {
|
|
|
853
859
|
}, async (input, extra) => {
|
|
854
860
|
const { workspaceId: requestedWorkspaceId, relativePath, createIfMissing, horizontalSpacing, verticalSpacing, padding, reviewScale, } = input;
|
|
855
861
|
const workspaceId = await resolveServerWorkspaceForSource(engine, context, requestedWorkspaceId, relativePath, extra.signal);
|
|
862
|
+
const releaseCaches = cacheLifetime.begin();
|
|
856
863
|
try {
|
|
857
864
|
requireServerScope(context, 'hoi4:write');
|
|
858
865
|
const progress = progressReporter(extra);
|
|
@@ -1156,5 +1163,8 @@ export function registerFocusTools(server, engine, context) {
|
|
|
1156
1163
|
catch (error) {
|
|
1157
1164
|
return errorResult(error, workspaceId, autonomousFailureContext(error));
|
|
1158
1165
|
}
|
|
1166
|
+
finally {
|
|
1167
|
+
releaseCaches();
|
|
1168
|
+
}
|
|
1159
1169
|
});
|
|
1160
1170
|
}
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { z } from 'zod/v4';
|
|
2
2
|
import { boundedSourceHashEvidence, publicArtifactLink } from '../../core/artifacts.js';
|
|
3
3
|
import { canonicalJson, compareCodeUnits, hashCanonical } from '../../core/canonical.js';
|
|
4
|
+
import { IdleCacheLifetime } from '../../core/idle-cache-lifetime.js';
|
|
4
5
|
import { renderDimensionViolation, RenderBudget, RENDER_MAX_DIMENSION, } from '../../core/render-budget.js';
|
|
5
6
|
import { emptyServiceResult, ServiceError } from '../../core/result.js';
|
|
6
7
|
import { SOURCE_MAX_BYTES } from '../../core/source/index.js';
|
|
@@ -159,6 +160,7 @@ function validationSummary(validation) {
|
|
|
159
160
|
}
|
|
160
161
|
export function registerGuiTools(server, engine, context) {
|
|
161
162
|
const studio = new ScriptedGuiStudio(engine);
|
|
163
|
+
const cacheLifetime = new IdleCacheLifetime(() => studio.clearCaches());
|
|
162
164
|
server.registerTool('hoi4.gui_inspect', {
|
|
163
165
|
title: 'Inspect scripted GUI',
|
|
164
166
|
description: 'Inspect GUI sources and scenarios.',
|
|
@@ -167,6 +169,7 @@ export function registerGuiTools(server, engine, context) {
|
|
|
167
169
|
annotations: artifactProducing,
|
|
168
170
|
}, async ({ workspaceId: requestedWorkspaceId, windowName, scenario, relatedScenarios, generatedScenarios, }, extra) => {
|
|
169
171
|
const workspaceId = await resolveServerWorkspaceId(engine, context, requestedWorkspaceId, extra.signal);
|
|
172
|
+
const releaseCaches = cacheLifetime.begin();
|
|
170
173
|
try {
|
|
171
174
|
const progress = progressReporter(extra);
|
|
172
175
|
await progress.report(0, 3, 'Building GUI source graph');
|
|
@@ -276,10 +279,14 @@ export function registerGuiTools(server, engine, context) {
|
|
|
276
279
|
catch (error) {
|
|
277
280
|
return errorResult(error, workspaceId);
|
|
278
281
|
}
|
|
282
|
+
finally {
|
|
283
|
+
releaseCaches();
|
|
284
|
+
}
|
|
279
285
|
});
|
|
280
286
|
const render = async (input, extra, code) => {
|
|
281
287
|
const workspaceId = await resolveServerWorkspaceId(engine, context, input.workspaceId, extra.signal);
|
|
282
288
|
const { windowName } = input;
|
|
289
|
+
const releaseCaches = cacheLifetime.begin();
|
|
283
290
|
try {
|
|
284
291
|
const progress = progressReporter(extra);
|
|
285
292
|
await progress.report(0, 4, 'Building GUI source graph');
|
|
@@ -343,6 +350,9 @@ export function registerGuiTools(server, engine, context) {
|
|
|
343
350
|
catch (error) {
|
|
344
351
|
return errorResult(error, workspaceId);
|
|
345
352
|
}
|
|
353
|
+
finally {
|
|
354
|
+
releaseCaches();
|
|
355
|
+
}
|
|
346
356
|
};
|
|
347
357
|
const renderInput = guiBaseInput
|
|
348
358
|
.extend({
|
|
@@ -488,6 +498,7 @@ export function registerGuiTools(server, engine, context) {
|
|
|
488
498
|
}, async (input, extra) => {
|
|
489
499
|
const workspaceId = await resolveServerWorkspaceId(engine, context, input.workspaceId, extra.signal);
|
|
490
500
|
const { relativePath, windowName, scenario } = input;
|
|
501
|
+
const releaseCaches = cacheLifetime.begin();
|
|
491
502
|
try {
|
|
492
503
|
requireServerScope(context, 'hoi4:write');
|
|
493
504
|
const progress = progressReporter(extra);
|
|
@@ -567,5 +578,8 @@ export function registerGuiTools(server, engine, context) {
|
|
|
567
578
|
catch (error) {
|
|
568
579
|
return errorResult(error, workspaceId, autonomousFailureContext(error));
|
|
569
580
|
}
|
|
581
|
+
finally {
|
|
582
|
+
releaseCaches();
|
|
583
|
+
}
|
|
570
584
|
});
|
|
571
585
|
}
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { z } from 'zod/v4';
|
|
2
2
|
import { boundedSourceHashEvidence, publicArtifactLink, } from '../../core/artifacts.js';
|
|
3
3
|
import { canonicalJson, hashCanonical } from '../../core/canonical.js';
|
|
4
|
+
import { IdleCacheLifetime } from '../../core/idle-cache-lifetime.js';
|
|
4
5
|
import { emptyServiceResult } from '../../core/result.js';
|
|
5
6
|
import { AgentNudger, allocateMapIdentifiersAsync, buildMapCatalog, exportProvinceGeometryRowRuns, lookupMapCoordinate, MAP_PROVINCE_GEOMETRY_SELECTOR_LIMIT, renderMap, searchMapCatalog, } from '../../map/index.js';
|
|
6
7
|
import { workspaceIdSchema } from '../../schemas/common.js';
|
|
@@ -349,6 +350,7 @@ function selectedMapEntities(snapshot, provinceIds, stateIds, regionIds) {
|
|
|
349
350
|
}
|
|
350
351
|
export function registerMapTools(server, engine, context) {
|
|
351
352
|
const nudger = new AgentNudger(engine);
|
|
353
|
+
const cacheLifetime = new IdleCacheLifetime(() => engine.releaseScanCaches());
|
|
352
354
|
server.registerTool('hoi4.map_inspect', {
|
|
353
355
|
title: 'Inspect HOI4 map',
|
|
354
356
|
description: 'Render, validate, search, and click the complete map.',
|
|
@@ -391,6 +393,7 @@ export function registerMapTools(server, engine, context) {
|
|
|
391
393
|
annotations: artifactProducing,
|
|
392
394
|
}, async ({ workspaceId: requestedWorkspaceId, provinceIds, stateIds, regionIds, query, queryLimit, coordinates, includeOverview, allocationRequests, }, extra) => {
|
|
393
395
|
const workspaceId = await resolveServerWorkspaceId(engine, context, requestedWorkspaceId, extra.signal);
|
|
396
|
+
const releaseCaches = cacheLifetime.begin();
|
|
394
397
|
try {
|
|
395
398
|
const progress = progressReporter(extra);
|
|
396
399
|
await progress.report(0, 3, 'Inspecting and validating the map');
|
|
@@ -573,6 +576,9 @@ export function registerMapTools(server, engine, context) {
|
|
|
573
576
|
catch (error) {
|
|
574
577
|
return errorResult(error, workspaceId);
|
|
575
578
|
}
|
|
579
|
+
finally {
|
|
580
|
+
releaseCaches();
|
|
581
|
+
}
|
|
576
582
|
});
|
|
577
583
|
server.registerTool('hoi4.map_render', {
|
|
578
584
|
title: 'Render map inspection artifacts',
|
|
@@ -589,6 +595,7 @@ export function registerMapTools(server, engine, context) {
|
|
|
589
595
|
annotations: artifactProducing,
|
|
590
596
|
}, async ({ workspaceId: requestedWorkspaceId, layer, overlays, scale }, extra) => {
|
|
591
597
|
const workspaceId = await resolveServerWorkspaceId(engine, context, requestedWorkspaceId, extra.signal);
|
|
598
|
+
const releaseCaches = cacheLifetime.begin();
|
|
592
599
|
try {
|
|
593
600
|
const progress = progressReporter(extra);
|
|
594
601
|
await progress.report(0, 3, 'Rendering offline map layer');
|
|
@@ -615,6 +622,9 @@ export function registerMapTools(server, engine, context) {
|
|
|
615
622
|
catch (error) {
|
|
616
623
|
return errorResult(error, workspaceId);
|
|
617
624
|
}
|
|
625
|
+
finally {
|
|
626
|
+
releaseCaches();
|
|
627
|
+
}
|
|
618
628
|
});
|
|
619
629
|
server.registerTool('hoi4.map_rewrite', {
|
|
620
630
|
title: 'Create or clean up map content',
|
|
@@ -635,6 +645,7 @@ export function registerMapTools(server, engine, context) {
|
|
|
635
645
|
},
|
|
636
646
|
}, async ({ workspaceId: requestedWorkspaceId, operations, diffScale }, extra) => {
|
|
637
647
|
const workspaceId = await resolveServerWorkspaceId(engine, context, requestedWorkspaceId, extra.signal);
|
|
648
|
+
const releaseCaches = cacheLifetime.begin();
|
|
638
649
|
try {
|
|
639
650
|
requireServerScope(context, 'hoi4:write');
|
|
640
651
|
const progress = progressReporter(extra);
|
|
@@ -706,5 +717,8 @@ export function registerMapTools(server, engine, context) {
|
|
|
706
717
|
catch (error) {
|
|
707
718
|
return errorResult(error, workspaceId, autonomousFailureContext(error));
|
|
708
719
|
}
|
|
720
|
+
finally {
|
|
721
|
+
releaseCaches();
|
|
722
|
+
}
|
|
709
723
|
});
|
|
710
724
|
}
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { z } from 'zod/v4';
|
|
2
|
+
import { IdleCacheLifetime } from '../../core/idle-cache-lifetime.js';
|
|
2
3
|
import { emptyServiceResult } from '../../core/result.js';
|
|
3
4
|
import { ProbabilityAnalyzer, } from '../../probability/service.js';
|
|
4
5
|
import { customWeightedPoolManifestSchema, probabilityAcceptanceBandSchema, probabilityAdapterIdSchema, probabilityDiagnosticThresholdsSchema, probabilityMetricSchema, probabilityOutputSchema, probabilityRenderFilterSchema, probabilityScenarioSetSchema, probabilitySamplingMethodSchema, probabilitySourceSchema, } from '../../schemas/probability.js';
|
|
@@ -303,6 +304,7 @@ function analysisServiceResult(workspaceId, result) {
|
|
|
303
304
|
}
|
|
304
305
|
export function registerProbabilityTools(server, engine, context) {
|
|
305
306
|
const analyzer = new ProbabilityAnalyzer(engine);
|
|
307
|
+
const cacheLifetime = new IdleCacheLifetime(() => analyzer.clearCaches());
|
|
306
308
|
server.registerTool('hoi4.probability_inspect', {
|
|
307
309
|
title: 'Inspect AI and MTTH weighted logic',
|
|
308
310
|
description: 'Discover weighted adapters, candidates, provenance, and required inputs.',
|
|
@@ -312,6 +314,7 @@ export function registerProbabilityTools(server, engine, context) {
|
|
|
312
314
|
}, async (input, extra) => {
|
|
313
315
|
const progress = progressReporter(extra);
|
|
314
316
|
const base = await requestContext(engine, context, input.workspaceId, input.refresh, progress.signal);
|
|
317
|
+
const releaseCaches = cacheLifetime.begin();
|
|
315
318
|
try {
|
|
316
319
|
await progress.report(0, 2, 'Inspecting weighted source');
|
|
317
320
|
const inspected = await analyzer.inspect(base, input.adapter, input.source, input.candidatePool, input.customPoolManifest);
|
|
@@ -364,6 +367,9 @@ export function registerProbabilityTools(server, engine, context) {
|
|
|
364
367
|
catch (error) {
|
|
365
368
|
return errorResult(error, base.workspaceId);
|
|
366
369
|
}
|
|
370
|
+
finally {
|
|
371
|
+
releaseCaches();
|
|
372
|
+
}
|
|
367
373
|
});
|
|
368
374
|
server.registerTool('hoi4.probability_evaluate', {
|
|
369
375
|
title: 'Evaluate AI and MTTH scenarios',
|
|
@@ -374,6 +380,7 @@ export function registerProbabilityTools(server, engine, context) {
|
|
|
374
380
|
}, async (input, extra) => {
|
|
375
381
|
const progress = progressReporter(extra);
|
|
376
382
|
const base = await requestContext(engine, context, input.workspaceId, input.refresh, progress.signal);
|
|
383
|
+
const releaseCaches = cacheLifetime.begin();
|
|
377
384
|
try {
|
|
378
385
|
await progress.report(0, 3, 'Scanning and evaluating weighted source');
|
|
379
386
|
const request = {
|
|
@@ -388,6 +395,9 @@ export function registerProbabilityTools(server, engine, context) {
|
|
|
388
395
|
catch (error) {
|
|
389
396
|
return errorResult(error, base.workspaceId);
|
|
390
397
|
}
|
|
398
|
+
finally {
|
|
399
|
+
releaseCaches();
|
|
400
|
+
}
|
|
391
401
|
});
|
|
392
402
|
server.registerTool('hoi4.probability_sweep', {
|
|
393
403
|
title: 'Sweep AI and MTTH parameters',
|
|
@@ -398,6 +408,7 @@ export function registerProbabilityTools(server, engine, context) {
|
|
|
398
408
|
}, async (input, extra) => {
|
|
399
409
|
const progress = progressReporter(extra);
|
|
400
410
|
const base = await requestContext(engine, context, input.workspaceId, input.refresh, progress.signal);
|
|
411
|
+
const releaseCaches = cacheLifetime.begin();
|
|
401
412
|
try {
|
|
402
413
|
await progress.report(0, 3, 'Evaluating parameter sweep');
|
|
403
414
|
const request = {
|
|
@@ -412,6 +423,9 @@ export function registerProbabilityTools(server, engine, context) {
|
|
|
412
423
|
catch (error) {
|
|
413
424
|
return errorResult(error, base.workspaceId);
|
|
414
425
|
}
|
|
426
|
+
finally {
|
|
427
|
+
releaseCaches();
|
|
428
|
+
}
|
|
415
429
|
});
|
|
416
430
|
server.registerTool('hoi4.probability_simulate', {
|
|
417
431
|
title: 'Simulate uncertain weighted scenarios',
|
|
@@ -422,6 +436,7 @@ export function registerProbabilityTools(server, engine, context) {
|
|
|
422
436
|
}, async (input, extra) => {
|
|
423
437
|
const progress = progressReporter(extra);
|
|
424
438
|
const base = await requestContext(engine, context, input.workspaceId, input.refresh, progress.signal);
|
|
439
|
+
const releaseCaches = cacheLifetime.begin();
|
|
425
440
|
try {
|
|
426
441
|
await progress.report(0, input.samples, 'Sampling uncertain scenarios');
|
|
427
442
|
const request = {
|
|
@@ -436,6 +451,9 @@ export function registerProbabilityTools(server, engine, context) {
|
|
|
436
451
|
catch (error) {
|
|
437
452
|
return errorResult(error, base.workspaceId);
|
|
438
453
|
}
|
|
454
|
+
finally {
|
|
455
|
+
releaseCaches();
|
|
456
|
+
}
|
|
439
457
|
});
|
|
440
458
|
server.registerTool('hoi4.probability_sequence', {
|
|
441
459
|
title: 'Analyze a declared weighted sequence',
|
|
@@ -446,6 +464,7 @@ export function registerProbabilityTools(server, engine, context) {
|
|
|
446
464
|
}, async (input, extra) => {
|
|
447
465
|
const progress = progressReporter(extra);
|
|
448
466
|
const base = await requestContext(engine, context, input.workspaceId, undefined, progress.signal);
|
|
467
|
+
const releaseCaches = cacheLifetime.begin();
|
|
449
468
|
try {
|
|
450
469
|
await progress.report(0, input.maxSteps, 'Analyzing declared sequence');
|
|
451
470
|
const request = {
|
|
@@ -460,6 +479,9 @@ export function registerProbabilityTools(server, engine, context) {
|
|
|
460
479
|
catch (error) {
|
|
461
480
|
return errorResult(error, base.workspaceId);
|
|
462
481
|
}
|
|
482
|
+
finally {
|
|
483
|
+
releaseCaches();
|
|
484
|
+
}
|
|
463
485
|
});
|
|
464
486
|
server.registerTool('hoi4.probability_compare', {
|
|
465
487
|
title: 'Compare weighted source patches',
|
|
@@ -470,6 +492,7 @@ export function registerProbabilityTools(server, engine, context) {
|
|
|
470
492
|
}, async (input, extra) => {
|
|
471
493
|
const progress = progressReporter(extra);
|
|
472
494
|
const base = await requestContext(engine, context, input.workspaceId, input.refresh, progress.signal);
|
|
495
|
+
const releaseCaches = cacheLifetime.begin();
|
|
473
496
|
try {
|
|
474
497
|
await progress.report(0, 4, 'Comparing weighted source');
|
|
475
498
|
const request = {
|
|
@@ -484,6 +507,9 @@ export function registerProbabilityTools(server, engine, context) {
|
|
|
484
507
|
catch (error) {
|
|
485
508
|
return errorResult(error, base.workspaceId);
|
|
486
509
|
}
|
|
510
|
+
finally {
|
|
511
|
+
releaseCaches();
|
|
512
|
+
}
|
|
487
513
|
});
|
|
488
514
|
server.registerTool('hoi4.probability_render', {
|
|
489
515
|
title: 'Render AI and MTTH analysis',
|
|
@@ -494,6 +520,7 @@ export function registerProbabilityTools(server, engine, context) {
|
|
|
494
520
|
}, async (input, extra) => {
|
|
495
521
|
const progress = progressReporter(extra);
|
|
496
522
|
const base = await requestContext(engine, context, input.workspaceId, undefined, progress.signal);
|
|
523
|
+
const releaseCaches = cacheLifetime.begin();
|
|
497
524
|
try {
|
|
498
525
|
await progress.report(0, input.outputs.length, 'Rendering analysis resources');
|
|
499
526
|
const request = {
|
|
@@ -509,6 +536,9 @@ export function registerProbabilityTools(server, engine, context) {
|
|
|
509
536
|
catch (error) {
|
|
510
537
|
return errorResult(error, base.workspaceId);
|
|
511
538
|
}
|
|
539
|
+
finally {
|
|
540
|
+
releaseCaches();
|
|
541
|
+
}
|
|
512
542
|
});
|
|
513
543
|
server.registerPrompt('hoi4.probability_analysis', {
|
|
514
544
|
title: 'Analyze HOI4 weighted logic',
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { z } from 'zod/v4';
|
|
2
2
|
import { publicArtifactLink } from '../../core/artifacts.js';
|
|
3
3
|
import { compareCodeUnits, hashCanonical } from '../../core/canonical.js';
|
|
4
|
+
import { IdleCacheLifetime } from '../../core/idle-cache-lifetime.js';
|
|
4
5
|
import { emptyServiceResult } from '../../core/result.js';
|
|
5
6
|
import { workspaceIdSchema } from '../../schemas/common.js';
|
|
6
7
|
import { technologyDefectClassSchema, technologyDirectionSchema, technologyGraphReferenceSchema, technologyIdSchema, technologyImpactSchema, technologyProposedSourceSchema, technologyRenderViewSchema, technologyUnlockKindSchema, } from '../../schemas/technology.js';
|
|
@@ -238,6 +239,7 @@ function analysisRequest(input, workspaceId, context, signal) {
|
|
|
238
239
|
}
|
|
239
240
|
export function registerTechnologyTools(server, engine, context) {
|
|
240
241
|
const viewer = new TechnologyTreeViewer(engine);
|
|
242
|
+
const cacheLifetime = new IdleCacheLifetime(() => viewer.clearCaches());
|
|
241
243
|
server.registerTool('hoi4.tech_inspect', {
|
|
242
244
|
title: 'Inspect technology trees',
|
|
243
245
|
description: 'Scan, discover folders, trace, explain, inspect unlocks or bonuses, lint, and assess impact.',
|
|
@@ -246,6 +248,7 @@ export function registerTechnologyTools(server, engine, context) {
|
|
|
246
248
|
annotations: readOnly,
|
|
247
249
|
}, async (input, extra) => {
|
|
248
250
|
const workspaceId = await resolveServerWorkspaceId(engine, context, input.workspaceId, extra.signal);
|
|
251
|
+
const releaseCaches = cacheLifetime.begin();
|
|
249
252
|
try {
|
|
250
253
|
const progress = progressReporter(extra);
|
|
251
254
|
await progress.report(0, 2, 'Analyzing technologies');
|
|
@@ -266,6 +269,9 @@ export function registerTechnologyTools(server, engine, context) {
|
|
|
266
269
|
catch (error) {
|
|
267
270
|
return errorResult(error, workspaceId);
|
|
268
271
|
}
|
|
272
|
+
finally {
|
|
273
|
+
releaseCaches();
|
|
274
|
+
}
|
|
269
275
|
});
|
|
270
276
|
server.registerTool('hoi4.tech_render', {
|
|
271
277
|
title: 'Render technology trees',
|
|
@@ -275,6 +281,7 @@ export function registerTechnologyTools(server, engine, context) {
|
|
|
275
281
|
annotations: readOnly,
|
|
276
282
|
}, async (input, extra) => {
|
|
277
283
|
const workspaceId = await resolveServerWorkspaceId(engine, context, input.workspaceId, extra.signal);
|
|
284
|
+
const releaseCaches = cacheLifetime.begin();
|
|
278
285
|
try {
|
|
279
286
|
const progress = progressReporter(extra);
|
|
280
287
|
const request = {
|
|
@@ -310,6 +317,9 @@ export function registerTechnologyTools(server, engine, context) {
|
|
|
310
317
|
catch (error) {
|
|
311
318
|
return errorResult(error, workspaceId);
|
|
312
319
|
}
|
|
320
|
+
finally {
|
|
321
|
+
releaseCaches();
|
|
322
|
+
}
|
|
313
323
|
});
|
|
314
324
|
server.registerTool('hoi4.tech_compare', {
|
|
315
325
|
title: 'Compare technology trees',
|
|
@@ -319,6 +329,7 @@ export function registerTechnologyTools(server, engine, context) {
|
|
|
319
329
|
annotations: readOnly,
|
|
320
330
|
}, async (input, extra) => {
|
|
321
331
|
const workspaceId = await resolveServerWorkspaceId(engine, context, input.workspaceId, extra.signal);
|
|
332
|
+
const releaseCaches = cacheLifetime.begin();
|
|
322
333
|
try {
|
|
323
334
|
const progress = progressReporter(extra);
|
|
324
335
|
const request = {
|
|
@@ -368,5 +379,8 @@ export function registerTechnologyTools(server, engine, context) {
|
|
|
368
379
|
catch (error) {
|
|
369
380
|
return errorResult(error, workspaceId);
|
|
370
381
|
}
|
|
382
|
+
finally {
|
|
383
|
+
releaseCaches();
|
|
384
|
+
}
|
|
371
385
|
});
|
|
372
386
|
}
|
|
@@ -99,6 +99,19 @@ export class BoundedStdioServerTransport {
|
|
|
99
99
|
handleInputError = (error) => {
|
|
100
100
|
this.onerror(error);
|
|
101
101
|
};
|
|
102
|
+
handleInputEnd = () => {
|
|
103
|
+
this.finish();
|
|
104
|
+
};
|
|
105
|
+
handleInputClose = () => {
|
|
106
|
+
this.finish();
|
|
107
|
+
};
|
|
108
|
+
handleOutputError = (error) => {
|
|
109
|
+
this.onerror(error);
|
|
110
|
+
this.finish(true);
|
|
111
|
+
};
|
|
112
|
+
handleOutputClose = () => {
|
|
113
|
+
this.finish(true);
|
|
114
|
+
};
|
|
102
115
|
processCompleteFrame() {
|
|
103
116
|
let line;
|
|
104
117
|
try {
|
|
@@ -134,6 +147,10 @@ export class BoundedStdioServerTransport {
|
|
|
134
147
|
this.closed = true;
|
|
135
148
|
this.input.off('data', this.handleData);
|
|
136
149
|
this.input.off('error', this.handleInputError);
|
|
150
|
+
this.input.off('end', this.handleInputEnd);
|
|
151
|
+
this.input.off('close', this.handleInputClose);
|
|
152
|
+
this.output.off('error', this.handleOutputError);
|
|
153
|
+
this.output.off('close', this.handleOutputClose);
|
|
137
154
|
if (destroyInput)
|
|
138
155
|
this.input.destroy();
|
|
139
156
|
else if (this.input.listenerCount('data') === 0)
|
|
@@ -147,6 +164,10 @@ export class BoundedStdioServerTransport {
|
|
|
147
164
|
this.started = true;
|
|
148
165
|
this.input.on('data', this.handleData);
|
|
149
166
|
this.input.on('error', this.handleInputError);
|
|
167
|
+
this.input.once('end', this.handleInputEnd);
|
|
168
|
+
this.input.once('close', this.handleInputClose);
|
|
169
|
+
this.output.on('error', this.handleOutputError);
|
|
170
|
+
this.output.once('close', this.handleOutputClose);
|
|
150
171
|
return Promise.resolve();
|
|
151
172
|
}
|
|
152
173
|
close() {
|
|
@@ -17,6 +17,7 @@ import { Rational } from './rational.js';
|
|
|
17
17
|
import { discoverWeightedSurface, inventoryWeightedSurfaces, } from './source-analysis.js';
|
|
18
18
|
import { sweepSurface } from './sweep.js';
|
|
19
19
|
const states = new WeakMap();
|
|
20
|
+
const ANALYSIS_CACHE_ENTRIES = 16;
|
|
20
21
|
function resolveSourceBackedAdapter(snapshot, source, candidatePool, requested) {
|
|
21
22
|
if (requested !== undefined && requested !== 'custom_weighted_pool') {
|
|
22
23
|
try {
|
|
@@ -62,6 +63,23 @@ function analyzerState(engine) {
|
|
|
62
63
|
}
|
|
63
64
|
return state;
|
|
64
65
|
}
|
|
66
|
+
function rememberAnalysis(state, result) {
|
|
67
|
+
const replacedByCacheKey = state.byCacheKey.get(result.metadata.cacheKey);
|
|
68
|
+
if (replacedByCacheKey !== undefined)
|
|
69
|
+
state.byId.delete(replacedByCacheKey.analysisId);
|
|
70
|
+
state.byId.delete(result.analysisId);
|
|
71
|
+
state.byCacheKey.delete(result.metadata.cacheKey);
|
|
72
|
+
state.byId.set(result.analysisId, result);
|
|
73
|
+
state.byCacheKey.set(result.metadata.cacheKey, result);
|
|
74
|
+
while (state.byId.size > ANALYSIS_CACHE_ENTRIES) {
|
|
75
|
+
const oldest = state.byId.entries().next().value;
|
|
76
|
+
if (oldest === undefined)
|
|
77
|
+
break;
|
|
78
|
+
state.byId.delete(oldest[0]);
|
|
79
|
+
if (state.byCacheKey.get(oldest[1].metadata.cacheKey) === oldest[1])
|
|
80
|
+
state.byCacheKey.delete(oldest[1].metadata.cacheKey);
|
|
81
|
+
}
|
|
82
|
+
}
|
|
65
83
|
const DEFAULT_DIAGNOSTIC_THRESHOLDS = {
|
|
66
84
|
dominantProbability: 0.9,
|
|
67
85
|
dominantScenarioPrevalence: 0.8,
|
|
@@ -686,6 +704,12 @@ export class ProbabilityAnalyzer {
|
|
|
686
704
|
this.engine = engine;
|
|
687
705
|
this.state = analyzerState(engine);
|
|
688
706
|
}
|
|
707
|
+
/** Release source snapshots and analysis results after an idle MCP batch. */
|
|
708
|
+
clearCaches() {
|
|
709
|
+
this.state.byId.clear();
|
|
710
|
+
this.state.byCacheKey.clear();
|
|
711
|
+
this.engine.releaseScanCaches();
|
|
712
|
+
}
|
|
689
713
|
async scan(context, sourcePaths = [], emptyScope = 'domain') {
|
|
690
714
|
if (context.refresh === true)
|
|
691
715
|
this.engine.invalidate(context.workspaceId);
|
|
@@ -880,8 +904,7 @@ export class ProbabilityAnalyzer {
|
|
|
880
904
|
const stored = await this.engine.artifacts.withAtomicChunkedWrites(workspace, writes, (artifacts) => Promise.resolve([...artifacts]), signal);
|
|
881
905
|
const complete = { ...result, resources: stored.map(publicArtifactLink) };
|
|
882
906
|
if (complete.operation !== 'render') {
|
|
883
|
-
this.state
|
|
884
|
-
this.state.byCacheKey.set(complete.metadata.cacheKey, complete);
|
|
907
|
+
rememberAnalysis(this.state, complete);
|
|
885
908
|
}
|
|
886
909
|
return complete;
|
|
887
910
|
}
|
|
@@ -19,7 +19,7 @@ const PROPOSED_SOURCE_FILES = 128;
|
|
|
19
19
|
const PROPOSED_SOURCE_BYTES = 67_108_864;
|
|
20
20
|
const GRAPH_ARTIFACT_BYTES = 134_217_728;
|
|
21
21
|
const GRAPH_ARTIFACT_CHUNKS = 2_048;
|
|
22
|
-
const HISTORY_ENTRIES =
|
|
22
|
+
const HISTORY_ENTRIES = 2;
|
|
23
23
|
const FOCUSED_RENDER_LIMIT = 32;
|
|
24
24
|
class BoundedTechnologyFragmentCache {
|
|
25
25
|
#values = new Map();
|
|
@@ -47,6 +47,10 @@ class BoundedTechnologyFragmentCache {
|
|
|
47
47
|
this.#bytes -= oldest[1].bytes;
|
|
48
48
|
}
|
|
49
49
|
}
|
|
50
|
+
clear() {
|
|
51
|
+
this.#values.clear();
|
|
52
|
+
this.#bytes = 0;
|
|
53
|
+
}
|
|
50
54
|
}
|
|
51
55
|
const sharedTechnologyStates = new WeakMap();
|
|
52
56
|
function sharedState(engine) {
|
|
@@ -429,6 +433,13 @@ export class TechnologyTreeViewer {
|
|
|
429
433
|
this.engine = engine;
|
|
430
434
|
this.#state = sharedState(engine);
|
|
431
435
|
}
|
|
436
|
+
/** Release full source graphs retained between adjacent MCP calls. */
|
|
437
|
+
clearCaches() {
|
|
438
|
+
this.#state.current.clear();
|
|
439
|
+
this.#state.history.clear();
|
|
440
|
+
this.#state.fragments.clear();
|
|
441
|
+
this.engine.releaseScanCaches();
|
|
442
|
+
}
|
|
432
443
|
async scan(workspaceId, options = {}) {
|
|
433
444
|
options.signal?.throwIfAborted();
|
|
434
445
|
const workspace = this.engine.resolver.get(workspaceId, options.principal);
|
|
@@ -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 = '3.0.
|
|
3
|
+
export const PACKAGE_VERSION = '3.0.6';
|
|
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
|
@@ -35,7 +35,7 @@ The renderer resolves sprites and fonts through the complete mod, dependency, an
|
|
|
35
35
|
|
|
36
36
|
Bitmap text uses the language-appropriate HOI4 font definition and its real glyph atlas. Header, serif, compact, typewriter, black, inverted, and other declared faces keep their own glyph shapes, native metrics, face colour, border colour, language override, and font-specific `textcolors` palette. The renderer reads BMFont channel roles, separates face and outline coverage, and recognizes both vanilla black-on-white masks and conventional white-on-transparent custom masks. HOI4 localisation colour runs such as `§Y` and `§R` therefore colour the glyph face while retaining its sharp antialiasing and declared border instead of flattening the glyph into a blurred monochrome mask or switching to the tool font. The default language uses the base font rather than an unrelated language override, and the renderer recognizes installed-game atlases whose filename omits a page suffix declared by the matching `.fnt` file.
|
|
37
37
|
|
|
38
|
-
`uiScale` is the in-game UI scale, not an image zoom. Use `1` for the normal 1920×1080 layout. Bitmap-font glyphs come directly from the real atlas without a sharpening, threshold, or reconstructed-edge pass.
|
|
38
|
+
`uiScale` is the in-game UI scale, not an image zoom. Use `1` for the normal 1920×1080 layout. 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.
|
|
39
39
|
|
|
40
40
|
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.
|
|
41
41
|
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
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": "3.0.
|
|
4
|
+
"version": "3.0.6",
|
|
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/v3.0.
|
|
2
|
+
"$id": "https://github.com/klimPaskov/hoi4-agent-tools/blob/v3.0.6/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/v3.0.
|
|
2
|
+
"$id": "https://github.com/klimPaskov/hoi4-agent-tools/blob/v3.0.6/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/v3.0.
|
|
2
|
+
"$id": "https://github.com/klimPaskov/hoi4-agent-tools/blob/v3.0.6/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/v3.0.
|
|
2
|
+
"$id": "https://github.com/klimPaskov/hoi4-agent-tools/blob/v3.0.6/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/v3.0.
|
|
2
|
+
"$id": "https://github.com/klimPaskov/hoi4-agent-tools/blob/v3.0.6/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/v3.0.
|
|
2
|
+
"$id": "https://github.com/klimPaskov/hoi4-agent-tools/blob/v3.0.6/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/v3.0.
|
|
2
|
+
"$id": "https://github.com/klimPaskov/hoi4-agent-tools/blob/v3.0.6/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/v3.0.
|
|
2
|
+
"$id": "https://github.com/klimPaskov/hoi4-agent-tools/blob/v3.0.6/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/v3.0.
|
|
2
|
+
"$id": "https://github.com/klimPaskov/hoi4-agent-tools/blob/v3.0.6/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/v3.0.
|
|
2
|
+
"$id": "https://github.com/klimPaskov/hoi4-agent-tools/blob/v3.0.6/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/v3.0.
|
|
2
|
+
"$id": "https://github.com/klimPaskov/hoi4-agent-tools/blob/v3.0.6/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/v3.0.
|
|
2
|
+
"$id": "https://github.com/klimPaskov/hoi4-agent-tools/blob/v3.0.6/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/v3.0.
|
|
2
|
+
"$id": "https://github.com/klimPaskov/hoi4-agent-tools/blob/v3.0.6/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/v3.0.
|
|
2
|
+
"$id": "https://github.com/klimPaskov/hoi4-agent-tools/blob/v3.0.6/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/v3.0.
|
|
2
|
+
"$id": "https://github.com/klimPaskov/hoi4-agent-tools/blob/v3.0.6/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/v3.0.
|
|
2
|
+
"$id": "https://github.com/klimPaskov/hoi4-agent-tools/blob/v3.0.6/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/v3.0.
|
|
2
|
+
"$id": "https://github.com/klimPaskov/hoi4-agent-tools/blob/v3.0.6/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/v3.0.
|
|
2
|
+
"$id": "https://github.com/klimPaskov/hoi4-agent-tools/blob/v3.0.6/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/v3.0.
|
|
2
|
+
"$id": "https://github.com/klimPaskov/hoi4-agent-tools/blob/v3.0.6/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/v3.0.
|
|
2
|
+
"$id": "https://github.com/klimPaskov/hoi4-agent-tools/blob/v3.0.6/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": "3.0.
|
|
6
|
+
"version": "3.0.6",
|
|
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": "3.0.
|
|
16
|
+
"version": "3.0.6",
|
|
17
17
|
"transport": {
|
|
18
18
|
"type": "stdio"
|
|
19
19
|
}
|