hoi4-agent-tools 3.0.9 → 3.2.0
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 +32 -1
- package/README.md +10 -2
- package/dist/bin/stdio.js +23 -12
- package/dist/hoi4_agent_tools/core/analysis-checkpoints.js +82 -0
- package/dist/hoi4_agent_tools/core/analysis-evidence.js +9 -0
- package/dist/hoi4_agent_tools/core/analysis-job-operations.js +38 -0
- package/dist/hoi4_agent_tools/core/artifact-resource.js +173 -0
- package/dist/hoi4_agent_tools/core/artifacts.js +84 -2
- package/dist/hoi4_agent_tools/core/condition-evaluator.js +16 -0
- package/dist/hoi4_agent_tools/core/dependency-pages.js +216 -0
- package/dist/hoi4_agent_tools/core/dependency-walk.js +266 -0
- package/dist/hoi4_agent_tools/core/domain-validation.js +188 -0
- package/dist/hoi4_agent_tools/core/engine.js +48 -5
- package/dist/hoi4_agent_tools/core/helper-expansion.js +186 -0
- package/dist/hoi4_agent_tools/core/impact-comparison.js +49 -0
- package/dist/hoi4_agent_tools/core/impact-graph.js +301 -0
- package/dist/hoi4_agent_tools/core/impact-semantic.js +256 -0
- package/dist/hoi4_agent_tools/core/index-segments.js +137 -0
- package/dist/hoi4_agent_tools/core/index.js +47 -4
- package/dist/hoi4_agent_tools/core/job-controls.js +109 -0
- package/dist/hoi4_agent_tools/core/job-executor.js +190 -0
- package/dist/hoi4_agent_tools/core/job-service.js +112 -0
- package/dist/hoi4_agent_tools/core/job-store.js +641 -0
- package/dist/hoi4_agent_tools/core/job-transactions.js +126 -0
- package/dist/hoi4_agent_tools/core/job-worker-host.js +202 -0
- package/dist/hoi4_agent_tools/core/job-worker.js +64 -0
- package/dist/hoi4_agent_tools/core/operation-context.js +31 -0
- package/dist/hoi4_agent_tools/core/operation-result.js +412 -0
- package/dist/hoi4_agent_tools/core/operation-tasks.js +387 -0
- package/dist/hoi4_agent_tools/core/persistent-analysis-cache.js +383 -0
- package/dist/hoi4_agent_tools/core/result.js +1 -0
- package/dist/hoi4_agent_tools/core/scanner.js +15 -75
- package/dist/hoi4_agent_tools/core/semantic-dependencies.js +233 -0
- package/dist/hoi4_agent_tools/core/shared-request-capacity.js +43 -11
- package/dist/hoi4_agent_tools/core/source/cache.js +107 -0
- package/dist/hoi4_agent_tools/core/source/parser.js +11 -1
- package/dist/hoi4_agent_tools/core/source-overlay.js +125 -0
- package/dist/hoi4_agent_tools/core/transaction-execution.js +134 -0
- package/dist/hoi4_agent_tools/core/transactions.js +80 -27
- package/dist/hoi4_agent_tools/decision/ai.js +104 -0
- package/dist/hoi4_agent_tools/decision/comparison.js +106 -0
- package/dist/hoi4_agent_tools/decision/cost.js +177 -0
- package/dist/hoi4_agent_tools/decision/evaluation.js +256 -0
- package/dist/hoi4_agent_tools/decision/lifecycle.js +114 -0
- package/dist/hoi4_agent_tools/decision/service.js +172 -0
- package/dist/hoi4_agent_tools/decision/source-inventory.js +182 -0
- package/dist/hoi4_agent_tools/event/graph.js +214 -290
- package/dist/hoi4_agent_tools/event/helper-expansion.js +33 -0
- package/dist/hoi4_agent_tools/event/job-operations.js +51 -0
- package/dist/hoi4_agent_tools/event/operations.js +179 -0
- package/dist/hoi4_agent_tools/event/service.js +67 -15
- package/dist/hoi4_agent_tools/event/source-analysis.js +5 -4
- package/dist/hoi4_agent_tools/focus/job-operations.js +77 -0
- package/dist/hoi4_agent_tools/focus/tool-operations.js +669 -0
- package/dist/hoi4_agent_tools/focus/tool-support.js +123 -0
- package/dist/hoi4_agent_tools/gui/job-operations.js +81 -0
- package/dist/hoi4_agent_tools/gui/tool-operations.js +270 -0
- package/dist/hoi4_agent_tools/impact/scenario-suites.js +74 -0
- package/dist/hoi4_agent_tools/impact/service.js +127 -0
- package/dist/hoi4_agent_tools/map/job-operations.js +76 -0
- package/dist/hoi4_agent_tools/map/tool-operations.js +493 -0
- package/dist/hoi4_agent_tools/mcp/prompts/probability.js +25 -0
- package/dist/hoi4_agent_tools/mcp/prompts/register-modern.js +29 -0
- package/dist/hoi4_agent_tools/mcp/resources/register-modern.js +34 -0
- package/dist/hoi4_agent_tools/mcp/resources/register.js +4 -150
- package/dist/hoi4_agent_tools/mcp/server/base-tools.js +3 -219
- package/dist/hoi4_agent_tools/mcp/server/create-modern-operations.js +188 -0
- package/dist/hoi4_agent_tools/mcp/server/create.js +18 -6
- package/dist/hoi4_agent_tools/mcp/server/instructions.js +2 -0
- package/dist/hoi4_agent_tools/mcp/server/job-task-store.js +67 -0
- package/dist/hoi4_agent_tools/mcp/server/legacy-task-tools.js +20 -0
- package/dist/hoi4_agent_tools/mcp/server/modern-tasks.js +168 -0
- package/dist/hoi4_agent_tools/mcp/server/progress.js +17 -15
- package/dist/hoi4_agent_tools/mcp/server/request-lifecycle.js +45 -0
- package/dist/hoi4_agent_tools/mcp/server/result.js +2 -412
- package/dist/hoi4_agent_tools/mcp/server/task-request-context.js +9 -0
- package/dist/hoi4_agent_tools/mcp/server/task-tool-catalog.js +16 -0
- package/dist/hoi4_agent_tools/mcp/server/task-tool-definition.js +1 -0
- package/dist/hoi4_agent_tools/mcp/server/transaction-execution.js +1 -123
- package/dist/hoi4_agent_tools/mcp/tools/analysis.js +65 -0
- package/dist/hoi4_agent_tools/mcp/tools/chaosx.js +38 -21
- package/dist/hoi4_agent_tools/mcp/tools/event.js +24 -315
- package/dist/hoi4_agent_tools/mcp/tools/focus.js +34 -1039
- package/dist/hoi4_agent_tools/mcp/tools/gui.js +19 -504
- package/dist/hoi4_agent_tools/mcp/tools/job.js +46 -0
- package/dist/hoi4_agent_tools/mcp/tools/map.js +21 -600
- package/dist/hoi4_agent_tools/mcp/tools/probability.js +39 -463
- package/dist/hoi4_agent_tools/mcp/tools/technology.js +40 -304
- package/dist/hoi4_agent_tools/mcp/transports/http.js +58 -1
- package/dist/hoi4_agent_tools/mcp/transports/modern-task-routing.js +109 -0
- package/dist/hoi4_agent_tools/mcp/transports/negotiated-stdio.js +121 -0
- package/dist/hoi4_agent_tools/probability/job-operations.js +58 -0
- package/dist/hoi4_agent_tools/probability/operations.js +183 -0
- package/dist/hoi4_agent_tools/probability/service.js +24 -3
- package/dist/hoi4_agent_tools/schemas/analysis.js +228 -0
- package/dist/hoi4_agent_tools/schemas/common.js +2 -0
- package/dist/hoi4_agent_tools/schemas/event.js +72 -1
- package/dist/hoi4_agent_tools/schemas/focus-requests.js +189 -0
- package/dist/hoi4_agent_tools/schemas/gui-requests.js +193 -0
- package/dist/hoi4_agent_tools/schemas/helper-expansion.js +58 -0
- package/dist/hoi4_agent_tools/schemas/map-requests.js +85 -0
- package/dist/hoi4_agent_tools/schemas/probability-requests.js +168 -0
- package/dist/hoi4_agent_tools/schemas/technology.js +90 -1
- package/dist/hoi4_agent_tools/schemas/transaction.js +1 -0
- package/dist/hoi4_agent_tools/technology/graph.js +83 -78
- package/dist/hoi4_agent_tools/technology/helper-expansion.js +33 -0
- package/dist/hoi4_agent_tools/technology/job-operations.js +60 -0
- package/dist/hoi4_agent_tools/technology/operations.js +125 -0
- package/dist/hoi4_agent_tools/technology/service.js +89 -15
- package/dist/hoi4_agent_tools/technology/source-analysis.js +2 -1
- package/dist/hoi4_agent_tools/version.js +1 -1
- package/docs/README.md +3 -0
- package/docs/analysis.md +100 -0
- package/docs/development.md +2 -0
- package/docs/events.md +7 -2
- package/docs/helper-expansion.md +78 -0
- package/docs/http.md +2 -0
- package/docs/jobs.md +86 -0
- package/docs/technology.md +6 -2
- package/package.json +15 -6
- 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/decision-inspect-input.schema.json +290 -0
- 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/helper-expansion-request.schema.json +44 -0
- package/schemas/helper-expansion-summary.schema.json +70 -0
- package/schemas/impact-inspect-input.schema.json +203 -0
- 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 +3 -3
|
@@ -1,20 +1,8 @@
|
|
|
1
|
+
import { registerLegacyTaskTools } from '../server/legacy-task-tools.js';
|
|
1
2
|
import { z } from 'zod/v4';
|
|
2
|
-
import {
|
|
3
|
-
import { canonicalJson, compareCodeUnits, hashCanonical } from '../../core/canonical.js';
|
|
4
|
-
import { IdleCacheLifetime } from '../../core/idle-cache-lifetime.js';
|
|
5
|
-
import { renderDimensionViolation, RenderBudget, RENDER_MAX_DIMENSION, } from '../../core/render-budget.js';
|
|
6
|
-
import { emptyServiceResult, ServiceError } from '../../core/result.js';
|
|
7
|
-
import { SOURCE_MAX_BYTES } from '../../core/source/index.js';
|
|
8
|
-
import { GuiHelperDocumentSchema, GuiGeneratedScenarioOptionsSchema, GuiPreviewScenarioSchema, GUI_TEXT_PACKAGE_MAX_FILES, ScriptedGuiStudio, compileGuiHelpers, } from '../../gui/index.js';
|
|
9
|
-
import { encodeGuiInspectionArtifact, projectGuiGraphForArtifact, } from '../../gui/inspection-artifact.js';
|
|
10
|
-
import { workspaceIdSchema, workspaceRelativePathSchema } from '../../schemas/common.js';
|
|
11
|
-
import { PACKAGE_VERSION } from '../../version.js';
|
|
12
|
-
import { requireServerScope, resolveServerWorkspaceId, } from '../server/base-tools.js';
|
|
13
|
-
import { compactValidatedInputSchema } from '../server/context-schemas.js';
|
|
14
|
-
import { autonomousFailureContext, autonomousResultArtifacts, executePlannedTransaction, } from '../server/transaction-execution.js';
|
|
3
|
+
import { guiInspectRequestSchema, guiRenderRequestSchema, guiRewriteRequestSchema, } from '../../schemas/gui-requests.js';
|
|
15
4
|
import { indexSkippedSourceSchema, nonNegativeIntegerSchema, sha256Schema, } from '../server/output-schemas.js';
|
|
16
|
-
import {
|
|
17
|
-
import { errorResult, setInlineFilesScanned, strictOperationResultSchema, toolResult, } from '../server/result.js';
|
|
5
|
+
import { strictOperationResultSchema } from '../server/result.js';
|
|
18
6
|
const countRecordSchema = z.record(z.string().max(256), nonNegativeIntegerSchema);
|
|
19
7
|
const guiScanOutputSchema = strictOperationResultSchema(z
|
|
20
8
|
.object({
|
|
@@ -76,418 +64,28 @@ const artifactProducing = {
|
|
|
76
64
|
idempotentHint: true,
|
|
77
65
|
openWorldHint: false,
|
|
78
66
|
};
|
|
79
|
-
const
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
'selected',
|
|
83
|
-
'locked',
|
|
84
|
-
'disabled',
|
|
85
|
-
'warning',
|
|
86
|
-
'active',
|
|
87
|
-
'completed',
|
|
88
|
-
'empty-list',
|
|
89
|
-
'full-list',
|
|
90
|
-
'minimum-value',
|
|
91
|
-
'maximum-value',
|
|
92
|
-
'long-text',
|
|
93
|
-
'missing-localisation',
|
|
94
|
-
]);
|
|
95
|
-
const compactGuiScenarioSchema = compactValidatedInputSchema(GuiPreviewScenarioSchema, `GUI preview scenario: https://github.com/klimPaskov/hoi4-agent-tools/blob/v${PACKAGE_VERSION}/docs/gui.md`);
|
|
96
|
-
const compactGeneratedScenarioOptionsSchema = compactValidatedInputSchema(GuiGeneratedScenarioOptionsSchema, `Options: https://github.com/klimPaskov/hoi4-agent-tools/blob/v${PACKAGE_VERSION}/docs/gui.md`);
|
|
97
|
-
const compactGuiHelperSchema = compactValidatedInputSchema(GuiHelperDocumentSchema, `GUI helper document: https://github.com/klimPaskov/hoi4-agent-tools/blob/v${PACKAGE_VERSION}/docs/gui.md`);
|
|
98
|
-
const guiBaseInput = z
|
|
99
|
-
.object({
|
|
100
|
-
workspaceId: workspaceIdSchema,
|
|
101
|
-
windowName: z.string().min(1).max(256),
|
|
102
|
-
scenario: compactGuiScenarioSchema,
|
|
103
|
-
})
|
|
104
|
-
.strict();
|
|
105
|
-
const guiInspectInput = z
|
|
106
|
-
.object({
|
|
107
|
-
workspaceId: workspaceIdSchema,
|
|
108
|
-
windowName: z.string().min(1).max(256).optional(),
|
|
109
|
-
scenario: compactGuiScenarioSchema.optional(),
|
|
110
|
-
relatedScenarios: z.array(compactGuiScenarioSchema).max(32).optional(),
|
|
111
|
-
generatedScenarios: compactGeneratedScenarioOptionsSchema.optional(),
|
|
112
|
-
})
|
|
113
|
-
.strict()
|
|
114
|
-
.superRefine((value, context) => {
|
|
115
|
-
if ((value.windowName === undefined) !== (value.scenario === undefined)) {
|
|
116
|
-
context.addIssue({
|
|
117
|
-
code: 'custom',
|
|
118
|
-
message: 'windowName and scenario must be provided together',
|
|
119
|
-
});
|
|
120
|
-
}
|
|
121
|
-
if (value.relatedScenarios !== undefined && value.scenario === undefined) {
|
|
122
|
-
context.addIssue({
|
|
123
|
-
code: 'custom',
|
|
124
|
-
path: ['relatedScenarios'],
|
|
125
|
-
message: 'relatedScenarios requires a window scenario',
|
|
126
|
-
});
|
|
127
|
-
}
|
|
128
|
-
if (value.generatedScenarios !== undefined && value.scenario === undefined) {
|
|
129
|
-
context.addIssue({
|
|
130
|
-
code: 'custom',
|
|
131
|
-
path: ['generatedScenarios'],
|
|
132
|
-
message: 'generatedScenarios requires a window scenario',
|
|
133
|
-
});
|
|
134
|
-
}
|
|
135
|
-
});
|
|
136
|
-
const resolutionSchema = z
|
|
137
|
-
.object({
|
|
138
|
-
width: z.number().int().min(320).max(RENDER_MAX_DIMENSION),
|
|
139
|
-
height: z.number().int().min(200).max(RENDER_MAX_DIMENSION),
|
|
140
|
-
uiScale: z
|
|
141
|
-
.number()
|
|
142
|
-
.min(0.25)
|
|
143
|
-
.max(4)
|
|
144
|
-
.optional()
|
|
145
|
-
.describe('In-game UI scale for this resolution. Use 1 at 1920x1080; do not use it to enlarge an artifact.'),
|
|
146
|
-
})
|
|
147
|
-
.strict()
|
|
148
|
-
.superRefine(({ width, height }, context) => {
|
|
149
|
-
const violation = renderDimensionViolation(width, height, 'GUI matrix resolution');
|
|
150
|
-
if (violation !== undefined) {
|
|
151
|
-
context.addIssue({ code: 'custom', message: `${violation.code}: ${violation.message}` });
|
|
152
|
-
}
|
|
153
|
-
});
|
|
154
|
-
function validationSummary(validation) {
|
|
155
|
-
return {
|
|
156
|
-
passed: validation.checks.every(({ passed }) => passed) &&
|
|
157
|
-
!validation.diagnostics.some(({ severity }) => severity === 'error' || severity === 'blocker'),
|
|
158
|
-
checks: validation.checks,
|
|
159
|
-
};
|
|
160
|
-
}
|
|
161
|
-
export function registerGuiTools(server, engine, context) {
|
|
162
|
-
const studio = new ScriptedGuiStudio(engine);
|
|
163
|
-
const cacheLifetime = new IdleCacheLifetime(() => studio.clearCaches());
|
|
164
|
-
server.registerTool('hoi4.gui_inspect', {
|
|
67
|
+
export const guiTaskTools = [
|
|
68
|
+
{
|
|
69
|
+
name: 'hoi4.gui_inspect',
|
|
165
70
|
title: 'Inspect scripted GUI',
|
|
166
71
|
description: 'Inspect GUI sources and scenarios.',
|
|
167
|
-
inputSchema:
|
|
72
|
+
inputSchema: guiInspectRequestSchema,
|
|
168
73
|
outputSchema: guiScanOutputSchema,
|
|
169
74
|
annotations: artifactProducing,
|
|
170
|
-
},
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
try {
|
|
174
|
-
const progress = progressReporter(extra);
|
|
175
|
-
await progress.report(0, 3, 'Building GUI source graph');
|
|
176
|
-
const inspected = await withProgressHeartbeat(async () => {
|
|
177
|
-
if (windowName === undefined || scenario === undefined) {
|
|
178
|
-
const { graph } = await studio.scan(workspaceId, context.principal, progress.signal);
|
|
179
|
-
return { graph, linted: undefined };
|
|
180
|
-
}
|
|
181
|
-
const linted = await studio.lint({
|
|
182
|
-
workspaceId,
|
|
183
|
-
windowName,
|
|
184
|
-
scenario,
|
|
185
|
-
...(relatedScenarios === undefined ? {} : { relatedScenarios }),
|
|
186
|
-
generatedScenarios: generatedScenarios ?? {},
|
|
187
|
-
...(context.principal === undefined ? {} : { principal: context.principal }),
|
|
188
|
-
signal: progress.signal,
|
|
189
|
-
});
|
|
190
|
-
return { graph: linted.graph, linted };
|
|
191
|
-
}, progress, 'Inspecting GUI sources and linked assets');
|
|
192
|
-
const { graph, linted } = inspected;
|
|
193
|
-
const sharedRevision = hashCanonical(graph.sourceHashes);
|
|
194
|
-
const workspace = engine.resolver.get(workspaceId, context.principal);
|
|
195
|
-
const sourceEvidence = boundedSourceHashEvidence(graph.sourceHashes);
|
|
196
|
-
const artifactGraph = projectGuiGraphForArtifact(graph, linted?.scene.elements.map(({ sourceId }) => sourceId));
|
|
197
|
-
const inspectionName = `gui-inspect.${sharedRevision.slice(0, 16)}.json`;
|
|
198
|
-
const inspectionJson = `${canonicalJson({
|
|
199
|
-
schemaVersion: 1,
|
|
200
|
-
sharedRevision,
|
|
201
|
-
offline: true,
|
|
202
|
-
graph: artifactGraph.graph,
|
|
203
|
-
...(artifactGraph.projection === undefined
|
|
204
|
-
? {}
|
|
205
|
-
: { graphProjection: artifactGraph.projection }),
|
|
206
|
-
...(linted === undefined
|
|
207
|
-
? {}
|
|
208
|
-
: {
|
|
209
|
-
scenario: linted.scene.scenario,
|
|
210
|
-
fidelity: linted.scene.fidelity,
|
|
211
|
-
validation: linted.validation,
|
|
212
|
-
}),
|
|
213
|
-
})}\n`;
|
|
214
|
-
const encodedInspection = await encodeGuiInspectionArtifact(inspectionName, inspectionJson);
|
|
215
|
-
const artifact = await engine.artifacts.putChunked(workspace, encodedInspection.name, encodedInspection.mimeType, encodedInspection.content, {
|
|
216
|
-
kind: 'gui-inspect',
|
|
217
|
-
toolVersion: PACKAGE_VERSION,
|
|
218
|
-
schemaVersion: 'gui-inspect.v1',
|
|
219
|
-
sourceHashes: sourceEvidence.sourceHashes,
|
|
220
|
-
metadata: {
|
|
221
|
-
sharedRevision,
|
|
222
|
-
offline: true,
|
|
223
|
-
complete: graph.complete,
|
|
224
|
-
skippedSourceCount: graph.skippedSourceCount,
|
|
225
|
-
sourceHashInventory: sourceEvidence.inventory,
|
|
226
|
-
compressed: encodedInspection.compressed,
|
|
227
|
-
uncompressedBytes: encodedInspection.uncompressedBytes,
|
|
228
|
-
graphProjection: artifactGraph.projection?.mode ?? 'full',
|
|
229
|
-
},
|
|
230
|
-
}, encodedInspection.compressed
|
|
231
|
-
? 'Gzip-compressed scripted GUI graph, diagnostics, and optional scenario fidelity inspection'
|
|
232
|
-
: 'Scripted GUI graph, diagnostics, and optional scenario fidelity inspection', progress.signal);
|
|
233
|
-
const diagnostics = linted === undefined ? graph.diagnostics : linted.validation.diagnostics;
|
|
234
|
-
const result = emptyServiceResult(workspaceId, {
|
|
235
|
-
sharedRevision,
|
|
236
|
-
complete: graph.complete,
|
|
237
|
-
skippedSourceCount: graph.skippedSourceCount,
|
|
238
|
-
skippedSources: graph.skippedSources,
|
|
239
|
-
nodes: graph.nodes.length,
|
|
240
|
-
edges: graph.edges.length,
|
|
241
|
-
elements: graph.elements.length,
|
|
242
|
-
sprites: graph.sprites.length,
|
|
243
|
-
fonts: graph.fonts.length,
|
|
244
|
-
scriptedGuis: graph.scriptedGuis.length,
|
|
245
|
-
...(linted === undefined
|
|
246
|
-
? {}
|
|
247
|
-
: {
|
|
248
|
-
windowName,
|
|
249
|
-
scenarioId: linted.scene.scenario.id,
|
|
250
|
-
inspectedElementCount: linted.scene.elements.length,
|
|
251
|
-
fidelityCounts: Object.fromEntries(Object.entries(linted.scene.fidelity).map(([key, values]) => [
|
|
252
|
-
key,
|
|
253
|
-
values.length,
|
|
254
|
-
])),
|
|
255
|
-
}),
|
|
256
|
-
});
|
|
257
|
-
result.code = graph.complete ? 'GUI_INSPECTED' : 'GUI_INSPECTED_PARTIAL';
|
|
258
|
-
setInlineFilesScanned(result, graph.filesScanned);
|
|
259
|
-
result.diagnostics = diagnostics.slice(0, 100);
|
|
260
|
-
result.artifacts = [publicArtifactLink(artifact)];
|
|
261
|
-
result.validation =
|
|
262
|
-
linted === undefined
|
|
263
|
-
? {
|
|
264
|
-
passed: !diagnostics.some(({ severity }) => severity === 'error' || severity === 'blocker'),
|
|
265
|
-
checks: [
|
|
266
|
-
{
|
|
267
|
-
id: 'gui-inspection',
|
|
268
|
-
passed: true,
|
|
269
|
-
message: graph.complete
|
|
270
|
-
? `${graph.nodes.length} GUI graph nodes connected from a complete inventory`
|
|
271
|
-
: `${graph.nodes.length} GUI graph nodes connected; ${graph.skippedSourceCount} over-limit source(s) were skipped`,
|
|
272
|
-
},
|
|
273
|
-
],
|
|
274
|
-
}
|
|
275
|
-
: validationSummary({ diagnostics, checks: linted.validation.checks });
|
|
276
|
-
await progress.report(3, 3, 'GUI inspection complete');
|
|
277
|
-
return toolResult(result);
|
|
278
|
-
}
|
|
279
|
-
catch (error) {
|
|
280
|
-
return errorResult(error, workspaceId);
|
|
281
|
-
}
|
|
282
|
-
finally {
|
|
283
|
-
releaseCaches();
|
|
284
|
-
}
|
|
285
|
-
});
|
|
286
|
-
const render = async (input, extra, code) => {
|
|
287
|
-
const workspaceId = await resolveServerWorkspaceId(engine, context, input.workspaceId, extra.signal);
|
|
288
|
-
const { windowName } = input;
|
|
289
|
-
const releaseCaches = cacheLifetime.begin();
|
|
290
|
-
try {
|
|
291
|
-
const progress = progressReporter(extra);
|
|
292
|
-
await progress.report(0, 4, 'Building GUI source graph');
|
|
293
|
-
const rendered = await withProgressHeartbeat(() => studio.renderAndStore({
|
|
294
|
-
workspaceId,
|
|
295
|
-
windowName,
|
|
296
|
-
scenario: input.scenario,
|
|
297
|
-
...(input.states === undefined ? {} : { states: input.states }),
|
|
298
|
-
...(input.resolutions === undefined
|
|
299
|
-
? {}
|
|
300
|
-
: {
|
|
301
|
-
resolutions: input.resolutions.map(({ width, height, uiScale }) => ({
|
|
302
|
-
width,
|
|
303
|
-
height,
|
|
304
|
-
...(uiScale === undefined ? {} : { uiScale }),
|
|
305
|
-
})),
|
|
306
|
-
}),
|
|
307
|
-
...(input.relatedScenarios === undefined
|
|
308
|
-
? {}
|
|
309
|
-
: { relatedScenarios: input.relatedScenarios }),
|
|
310
|
-
generatedScenarios: input.generatedScenarios ?? {},
|
|
311
|
-
...(input.comparisonScenario === undefined
|
|
312
|
-
? {}
|
|
313
|
-
: { comparisonScenario: input.comparisonScenario }),
|
|
314
|
-
...(context.principal === undefined ? {} : { principal: context.principal }),
|
|
315
|
-
signal: progress.signal,
|
|
316
|
-
}), progress, 'Rendering GUI variants and visual diagnostics');
|
|
317
|
-
await progress.report(3, 4, 'Preparing GUI result');
|
|
318
|
-
const diagnostics = rendered.validation.diagnostics;
|
|
319
|
-
const result = emptyServiceResult(workspaceId, {
|
|
320
|
-
windowName,
|
|
321
|
-
scenarioId: rendered.render.scene.scenario.id,
|
|
322
|
-
sourceRevision: rendered.render.scene.sourceRevision,
|
|
323
|
-
variantCount: rendered.render.images.length,
|
|
324
|
-
variants: rendered.render.images.slice(0, 64).map(({ variant, width, height }) => ({
|
|
325
|
-
variant,
|
|
326
|
-
width,
|
|
327
|
-
height,
|
|
328
|
-
})),
|
|
329
|
-
stateCount: rendered.stateScenes.length,
|
|
330
|
-
scenarioCount: rendered.scenarioScenes.length,
|
|
331
|
-
resolutionCount: rendered.resolutionScenes.length,
|
|
332
|
-
comparison: {
|
|
333
|
-
changedPixels: rendered.comparison.changedPixels,
|
|
334
|
-
changedRatio: rendered.comparison.changedRatio,
|
|
335
|
-
},
|
|
336
|
-
fidelityCounts: Object.fromEntries(Object.entries(rendered.render.fidelity).map(([key, values]) => [key, values.length])),
|
|
337
|
-
offlineRepresentation: true,
|
|
338
|
-
});
|
|
339
|
-
result.code = code;
|
|
340
|
-
setInlineFilesScanned(result, rendered.filesScanned);
|
|
341
|
-
result.diagnostics = diagnostics.slice(0, 100);
|
|
342
|
-
result.artifacts = rendered.artifacts.map(publicArtifactLink);
|
|
343
|
-
result.validation = validationSummary({
|
|
344
|
-
diagnostics,
|
|
345
|
-
checks: rendered.validation.checks,
|
|
346
|
-
});
|
|
347
|
-
await progress.report(4, 4, 'GUI render complete');
|
|
348
|
-
return toolResult(result);
|
|
349
|
-
}
|
|
350
|
-
catch (error) {
|
|
351
|
-
return errorResult(error, workspaceId);
|
|
352
|
-
}
|
|
353
|
-
finally {
|
|
354
|
-
releaseCaches();
|
|
355
|
-
}
|
|
356
|
-
};
|
|
357
|
-
const renderInput = guiBaseInput
|
|
358
|
-
.extend({
|
|
359
|
-
states: z.array(previewStateSchema).max(14).optional(),
|
|
360
|
-
resolutions: z.array(resolutionSchema).min(1).max(16).optional(),
|
|
361
|
-
relatedScenarios: z.array(compactGuiScenarioSchema).max(32).optional(),
|
|
362
|
-
generatedScenarios: compactGeneratedScenarioOptionsSchema.optional(),
|
|
363
|
-
comparisonScenario: compactGuiScenarioSchema.optional(),
|
|
364
|
-
})
|
|
365
|
-
.strict()
|
|
366
|
-
.superRefine(({ scenario, states, resolutions, relatedScenarios, generatedScenarios }, context) => {
|
|
367
|
-
const budget = new RenderBudget();
|
|
368
|
-
try {
|
|
369
|
-
const stateCount = states?.length ?? 14;
|
|
370
|
-
for (let index = 0; index < 9 + stateCount; index += 1) {
|
|
371
|
-
budget.reserve(scenario.resolution.width, scenario.resolution.height, 'GUI request variant');
|
|
372
|
-
}
|
|
373
|
-
for (const resolution of resolutions ?? [
|
|
374
|
-
{ width: 1280, height: 720 },
|
|
375
|
-
{ width: 1920, height: 1080 },
|
|
376
|
-
{ width: 2560, height: 1440 },
|
|
377
|
-
{ width: 1920, height: 1080 },
|
|
378
|
-
]) {
|
|
379
|
-
budget.reserve(resolution.width, resolution.height, 'GUI resolution variant');
|
|
380
|
-
}
|
|
381
|
-
const generatedCount = generatedScenarios?.enabled === false ? 0 : (generatedScenarios?.count ?? 1);
|
|
382
|
-
const scenarioCount = generatedCount === 0
|
|
383
|
-
? 1 + (relatedScenarios?.length ?? 0)
|
|
384
|
-
: generatedCount +
|
|
385
|
-
(generatedScenarios?.preservePlaceholder === false ? 0 : 1) +
|
|
386
|
-
(relatedScenarios?.length ?? 0);
|
|
387
|
-
const stateColumns = Math.min(3, Math.max(1, stateCount));
|
|
388
|
-
const stateRows = Math.max(1, Math.ceil(stateCount / stateColumns));
|
|
389
|
-
budget.reserve(stateColumns * 420, 46 + stateRows * 280, 'GUI state gallery');
|
|
390
|
-
const resolutionCount = resolutions?.length ?? 4;
|
|
391
|
-
const resolutionColumns = Math.min(3, Math.max(1, resolutionCount));
|
|
392
|
-
const resolutionRows = Math.max(1, Math.ceil(resolutionCount / resolutionColumns));
|
|
393
|
-
budget.reserve(resolutionColumns * 420, 46 + resolutionRows * 280, 'GUI resolution gallery');
|
|
394
|
-
const scenarioBudget = new RenderBudget();
|
|
395
|
-
const scenarioColumns = Math.min(3, Math.max(1, scenarioCount));
|
|
396
|
-
const scenarioRows = Math.max(1, Math.ceil(scenarioCount / scenarioColumns));
|
|
397
|
-
scenarioBudget.reserve(scenarioColumns * 420, 46 + scenarioRows * 280, 'GUI scripted scenario gallery');
|
|
398
|
-
}
|
|
399
|
-
catch (error) {
|
|
400
|
-
if (error instanceof ServiceError) {
|
|
401
|
-
context.addIssue({ code: 'custom', message: `${error.code}: ${error.message}` });
|
|
402
|
-
return;
|
|
403
|
-
}
|
|
404
|
-
throw error;
|
|
405
|
-
}
|
|
406
|
-
});
|
|
407
|
-
server.registerTool('hoi4.gui_render', {
|
|
75
|
+
},
|
|
76
|
+
{
|
|
77
|
+
name: 'hoi4.gui_render',
|
|
408
78
|
title: 'Render scripted GUI artifacts',
|
|
409
79
|
description: 'Render GUI states, resolutions, generated or explicit scenarios, dynamic flags and text icons, hierarchy, comparisons, and diagnostics.',
|
|
410
|
-
inputSchema:
|
|
80
|
+
inputSchema: guiRenderRequestSchema,
|
|
411
81
|
outputSchema: guiRenderOutputSchema,
|
|
412
82
|
annotations: artifactProducing,
|
|
413
|
-
},
|
|
414
|
-
|
|
83
|
+
},
|
|
84
|
+
{
|
|
85
|
+
name: 'hoi4.gui_rewrite',
|
|
415
86
|
title: 'Create or clean up scripted GUI',
|
|
416
87
|
description: 'Apply one validated source, helper, or exact-patch GUI package. Text dependencies use additionalFiles; binary art stays workspace-referenced.',
|
|
417
|
-
inputSchema:
|
|
418
|
-
.object({
|
|
419
|
-
mode: z.enum(['source', 'helpers', 'patches']),
|
|
420
|
-
workspaceId: workspaceIdSchema,
|
|
421
|
-
relativePath: workspaceRelativePathSchema,
|
|
422
|
-
windowName: z.string().min(1).max(256),
|
|
423
|
-
scenario: compactGuiScenarioSchema,
|
|
424
|
-
source: z.string().max(SOURCE_MAX_BYTES).optional(),
|
|
425
|
-
helper: compactGuiHelperSchema.optional(),
|
|
426
|
-
additionalFiles: z
|
|
427
|
-
.array(z
|
|
428
|
-
.object({
|
|
429
|
-
relativePath: workspaceRelativePathSchema,
|
|
430
|
-
source: z.string().max(SOURCE_MAX_BYTES),
|
|
431
|
-
})
|
|
432
|
-
.strict())
|
|
433
|
-
.max(GUI_TEXT_PACKAGE_MAX_FILES - 1)
|
|
434
|
-
.optional(),
|
|
435
|
-
expectedSourceHash: z
|
|
436
|
-
.string()
|
|
437
|
-
.regex(/^[a-f0-9]{64}$/u)
|
|
438
|
-
.optional(),
|
|
439
|
-
patches: z
|
|
440
|
-
.array(z
|
|
441
|
-
.object({
|
|
442
|
-
start: z.number().int().min(0),
|
|
443
|
-
end: z.number().int().min(0),
|
|
444
|
-
expectedText: z.string().max(5_000_000),
|
|
445
|
-
text: z.string().max(5_000_000),
|
|
446
|
-
description: z.string().min(1).max(1000),
|
|
447
|
-
})
|
|
448
|
-
.strict())
|
|
449
|
-
.min(1)
|
|
450
|
-
.max(1000)
|
|
451
|
-
.optional(),
|
|
452
|
-
})
|
|
453
|
-
.strict()
|
|
454
|
-
.superRefine((value, context) => {
|
|
455
|
-
if (value.mode === 'source' && value.source === undefined) {
|
|
456
|
-
context.addIssue({ code: 'custom', message: 'source is required in source mode' });
|
|
457
|
-
}
|
|
458
|
-
if (value.mode === 'helpers' && value.helper === undefined) {
|
|
459
|
-
context.addIssue({ code: 'custom', message: 'helper is required in helpers mode' });
|
|
460
|
-
}
|
|
461
|
-
if (value.mode === 'patches' &&
|
|
462
|
-
(value.patches === undefined || value.expectedSourceHash === undefined)) {
|
|
463
|
-
context.addIssue({
|
|
464
|
-
code: 'custom',
|
|
465
|
-
message: 'patches and expectedSourceHash are required in patches mode',
|
|
466
|
-
});
|
|
467
|
-
}
|
|
468
|
-
if (value.mode === 'source' && value.helper !== undefined) {
|
|
469
|
-
context.addIssue({ code: 'custom', message: 'helper is forbidden in source mode' });
|
|
470
|
-
}
|
|
471
|
-
if (value.mode === 'helpers' && value.source !== undefined) {
|
|
472
|
-
context.addIssue({ code: 'custom', message: 'source is forbidden in helpers mode' });
|
|
473
|
-
}
|
|
474
|
-
if (value.mode !== 'patches' &&
|
|
475
|
-
(value.patches !== undefined || value.expectedSourceHash !== undefined)) {
|
|
476
|
-
context.addIssue({
|
|
477
|
-
code: 'custom',
|
|
478
|
-
message: 'patch fields are accepted only in patches mode',
|
|
479
|
-
});
|
|
480
|
-
}
|
|
481
|
-
if (value.mode === 'patches' &&
|
|
482
|
-
(value.source !== undefined ||
|
|
483
|
-
value.helper !== undefined ||
|
|
484
|
-
value.additionalFiles !== undefined)) {
|
|
485
|
-
context.addIssue({
|
|
486
|
-
code: 'custom',
|
|
487
|
-
message: 'source, helper, and additionalFiles are forbidden in patches mode',
|
|
488
|
-
});
|
|
489
|
-
}
|
|
490
|
-
}),
|
|
88
|
+
inputSchema: guiRewriteRequestSchema,
|
|
491
89
|
outputSchema: guiPlanOutputSchema,
|
|
492
90
|
annotations: {
|
|
493
91
|
readOnlyHint: false,
|
|
@@ -495,91 +93,8 @@ export function registerGuiTools(server, engine, context) {
|
|
|
495
93
|
idempotentHint: false,
|
|
496
94
|
openWorldHint: false,
|
|
497
95
|
},
|
|
498
|
-
},
|
|
499
|
-
|
|
500
|
-
|
|
501
|
-
|
|
502
|
-
try {
|
|
503
|
-
requireServerScope(context, 'hoi4:write');
|
|
504
|
-
const progress = progressReporter(extra);
|
|
505
|
-
await progress.report(0, 3, 'Validating the requested GUI result');
|
|
506
|
-
const compilation = input.mode === 'helpers' ? compileGuiHelpers(input.helper) : undefined;
|
|
507
|
-
const plannedTransaction = await withProgressHeartbeat(() => studio.planSource({
|
|
508
|
-
workspaceId,
|
|
509
|
-
relativePath,
|
|
510
|
-
...(input.mode === 'patches'
|
|
511
|
-
? {
|
|
512
|
-
expectedSourceHash: input.expectedSourceHash,
|
|
513
|
-
patches: input.patches,
|
|
514
|
-
}
|
|
515
|
-
: {
|
|
516
|
-
source: input.mode === 'source' ? input.source : compilation.source,
|
|
517
|
-
...(input.additionalFiles === undefined
|
|
518
|
-
? {}
|
|
519
|
-
: { additionalFiles: input.additionalFiles }),
|
|
520
|
-
}),
|
|
521
|
-
windowName,
|
|
522
|
-
scenario,
|
|
523
|
-
...(context.principal === undefined ? {} : { principal: context.principal }),
|
|
524
|
-
signal: progress.signal,
|
|
525
|
-
}), progress, 'Preparing GUI rewrite');
|
|
526
|
-
await progress.report(2, 3, 'Applying and validating the GUI rewrite');
|
|
527
|
-
const execution = await withProgressHeartbeat(() => executePlannedTransaction(engine, plannedTransaction, context.principal, progress.signal), progress, 'Applying GUI rewrite');
|
|
528
|
-
const transaction = execution.transaction;
|
|
529
|
-
const planned = {
|
|
530
|
-
transaction,
|
|
531
|
-
compilation,
|
|
532
|
-
};
|
|
533
|
-
const result = emptyServiceResult(workspaceId, {
|
|
534
|
-
mode: input.mode,
|
|
535
|
-
execution: execution.outcome,
|
|
536
|
-
fileCount: transaction.files.length,
|
|
537
|
-
artifactCount: transaction.artifacts.length,
|
|
538
|
-
...(planned.compilation === undefined
|
|
539
|
-
? {}
|
|
540
|
-
: {
|
|
541
|
-
nodeCount: planned.compilation.nodeCount,
|
|
542
|
-
templateInstanceCount: planned.compilation.templateInstanceCount,
|
|
543
|
-
rawEscapeCount: planned.compilation.rawEscapeCount,
|
|
544
|
-
}),
|
|
545
|
-
});
|
|
546
|
-
result.status = transaction.validation.passed ? 'ok' : 'blocked';
|
|
547
|
-
result.code =
|
|
548
|
-
execution.outcome === 'applied'
|
|
549
|
-
? 'GUI_CHANGES_APPLIED'
|
|
550
|
-
: execution.outcome === 'unchanged'
|
|
551
|
-
? 'GUI_CHANGES_UNCHANGED'
|
|
552
|
-
: 'GUI_CHANGES_BLOCKED';
|
|
553
|
-
setInlineFilesScanned(result, [
|
|
554
|
-
relativePath,
|
|
555
|
-
...(input.additionalFiles ?? []).map(({ relativePath: file }) => file),
|
|
556
|
-
].sort((left, right) => compareCodeUnits(left, right)));
|
|
557
|
-
result.proposedFiles = transaction.files
|
|
558
|
-
.slice(0, 100)
|
|
559
|
-
.map(({ relativePath: file }) => file);
|
|
560
|
-
result.changedFiles = transaction.appliedFiles.slice(0, 100);
|
|
561
|
-
result.diagnostics = transaction.diagnostics.slice(0, 100);
|
|
562
|
-
result.artifacts = autonomousResultArtifacts(execution);
|
|
563
|
-
result.validation = transaction.validation;
|
|
564
|
-
result.blockers = transaction.diagnostics
|
|
565
|
-
.filter(({ severity }) => severity === 'error' || severity === 'blocker')
|
|
566
|
-
.map(({ code, message, details }) => ({
|
|
567
|
-
code,
|
|
568
|
-
message,
|
|
569
|
-
...(details === undefined ? {} : { details }),
|
|
570
|
-
}));
|
|
571
|
-
await progress.report(3, 3, execution.outcome === 'applied'
|
|
572
|
-
? 'GUI rewrite complete'
|
|
573
|
-
: execution.outcome === 'unchanged'
|
|
574
|
-
? 'GUI content already satisfied the rewrite'
|
|
575
|
-
: 'GUI rewrite blocked');
|
|
576
|
-
return toolResult(result);
|
|
577
|
-
}
|
|
578
|
-
catch (error) {
|
|
579
|
-
return errorResult(error, workspaceId, autonomousFailureContext(error));
|
|
580
|
-
}
|
|
581
|
-
finally {
|
|
582
|
-
releaseCaches();
|
|
583
|
-
}
|
|
584
|
-
});
|
|
96
|
+
},
|
|
97
|
+
];
|
|
98
|
+
export function registerGuiTools(server, _engine, _context) {
|
|
99
|
+
registerLegacyTaskTools(server, guiTaskTools);
|
|
585
100
|
}
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
import { CallToolResultSchema } from '@modelcontextprotocol/sdk/types.js';
|
|
2
|
+
import { JobControlService, jobReferenceSchema, jobStatusOutputSchema, } from '../../core/job-controls.js';
|
|
3
|
+
import { errorResult } from '../../core/operation-result.js';
|
|
4
|
+
export const jobControlTools = [
|
|
5
|
+
{
|
|
6
|
+
name: 'hoi4.job_inspect',
|
|
7
|
+
title: 'Inspect persistent job',
|
|
8
|
+
description: 'Inspect a durable background operation. A completed job returns the original tool result; active and terminal non-result states return bounded status evidence.',
|
|
9
|
+
inputSchema: jobReferenceSchema,
|
|
10
|
+
annotations: {
|
|
11
|
+
readOnlyHint: true,
|
|
12
|
+
destructiveHint: false,
|
|
13
|
+
idempotentHint: true,
|
|
14
|
+
openWorldHint: false,
|
|
15
|
+
},
|
|
16
|
+
},
|
|
17
|
+
{
|
|
18
|
+
name: 'hoi4.job_cancel',
|
|
19
|
+
title: 'Cancel persistent job',
|
|
20
|
+
description: 'Durably request cancellation of an authorized background operation. Completed results remain completed.',
|
|
21
|
+
inputSchema: jobReferenceSchema,
|
|
22
|
+
outputSchema: jobStatusOutputSchema,
|
|
23
|
+
annotations: {
|
|
24
|
+
readOnlyHint: false,
|
|
25
|
+
destructiveHint: true,
|
|
26
|
+
idempotentHint: true,
|
|
27
|
+
openWorldHint: false,
|
|
28
|
+
},
|
|
29
|
+
},
|
|
30
|
+
];
|
|
31
|
+
/** SDK-v1 projection of the shared, principal-private persistent-job controls. */
|
|
32
|
+
export function registerJobTools(server, engine, context, service) {
|
|
33
|
+
const controls = new JobControlService(engine, service);
|
|
34
|
+
for (const { name, ...definition } of jobControlTools) {
|
|
35
|
+
server.registerTool(name, definition, async (input, extra) => {
|
|
36
|
+
try {
|
|
37
|
+
return CallToolResultSchema.parse(await controls.call(name, input, context, extra.signal));
|
|
38
|
+
}
|
|
39
|
+
catch (error) {
|
|
40
|
+
if (extra.signal.aborted)
|
|
41
|
+
throw error;
|
|
42
|
+
return errorResult(error, input.workspaceId);
|
|
43
|
+
}
|
|
44
|
+
});
|
|
45
|
+
}
|
|
46
|
+
}
|