hoi4-agent-tools 3.0.9 → 3.1.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 +23 -1
- package/README.md +4 -0
- package/dist/bin/stdio.js +23 -12
- package/dist/hoi4_agent_tools/core/analysis-checkpoints.js +82 -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/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/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 +200 -0
- package/dist/hoi4_agent_tools/core/job-worker.js +62 -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 +382 -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/transaction-execution.js +134 -0
- package/dist/hoi4_agent_tools/core/transactions.js +80 -27
- 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/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 +16 -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 +43 -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 +14 -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/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/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 +2 -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 +85 -0
- package/docs/technology.md +6 -2
- package/package.json +11 -5
- 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/helper-expansion-request.schema.json +44 -0
- package/schemas/helper-expansion-summary.schema.json +70 -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 +2 -2
|
@@ -0,0 +1,493 @@
|
|
|
1
|
+
import { boundedSourceHashEvidence, publicArtifactLink, } from '../core/artifacts.js';
|
|
2
|
+
import { canonicalJson, hashCanonical } from '../core/canonical.js';
|
|
3
|
+
import { autonomousResultArtifacts, } from '../core/transaction-execution.js';
|
|
4
|
+
import { emptyServiceResult } from '../core/result.js';
|
|
5
|
+
import { setInlineFilesScanned } from '../core/operation-result.js';
|
|
6
|
+
import { PACKAGE_VERSION } from '../version.js';
|
|
7
|
+
import { allocateMapIdentifiersAsync, } from './operations.js';
|
|
8
|
+
import { buildMapCatalog, lookupMapCoordinate, searchMapCatalog } from './catalog.js';
|
|
9
|
+
import { renderMap } from './render.js';
|
|
10
|
+
import { exportProvinceGeometryRowRuns } from './service.js';
|
|
11
|
+
const jsonObject = z.record(z.string(), z.json());
|
|
12
|
+
const mapRewriteRecipeSchema = z
|
|
13
|
+
.object({
|
|
14
|
+
data: jsonObject,
|
|
15
|
+
filesScanned: z.array(z.string().min(1).max(4096)),
|
|
16
|
+
planBlockers: z
|
|
17
|
+
.array(z
|
|
18
|
+
.object({
|
|
19
|
+
code: z.string().min(1).max(256),
|
|
20
|
+
message: z.string().max(4096),
|
|
21
|
+
})
|
|
22
|
+
.strict())
|
|
23
|
+
.max(100),
|
|
24
|
+
})
|
|
25
|
+
.strict();
|
|
26
|
+
const mapInlineDiffLimit = 20;
|
|
27
|
+
const mapInlineMembershipIdLimit = 32;
|
|
28
|
+
const mapInlineTextLimit = 512;
|
|
29
|
+
function compactAllocationEvidence(evidence) {
|
|
30
|
+
return {
|
|
31
|
+
...evidence,
|
|
32
|
+
rootCount: evidence.roots.length,
|
|
33
|
+
roots: evidence.roots.slice(0, 16),
|
|
34
|
+
rootsTruncated: evidence.roots.length > 16,
|
|
35
|
+
};
|
|
36
|
+
}
|
|
37
|
+
function compactNullableText(value) {
|
|
38
|
+
return value === null ? null : value.slice(0, mapInlineTextLimit);
|
|
39
|
+
}
|
|
40
|
+
function compactRecordDiffs(entries) {
|
|
41
|
+
return entries.slice(0, mapInlineDiffLimit).map(({ key, before, after }) => ({
|
|
42
|
+
key: key.slice(0, 256),
|
|
43
|
+
before: compactNullableText(before),
|
|
44
|
+
after: compactNullableText(after),
|
|
45
|
+
}));
|
|
46
|
+
}
|
|
47
|
+
function compactMapSemanticDiff(semantic) {
|
|
48
|
+
const counts = {
|
|
49
|
+
definitions: semantic.definitions.length,
|
|
50
|
+
stateMembership: semantic.stateMembership.length,
|
|
51
|
+
regionMembership: semantic.regionMembership.length,
|
|
52
|
+
states: semantic.states.length,
|
|
53
|
+
ports: semantic.ports.length,
|
|
54
|
+
buildingPositions: semantic.buildingPositions.length,
|
|
55
|
+
unitPositions: semantic.unitPositions.length,
|
|
56
|
+
weatherPositions: semantic.weatherPositions.length,
|
|
57
|
+
entityLocators: semantic.entityLocators.length,
|
|
58
|
+
supplyNodes: semantic.supplyNodes.length,
|
|
59
|
+
railways: semantic.railways.length,
|
|
60
|
+
adjacencies: semantic.adjacencies.length,
|
|
61
|
+
normalAdjacencies: semantic.normalAdjacencies.length,
|
|
62
|
+
};
|
|
63
|
+
return {
|
|
64
|
+
semantic: {
|
|
65
|
+
definitions: semantic.definitions
|
|
66
|
+
.slice(0, mapInlineDiffLimit)
|
|
67
|
+
.map(({ id, before, after }) => ({
|
|
68
|
+
id,
|
|
69
|
+
before: compactNullableText(before),
|
|
70
|
+
after: compactNullableText(after),
|
|
71
|
+
})),
|
|
72
|
+
stateMembership: semantic.stateMembership.slice(0, mapInlineDiffLimit).map((entry) => ({
|
|
73
|
+
...entry,
|
|
74
|
+
before: entry.before.slice(0, mapInlineMembershipIdLimit),
|
|
75
|
+
after: entry.after.slice(0, mapInlineMembershipIdLimit),
|
|
76
|
+
})),
|
|
77
|
+
regionMembership: semantic.regionMembership.slice(0, mapInlineDiffLimit).map((entry) => ({
|
|
78
|
+
...entry,
|
|
79
|
+
before: entry.before.slice(0, mapInlineMembershipIdLimit),
|
|
80
|
+
after: entry.after.slice(0, mapInlineMembershipIdLimit),
|
|
81
|
+
})),
|
|
82
|
+
states: compactRecordDiffs(semantic.states),
|
|
83
|
+
ports: compactRecordDiffs(semantic.ports),
|
|
84
|
+
buildingPositions: compactRecordDiffs(semantic.buildingPositions),
|
|
85
|
+
unitPositions: compactRecordDiffs(semantic.unitPositions),
|
|
86
|
+
weatherPositions: compactRecordDiffs(semantic.weatherPositions),
|
|
87
|
+
entityLocators: compactRecordDiffs(semantic.entityLocators),
|
|
88
|
+
supplyNodes: compactRecordDiffs(semantic.supplyNodes),
|
|
89
|
+
railways: compactRecordDiffs(semantic.railways),
|
|
90
|
+
adjacencies: compactRecordDiffs(semantic.adjacencies),
|
|
91
|
+
normalAdjacencies: compactRecordDiffs(semantic.normalAdjacencies),
|
|
92
|
+
supplyNodesChanged: semantic.supplyNodesChanged,
|
|
93
|
+
railwaysChanged: semantic.railwaysChanged,
|
|
94
|
+
adjacenciesChanged: semantic.adjacenciesChanged,
|
|
95
|
+
normalAdjacenciesChanged: semantic.normalAdjacenciesChanged,
|
|
96
|
+
},
|
|
97
|
+
counts,
|
|
98
|
+
truncated: Object.values(counts).some((count) => count > mapInlineDiffLimit) ||
|
|
99
|
+
[...semantic.stateMembership, ...semantic.regionMembership].some(({ before, after }) => before.length > mapInlineMembershipIdLimit || after.length > mapInlineMembershipIdLimit) ||
|
|
100
|
+
semantic.definitions.some(({ before, after }) => (before?.length ?? 0) > mapInlineTextLimit || (after?.length ?? 0) > mapInlineTextLimit) ||
|
|
101
|
+
[
|
|
102
|
+
...semantic.states,
|
|
103
|
+
...semantic.ports,
|
|
104
|
+
...semantic.buildingPositions,
|
|
105
|
+
...semantic.unitPositions,
|
|
106
|
+
...semantic.weatherPositions,
|
|
107
|
+
...semantic.entityLocators,
|
|
108
|
+
...semantic.supplyNodes,
|
|
109
|
+
...semantic.railways,
|
|
110
|
+
...semantic.adjacencies,
|
|
111
|
+
...semantic.normalAdjacencies,
|
|
112
|
+
].some(({ key, before, after }) => key.length > 256 ||
|
|
113
|
+
(before?.length ?? 0) > mapInlineTextLimit ||
|
|
114
|
+
(after?.length ?? 0) > mapInlineTextLimit),
|
|
115
|
+
};
|
|
116
|
+
}
|
|
117
|
+
function validationSummary(validation) {
|
|
118
|
+
return { passed: validation.passed, checks: validation.checks };
|
|
119
|
+
}
|
|
120
|
+
function mapArtifactSourceEvidence(files) {
|
|
121
|
+
const complete = Object.fromEntries(files.map(({ displayPath, sha256 }) => [displayPath, sha256]));
|
|
122
|
+
return { complete, bounded: boundedSourceHashEvidence(complete) };
|
|
123
|
+
}
|
|
124
|
+
function selectedMapEntities(snapshot, provinceIds, stateIds, regionIds) {
|
|
125
|
+
const provinces = [...new Set(provinceIds)]
|
|
126
|
+
.sort((a, b) => a - b)
|
|
127
|
+
.map((id) => {
|
|
128
|
+
const definition = snapshot.index.definitionsById.get(id);
|
|
129
|
+
const geometry = snapshot.index.raster?.geometry.get(id);
|
|
130
|
+
return {
|
|
131
|
+
id,
|
|
132
|
+
definition: definition === undefined
|
|
133
|
+
? null
|
|
134
|
+
: {
|
|
135
|
+
color: definition.color,
|
|
136
|
+
type: definition.type,
|
|
137
|
+
coastal: definition.coastal,
|
|
138
|
+
terrain: definition.terrain,
|
|
139
|
+
continent: definition.continent,
|
|
140
|
+
},
|
|
141
|
+
geometry: geometry ?? null,
|
|
142
|
+
stateIds: snapshot.index.stateForProvince(id).map(({ id: state }) => state),
|
|
143
|
+
regionIds: snapshot.index.regionForProvince(id).map(({ id: region }) => region),
|
|
144
|
+
victoryPoints: snapshot.index.victoryPointsByProvince
|
|
145
|
+
.get(id)
|
|
146
|
+
?.map(({ stateId: state, value }) => ({ stateId: state, value })) ?? [],
|
|
147
|
+
provinceBuildings: snapshot.index.provinceBuildingsByProvince
|
|
148
|
+
.get(id)
|
|
149
|
+
?.map(({ stateId: state, buildings }) => ({
|
|
150
|
+
stateId: state,
|
|
151
|
+
buildings: Object.fromEntries(buildings),
|
|
152
|
+
})) ?? [],
|
|
153
|
+
port: (() => {
|
|
154
|
+
const port = snapshot.index.ports.find(({ provinceId }) => provinceId === id);
|
|
155
|
+
return port === undefined
|
|
156
|
+
? null
|
|
157
|
+
: {
|
|
158
|
+
stateId: port.stateId,
|
|
159
|
+
provinceId: port.provinceId,
|
|
160
|
+
level: port.level,
|
|
161
|
+
coastal: port.coastal,
|
|
162
|
+
adjacentSeaProvinceIds: port.adjacentSeaProvinceIds,
|
|
163
|
+
positions: port.positions.map(({ stateId, building, x, y, z, rotation, adjacentSeaProvince }) => ({
|
|
164
|
+
stateId,
|
|
165
|
+
building,
|
|
166
|
+
x,
|
|
167
|
+
y,
|
|
168
|
+
z,
|
|
169
|
+
rotation,
|
|
170
|
+
adjacentSeaProvince,
|
|
171
|
+
})),
|
|
172
|
+
};
|
|
173
|
+
})(),
|
|
174
|
+
};
|
|
175
|
+
});
|
|
176
|
+
const states = [...new Set(stateIds)]
|
|
177
|
+
.sort((a, b) => a - b)
|
|
178
|
+
.map((id) => {
|
|
179
|
+
const state = snapshot.index.statesById.get(id);
|
|
180
|
+
return state === undefined
|
|
181
|
+
? { id, value: null }
|
|
182
|
+
: {
|
|
183
|
+
id,
|
|
184
|
+
value: {
|
|
185
|
+
name: state.name,
|
|
186
|
+
capital: state.capital ?? null,
|
|
187
|
+
manpower: state.manpower,
|
|
188
|
+
category: state.category,
|
|
189
|
+
provinces: state.provinces,
|
|
190
|
+
resources: Object.fromEntries(state.resources),
|
|
191
|
+
owner: state.owner ?? null,
|
|
192
|
+
controller: state.controller ?? null,
|
|
193
|
+
cores: state.cores,
|
|
194
|
+
claims: state.claims,
|
|
195
|
+
victoryPoints: state.victoryPoints.map(({ provinceId, value }) => ({
|
|
196
|
+
provinceId,
|
|
197
|
+
value,
|
|
198
|
+
})),
|
|
199
|
+
stateBuildings: Object.fromEntries(state.stateBuildings),
|
|
200
|
+
provinceBuildings: Object.fromEntries([...state.provinceBuildings].map(([provinceId, buildings]) => [
|
|
201
|
+
String(provinceId),
|
|
202
|
+
Object.fromEntries(buildings),
|
|
203
|
+
])),
|
|
204
|
+
},
|
|
205
|
+
};
|
|
206
|
+
});
|
|
207
|
+
const regions = [...new Set(regionIds)]
|
|
208
|
+
.sort((a, b) => a - b)
|
|
209
|
+
.map((id) => {
|
|
210
|
+
const region = snapshot.index.regionsById.get(id);
|
|
211
|
+
return region === undefined
|
|
212
|
+
? { id, value: null }
|
|
213
|
+
: {
|
|
214
|
+
id,
|
|
215
|
+
value: {
|
|
216
|
+
name: region.name,
|
|
217
|
+
provinces: region.provinces,
|
|
218
|
+
navalTerrain: region.navalTerrain ?? null,
|
|
219
|
+
},
|
|
220
|
+
};
|
|
221
|
+
});
|
|
222
|
+
return { provinces, states, regions };
|
|
223
|
+
}
|
|
224
|
+
export function normalizeMapInspectRequest(input) {
|
|
225
|
+
return input;
|
|
226
|
+
}
|
|
227
|
+
export function normalizeMapRenderRequest(input) {
|
|
228
|
+
return input;
|
|
229
|
+
}
|
|
230
|
+
export function normalizeMapRewriteRequest(input) {
|
|
231
|
+
return input;
|
|
232
|
+
}
|
|
233
|
+
export async function prepareMapRewrite(nudger, input, context) {
|
|
234
|
+
await context.progress(0, 5, 'Planning map operations and visual diff');
|
|
235
|
+
const planned = await nudger.planRewriteWithDiff({
|
|
236
|
+
workspaceId: context.workspaceId,
|
|
237
|
+
operations: input.operations,
|
|
238
|
+
...(input.diffScale === undefined ? {} : { diffScale: input.diffScale }),
|
|
239
|
+
...(context.principal === undefined ? {} : { principal: context.principal }),
|
|
240
|
+
...(context.signal === undefined ? {} : { signal: context.signal }),
|
|
241
|
+
});
|
|
242
|
+
const compactSemantic = compactMapSemanticDiff(planned.bundle.semantic);
|
|
243
|
+
await context.progress(3, 5, 'Map rewrite prepared for journaled application');
|
|
244
|
+
return {
|
|
245
|
+
transaction: planned.transaction,
|
|
246
|
+
recipe: mapRewriteRecipeSchema.parse({
|
|
247
|
+
data: jsonObject.parse({
|
|
248
|
+
allocations: planned.plan.allocations.slice(0, 100).map(compactAllocationEvidence),
|
|
249
|
+
operationBlockers: planned.plan.blockers
|
|
250
|
+
.slice(0, 100)
|
|
251
|
+
.map(({ code, message, operationId }) => ({ code, message, operationId })),
|
|
252
|
+
expectedChangedBounds: planned.plan.expectedChangedBounds ?? null,
|
|
253
|
+
changedProvinceIds: planned.bundle.changedProvinceIds.slice(0, 256),
|
|
254
|
+
changedProvinceCount: planned.bundle.changedProvinceIds.length,
|
|
255
|
+
semanticDiff: compactSemantic.semantic,
|
|
256
|
+
semanticDiffCounts: compactSemantic.counts,
|
|
257
|
+
semanticDiffTruncated: compactSemantic.truncated,
|
|
258
|
+
}),
|
|
259
|
+
filesScanned: planned.filesScanned,
|
|
260
|
+
planBlockers: planned.plan.blockers
|
|
261
|
+
.slice(0, 100)
|
|
262
|
+
.map(({ code, message }) => ({ code, message })),
|
|
263
|
+
}),
|
|
264
|
+
};
|
|
265
|
+
}
|
|
266
|
+
export function completeMapRewrite(workspaceId, execution, recipe) {
|
|
267
|
+
const parsed = mapRewriteRecipeSchema.parse(recipe);
|
|
268
|
+
const transaction = execution.transaction;
|
|
269
|
+
const result = emptyServiceResult(workspaceId, {
|
|
270
|
+
execution: execution.outcome,
|
|
271
|
+
...parsed.data,
|
|
272
|
+
fileCount: transaction.files.length,
|
|
273
|
+
artifactCount: transaction.artifacts.length,
|
|
274
|
+
});
|
|
275
|
+
result.status = transaction.validation.passed ? 'ok' : 'blocked';
|
|
276
|
+
result.code =
|
|
277
|
+
execution.outcome === 'applied'
|
|
278
|
+
? 'MAP_CHANGES_APPLIED'
|
|
279
|
+
: execution.outcome === 'unchanged'
|
|
280
|
+
? 'MAP_CHANGES_UNCHANGED'
|
|
281
|
+
: 'MAP_CHANGES_BLOCKED';
|
|
282
|
+
setInlineFilesScanned(result, parsed.filesScanned);
|
|
283
|
+
result.proposedFiles = transaction.files.slice(0, 100).map(({ relativePath }) => relativePath);
|
|
284
|
+
result.changedFiles = transaction.appliedFiles.slice(0, 100);
|
|
285
|
+
result.diagnostics = transaction.diagnostics.slice(0, 100);
|
|
286
|
+
result.artifacts = autonomousResultArtifacts(execution);
|
|
287
|
+
result.validation = transaction.validation;
|
|
288
|
+
result.blockers = [
|
|
289
|
+
...parsed.planBlockers,
|
|
290
|
+
...transaction.diagnostics
|
|
291
|
+
.filter(({ severity }) => severity === 'error' || severity === 'blocker')
|
|
292
|
+
.map(({ code, message, details }) => ({
|
|
293
|
+
code,
|
|
294
|
+
message,
|
|
295
|
+
...(details === undefined ? {} : { details }),
|
|
296
|
+
})),
|
|
297
|
+
].slice(0, 100);
|
|
298
|
+
return result;
|
|
299
|
+
}
|
|
300
|
+
export async function inspectMap(engine, nudger, input, context) {
|
|
301
|
+
await context.progress(0, 3, 'Inspecting and validating the map');
|
|
302
|
+
const { snapshot, validation } = await nudger.validate(context.workspaceId, context.principal, context.signal);
|
|
303
|
+
const sharedRevision = snapshot.revision;
|
|
304
|
+
const catalog = buildMapCatalog(snapshot.index);
|
|
305
|
+
const queryMatches = input.query === undefined ? [] : searchMapCatalog(catalog, input.query, input.queryLimit);
|
|
306
|
+
const coordinateMatches = input.coordinates.map((coordinate) => lookupMapCoordinate(snapshot.index, coordinate));
|
|
307
|
+
const overviewRendered = input.includeOverview && snapshot.index.raster !== undefined;
|
|
308
|
+
const selected = selectedMapEntities(snapshot, input.provinceIds, input.stateIds, input.regionIds);
|
|
309
|
+
const provinceGeometry = input.provinceIds.length === 0
|
|
310
|
+
? undefined
|
|
311
|
+
: await exportProvinceGeometryRowRuns(snapshot.index, input.provinceIds, context.signal);
|
|
312
|
+
const allocationPreviews = [];
|
|
313
|
+
for (const request of input.allocationRequests) {
|
|
314
|
+
allocationPreviews.push({
|
|
315
|
+
request,
|
|
316
|
+
allocation: await allocateMapIdentifiersAsync(snapshot.index, request, context.signal),
|
|
317
|
+
});
|
|
318
|
+
}
|
|
319
|
+
const workspace = engine.resolver.get(context.workspaceId, context.principal);
|
|
320
|
+
const sourceEvidence = mapArtifactSourceEvidence(snapshot.files);
|
|
321
|
+
const inspectionProvenance = {
|
|
322
|
+
kind: 'map-inspect',
|
|
323
|
+
toolVersion: PACKAGE_VERSION,
|
|
324
|
+
schemaVersion: 'map-inspect.v2',
|
|
325
|
+
sourceHashes: sourceEvidence.bounded.sourceHashes,
|
|
326
|
+
metadata: {
|
|
327
|
+
sharedRevision,
|
|
328
|
+
sourceHashInventory: sourceEvidence.bounded.inventory,
|
|
329
|
+
},
|
|
330
|
+
};
|
|
331
|
+
const artifactWrites = [
|
|
332
|
+
{
|
|
333
|
+
name: `map-inspect.${snapshot.revision.slice(0, 16)}.json`,
|
|
334
|
+
mimeType: 'application/json',
|
|
335
|
+
content: `${canonicalJson({
|
|
336
|
+
schemaVersion: 2,
|
|
337
|
+
revision: snapshot.revision,
|
|
338
|
+
sharedRevision,
|
|
339
|
+
dimensions: snapshot.index.raster === undefined
|
|
340
|
+
? null
|
|
341
|
+
: {
|
|
342
|
+
width: snapshot.index.raster.width,
|
|
343
|
+
height: snapshot.index.raster.height,
|
|
344
|
+
bitsPerPixel: snapshot.index.provinceBitmap?.bitsPerPixel,
|
|
345
|
+
dibSize: snapshot.index.provinceBitmap?.dibSize,
|
|
346
|
+
},
|
|
347
|
+
counts: {
|
|
348
|
+
definitions: snapshot.index.definitions.length,
|
|
349
|
+
states: snapshot.index.states.length,
|
|
350
|
+
regions: snapshot.index.regions.length,
|
|
351
|
+
adjacencies: snapshot.index.adjacencies.length,
|
|
352
|
+
supplyNodes: snapshot.index.supplyNodes.length,
|
|
353
|
+
railways: snapshot.index.railways.length,
|
|
354
|
+
ports: snapshot.index.ports.length,
|
|
355
|
+
locators: snapshot.index.entityLocators.length,
|
|
356
|
+
},
|
|
357
|
+
catalog,
|
|
358
|
+
query: input.query ?? null,
|
|
359
|
+
queryMatches,
|
|
360
|
+
coordinateMatches,
|
|
361
|
+
selected,
|
|
362
|
+
allocationPreviews,
|
|
363
|
+
validation,
|
|
364
|
+
sourceHashes: sourceEvidence.complete,
|
|
365
|
+
})}\n`,
|
|
366
|
+
provenance: inspectionProvenance,
|
|
367
|
+
description: 'Complete searchable map catalog, inspection, validation, selected records, and allocation previews',
|
|
368
|
+
},
|
|
369
|
+
];
|
|
370
|
+
if (overviewRendered) {
|
|
371
|
+
const overviewLayer = 'state';
|
|
372
|
+
const overviewOverlays = [
|
|
373
|
+
'coastlines',
|
|
374
|
+
'ports',
|
|
375
|
+
'victory-points',
|
|
376
|
+
'supply-nodes',
|
|
377
|
+
'railways',
|
|
378
|
+
];
|
|
379
|
+
const overview = await renderMap(snapshot.index, {
|
|
380
|
+
layer: overviewLayer,
|
|
381
|
+
overlays: overviewOverlays,
|
|
382
|
+
...(context.signal === undefined ? {} : { signal: context.signal }),
|
|
383
|
+
});
|
|
384
|
+
const overviewProvenance = {
|
|
385
|
+
kind: 'map-inspect-overview',
|
|
386
|
+
toolVersion: PACKAGE_VERSION,
|
|
387
|
+
schemaVersion: 'map-inspect-overview.v1',
|
|
388
|
+
sourceHashes: sourceEvidence.bounded.sourceHashes,
|
|
389
|
+
renderProfile: {
|
|
390
|
+
layer: overviewLayer,
|
|
391
|
+
overlays: [...new Set(overviewOverlays)].sort(),
|
|
392
|
+
scale: 1,
|
|
393
|
+
},
|
|
394
|
+
metadata: { sourceHashInventory: sourceEvidence.bounded.inventory },
|
|
395
|
+
};
|
|
396
|
+
artifactWrites.push({
|
|
397
|
+
name: `map-overview.${snapshot.revision.slice(0, 16)}.png`,
|
|
398
|
+
mimeType: 'image/png',
|
|
399
|
+
content: overview.png,
|
|
400
|
+
provenance: overviewProvenance,
|
|
401
|
+
description: 'Complete rendered map overview',
|
|
402
|
+
}, {
|
|
403
|
+
name: `map-overview.${snapshot.revision.slice(0, 16)}.html`,
|
|
404
|
+
mimeType: 'text/html',
|
|
405
|
+
content: overview.html,
|
|
406
|
+
provenance: overviewProvenance,
|
|
407
|
+
description: 'Searchable and clickable full-map navigator with exact IDs, names, coordinates, and linked records',
|
|
408
|
+
});
|
|
409
|
+
}
|
|
410
|
+
if (provinceGeometry !== undefined) {
|
|
411
|
+
const { width, height, requestedProvinceIds, unknownProvinceIds, missingGeometryProvinceIds, pixelCount, rowRunCount, provinces, } = provinceGeometry;
|
|
412
|
+
const selectorHash = hashCanonical(requestedProvinceIds).slice(0, 16);
|
|
413
|
+
artifactWrites.push({
|
|
414
|
+
name: `map-province-geometry.${snapshot.revision.slice(0, 16)}.${selectorHash}.json`,
|
|
415
|
+
mimeType: 'application/json',
|
|
416
|
+
content: `${canonicalJson({
|
|
417
|
+
schemaVersion: 1,
|
|
418
|
+
revision: snapshot.revision,
|
|
419
|
+
dimensions: { width, height },
|
|
420
|
+
coordinateSystem: { origin: 'top-left', xDirection: 'right', yDirection: 'down' },
|
|
421
|
+
rowRunFormat: ['y', 'startX', 'endXExclusive'],
|
|
422
|
+
requestedProvinceIds,
|
|
423
|
+
unknownProvinceIds,
|
|
424
|
+
missingGeometryProvinceIds,
|
|
425
|
+
pixelCount,
|
|
426
|
+
rowRunCount,
|
|
427
|
+
provinces,
|
|
428
|
+
sourceHashes: sourceEvidence.complete,
|
|
429
|
+
})}\n`,
|
|
430
|
+
provenance: {
|
|
431
|
+
kind: 'map-province-geometry',
|
|
432
|
+
toolVersion: PACKAGE_VERSION,
|
|
433
|
+
schemaVersion: 'map-province-geometry.v1',
|
|
434
|
+
sourceHashes: sourceEvidence.bounded.sourceHashes,
|
|
435
|
+
metadata: { requestedProvinceIds, sourceHashInventory: sourceEvidence.bounded.inventory },
|
|
436
|
+
},
|
|
437
|
+
description: 'Exact canonical province row runs for deriving bounded split or create geometry',
|
|
438
|
+
});
|
|
439
|
+
}
|
|
440
|
+
const artifacts = await engine.artifacts.withAtomicChunkedWrites(workspace, artifactWrites, (stored) => Promise.resolve([...stored]), context.signal);
|
|
441
|
+
const result = emptyServiceResult(context.workspaceId, {
|
|
442
|
+
revision: snapshot.revision,
|
|
443
|
+
sharedRevision,
|
|
444
|
+
width: snapshot.index.raster?.width ?? null,
|
|
445
|
+
height: snapshot.index.raster?.height ?? null,
|
|
446
|
+
definitions: snapshot.index.definitions.length,
|
|
447
|
+
states: snapshot.index.states.length,
|
|
448
|
+
regions: snapshot.index.regions.length,
|
|
449
|
+
ports: snapshot.index.ports.length,
|
|
450
|
+
inspectedProvinceCount: selected.provinces.length,
|
|
451
|
+
inspectedStateCount: selected.states.length,
|
|
452
|
+
inspectedRegionCount: selected.regions.length,
|
|
453
|
+
allocationCount: allocationPreviews.length,
|
|
454
|
+
queryMatchCount: queryMatches.length,
|
|
455
|
+
coordinateMatchCount: coordinateMatches.length,
|
|
456
|
+
overviewRendered,
|
|
457
|
+
provinceGeometryCount: provinceGeometry?.provinces.length ?? 0,
|
|
458
|
+
provinceGeometryPixelCount: provinceGeometry?.pixelCount ?? 0,
|
|
459
|
+
provinceGeometryRowRunCount: provinceGeometry?.rowRunCount ?? 0,
|
|
460
|
+
unknownProvinceIds: provinceGeometry?.unknownProvinceIds ?? [],
|
|
461
|
+
missingGeometryProvinceIds: provinceGeometry?.missingGeometryProvinceIds ?? [],
|
|
462
|
+
});
|
|
463
|
+
result.code = 'MAP_INSPECTED';
|
|
464
|
+
setInlineFilesScanned(result, snapshot.files.map(({ displayPath }) => displayPath));
|
|
465
|
+
result.diagnostics = validation.diagnostics.slice(0, 100);
|
|
466
|
+
result.artifacts = artifacts.map(publicArtifactLink);
|
|
467
|
+
result.validation = validationSummary(validation);
|
|
468
|
+
await context.progress(3, 3, 'Map inspection complete');
|
|
469
|
+
return result;
|
|
470
|
+
}
|
|
471
|
+
export async function renderMapView(nudger, input, context) {
|
|
472
|
+
await context.progress(0, 3, 'Rendering offline map layer');
|
|
473
|
+
const rendered = await nudger.renderAndStore(context.workspaceId, {
|
|
474
|
+
...(input.layer === undefined ? {} : { layer: input.layer }),
|
|
475
|
+
...(input.overlays === undefined ? {} : { overlays: input.overlays }),
|
|
476
|
+
...(input.scale === undefined ? {} : { scale: input.scale }),
|
|
477
|
+
...(context.principal === undefined ? {} : { principal: context.principal }),
|
|
478
|
+
...(context.signal === undefined ? {} : { signal: context.signal }),
|
|
479
|
+
});
|
|
480
|
+
const result = emptyServiceResult(context.workspaceId, {
|
|
481
|
+
revision: rendered.revision,
|
|
482
|
+
width: rendered.bundle.width,
|
|
483
|
+
height: rendered.bundle.height,
|
|
484
|
+
hashes: rendered.bundle.hashes,
|
|
485
|
+
offlineRepresentation: true,
|
|
486
|
+
});
|
|
487
|
+
result.code = 'MAP_RENDERED';
|
|
488
|
+
setInlineFilesScanned(result, rendered.filesScanned);
|
|
489
|
+
result.artifacts = rendered.artifacts.map(publicArtifactLink);
|
|
490
|
+
await context.progress(3, 3, 'Map render complete');
|
|
491
|
+
return result;
|
|
492
|
+
}
|
|
493
|
+
import { z } from 'zod/v4';
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
import { z } from 'zod/v4';
|
|
2
|
+
export const probabilityPromptArguments = z.object({
|
|
3
|
+
objective: z.string().min(1).max(4096),
|
|
4
|
+
sourceHint: z.string().max(1024).optional(),
|
|
5
|
+
});
|
|
6
|
+
export const probabilityPromptDefinition = {
|
|
7
|
+
name: 'hoi4.probability_analysis',
|
|
8
|
+
title: 'Analyze HOI4 weighted logic',
|
|
9
|
+
description: 'Plan one source-linked AI, MTTH, random, or declared-pool analysis and return to the owning modding workflow.',
|
|
10
|
+
};
|
|
11
|
+
/** One prompt body for both protocol generations; it does not run an analysis. */
|
|
12
|
+
export function probabilityPrompt(input) {
|
|
13
|
+
const { objective, sourceHint } = probabilityPromptArguments.parse(input);
|
|
14
|
+
return {
|
|
15
|
+
messages: [
|
|
16
|
+
{
|
|
17
|
+
role: 'user',
|
|
18
|
+
content: {
|
|
19
|
+
type: 'text',
|
|
20
|
+
text: `Analyze this HOI4 weighted-logic task: ${objective}${sourceHint === undefined ? '' : `\nSource hint: ${sourceHint}`}\nIdentify the exact weighted surface and adapter, declare representative world-state scenarios and every required candidate or external factor, inspect first, run the narrowest useful evaluate/sweep/simulate/sequence/compare operation, review linked uncertainty and provenance, then return the findings to the normal owning modding workflow. Do not infer missing state, execute effects, or edit source through probability tools.`,
|
|
21
|
+
},
|
|
22
|
+
},
|
|
23
|
+
],
|
|
24
|
+
};
|
|
25
|
+
}
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
import { GetPromptResultSchema } from '@modelcontextprotocol/core';
|
|
2
|
+
import { ProtocolError, ProtocolErrorCode } from '@modelcontextprotocol/server';
|
|
3
|
+
import { probabilityPrompt, probabilityPromptArguments, probabilityPromptDefinition, } from './probability.js';
|
|
4
|
+
export function registerModernPrompts(server) {
|
|
5
|
+
server.setRequestHandler('prompts/list', () => ({
|
|
6
|
+
prompts: [
|
|
7
|
+
{
|
|
8
|
+
...probabilityPromptDefinition,
|
|
9
|
+
arguments: Object.entries(probabilityPromptArguments.shape).map(([name, schema]) => ({
|
|
10
|
+
name,
|
|
11
|
+
required: !schema.safeParse(undefined).success,
|
|
12
|
+
})),
|
|
13
|
+
},
|
|
14
|
+
],
|
|
15
|
+
}));
|
|
16
|
+
server.setRequestHandler('prompts/get', (request) => {
|
|
17
|
+
if (request.params.name !== probabilityPromptDefinition.name)
|
|
18
|
+
throw new ProtocolError(ProtocolErrorCode.InvalidParams, 'Unknown prompt');
|
|
19
|
+
const parsed = probabilityPromptArguments.safeParse(request.params.arguments ?? {});
|
|
20
|
+
if (!parsed.success)
|
|
21
|
+
throw new ProtocolError(ProtocolErrorCode.InvalidParams, 'Invalid prompt arguments');
|
|
22
|
+
return GetPromptResultSchema.parse({
|
|
23
|
+
...probabilityPrompt(parsed.data),
|
|
24
|
+
resultType: 'complete',
|
|
25
|
+
ttlMs: 0,
|
|
26
|
+
cacheScope: 'private',
|
|
27
|
+
});
|
|
28
|
+
});
|
|
29
|
+
}
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
import { ReadResourceResultSchema } from '@modelcontextprotocol/core';
|
|
2
|
+
import { ProtocolError, ProtocolErrorCode, ResourceNotFoundError, } from '@modelcontextprotocol/server';
|
|
3
|
+
import { artifactResourceDefinition, readArtifactResource } from '../../core/artifact-resource.js';
|
|
4
|
+
import { ServiceError } from '../../core/result.js';
|
|
5
|
+
/** Modern wire projection of the same non-enumerating, authorization-bound resource reader. */
|
|
6
|
+
export function registerModernResources(server, engine, context) {
|
|
7
|
+
server.setRequestHandler('resources/list', () => ({ resources: [] }));
|
|
8
|
+
server.setRequestHandler('resources/templates/list', () => ({
|
|
9
|
+
resourceTemplates: [artifactResourceDefinition],
|
|
10
|
+
}));
|
|
11
|
+
server.setRequestHandler('resources/read', async (request, extra) => {
|
|
12
|
+
try {
|
|
13
|
+
return ReadResourceResultSchema.parse({
|
|
14
|
+
...(await readArtifactResource(engine, request.params.uri, context, extra.mcpReq.signal)),
|
|
15
|
+
resultType: 'complete',
|
|
16
|
+
ttlMs: 0,
|
|
17
|
+
cacheScope: 'private',
|
|
18
|
+
});
|
|
19
|
+
}
|
|
20
|
+
catch (error) {
|
|
21
|
+
if (extra.mcpReq.signal.aborted)
|
|
22
|
+
throw error;
|
|
23
|
+
if (error instanceof ServiceError) {
|
|
24
|
+
if (error.code.startsWith('RESOURCE_') ||
|
|
25
|
+
['ARTIFACT_URI_INVALID', 'ARTIFACT_RANGE_INVALID', 'ARTIFACT_METADATA_INVALID'].includes(error.code))
|
|
26
|
+
throw new ProtocolError(ProtocolErrorCode.InvalidParams, error.message, {
|
|
27
|
+
code: error.code,
|
|
28
|
+
});
|
|
29
|
+
throw new ResourceNotFoundError(request.params.uri);
|
|
30
|
+
}
|
|
31
|
+
throw new ProtocolError(ProtocolErrorCode.InternalError, 'The resource could not be read');
|
|
32
|
+
}
|
|
33
|
+
});
|
|
34
|
+
}
|