hoi4-agent-tools 4.3.0 → 4.5.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 +33 -1
- package/dist/hoi4_agent_tools/core/bounded-source.js +31 -9
- package/dist/hoi4_agent_tools/core/configuration.js +11 -0
- package/dist/hoi4_agent_tools/core/managed-outputs.js +26 -6
- package/dist/hoi4_agent_tools/core/operation-context.js +17 -1
- package/dist/hoi4_agent_tools/core/source/encoding.js +56 -2
- package/dist/hoi4_agent_tools/core/source/parser.js +16 -1
- package/dist/hoi4_agent_tools/core/temporary-directories.js +7 -2
- package/dist/hoi4_agent_tools/core/transaction-limits.js +18 -4
- package/dist/hoi4_agent_tools/core/transactions.js +23 -4
- package/dist/hoi4_agent_tools/core/workspace-json.js +54 -0
- package/dist/hoi4_agent_tools/core/workspace.js +42 -6
- package/dist/hoi4_agent_tools/focus/drift.js +34 -0
- package/dist/hoi4_agent_tools/focus/service.js +9 -3
- package/dist/hoi4_agent_tools/focus/tool-operations.js +2 -0
- package/dist/hoi4_agent_tools/map/appearance-validation.js +1110 -0
- package/dist/hoi4_agent_tools/map/bmp.js +9 -1
- package/dist/hoi4_agent_tools/map/border-quality-input.js +209 -0
- package/dist/hoi4_agent_tools/map/border-quality.js +1180 -0
- package/dist/hoi4_agent_tools/map/colormap.js +128 -0
- package/dist/hoi4_agent_tools/map/geography/geometry.js +284 -0
- package/dist/hoi4_agent_tools/map/geography/index.js +6 -0
- package/dist/hoi4_agent_tools/map/geography/model.js +196 -0
- package/dist/hoi4_agent_tools/map/geography/preparation.js +120 -0
- package/dist/hoi4_agent_tools/map/geography/preview.js +647 -0
- package/dist/hoi4_agent_tools/map/geography/raster.js +253 -0
- package/dist/hoi4_agent_tools/map/geography/resolve.js +1467 -0
- package/dist/hoi4_agent_tools/map/model.js +17 -3
- package/dist/hoi4_agent_tools/map/operations.js +284 -14
- package/dist/hoi4_agent_tools/map/partition-fields.js +398 -0
- package/dist/hoi4_agent_tools/map/partition-geography.js +113 -0
- package/dist/hoi4_agent_tools/map/partition-graph.js +165 -0
- package/dist/hoi4_agent_tools/map/partition-groups.js +164 -0
- package/dist/hoi4_agent_tools/map/partition-provinces.js +727 -0
- package/dist/hoi4_agent_tools/map/partition-tuning.js +101 -0
- package/dist/hoi4_agent_tools/map/partition-watershed.js +252 -0
- package/dist/hoi4_agent_tools/map/partition.js +163 -0
- package/dist/hoi4_agent_tools/map/reference-import.js +333 -0
- package/dist/hoi4_agent_tools/map/reference-preparation.js +142 -6
- package/dist/hoi4_agent_tools/map/reference-sheets.js +231 -0
- package/dist/hoi4_agent_tools/map/reference-world.js +104 -13
- package/dist/hoi4_agent_tools/map/relief/checks.js +281 -0
- package/dist/hoi4_agent_tools/map/relief/fields.js +15 -0
- package/dist/hoi4_agent_tools/map/relief/full-resolution.js +133 -0
- package/dist/hoi4_agent_tools/map/relief/grid.js +190 -0
- package/dist/hoi4_agent_tools/map/relief/hydrology.js +1315 -0
- package/dist/hoi4_agent_tools/map/relief/index.js +27 -0
- package/dist/hoi4_agent_tools/map/relief/land.js +110 -0
- package/dist/hoi4_agent_tools/map/relief/macro-relief.js +535 -0
- package/dist/hoi4_agent_tools/map/relief/math.js +93 -0
- package/dist/hoi4_agent_tools/map/relief/river-raster.js +680 -0
- package/dist/hoi4_agent_tools/map/relief/terrain-synthesis.js +304 -0
- package/dist/hoi4_agent_tools/map/render.js +36 -0
- package/dist/hoi4_agent_tools/map/service.js +206 -16
- package/dist/hoi4_agent_tools/map/tool-operations.js +249 -3
- package/dist/hoi4_agent_tools/map/validation.js +9 -0
- package/dist/hoi4_agent_tools/map/water.js +227 -0
- package/dist/hoi4_agent_tools/map/world-context.js +47 -1
- package/dist/hoi4_agent_tools/map/world-edge.js +335 -0
- package/dist/hoi4_agent_tools/map/world-noise.js +34 -0
- package/dist/hoi4_agent_tools/map/world-outputs.js +22 -10
- package/dist/hoi4_agent_tools/map/world-partition.js +119 -0
- package/dist/hoi4_agent_tools/map/world-provinces.js +131 -56
- package/dist/hoi4_agent_tools/map/world-realms.js +152 -0
- package/dist/hoi4_agent_tools/map/world.js +562 -163
- package/dist/hoi4_agent_tools/mcp/tools/map.js +69 -1
- package/dist/hoi4_agent_tools/reference/operations.js +3 -2
- package/dist/hoi4_agent_tools/schemas/geography.js +325 -0
- package/dist/hoi4_agent_tools/schemas/map-requests.js +20 -2
- package/dist/hoi4_agent_tools/schemas/map.js +280 -15
- package/dist/hoi4_agent_tools/schemas/reference-sheets.js +92 -0
- package/dist/hoi4_agent_tools/version.js +1 -1
- package/docs/configuration.md +17 -14
- package/docs/focus.md +6 -0
- package/docs/map.md +292 -15
- package/docs/tools.md +4 -4
- package/docs/troubleshooting.md +11 -11
- package/npm-shrinkwrap.json +109 -91
- package/package.json +3 -3
- package/schemas/configuration.schema.json +65 -58
- 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 +1 -1
- package/schemas/error-log-input.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/geography-model.schema.json +1148 -0
- package/schemas/gui-animation-source.schema.json +1 -1
- package/schemas/gui-helper.schema.json +5 -11
- package/schemas/gui-scenario.schema.json +1 -1
- package/schemas/helper-expansion-request.schema.json +1 -1
- package/schemas/helper-expansion-summary.schema.json +1 -1
- package/schemas/impact-inspect-input.schema.json +1 -1
- package/schemas/map-operation.schema.json +2325 -292
- package/schemas/mechanic-test-input.schema.json +1 -1
- package/schemas/mod-index-input.schema.json +1 -1
- package/schemas/operation-result.schema.json +1 -1
- package/schemas/package-check-input.schema.json +1 -1
- package/schemas/package-manifest.schema.json +1 -1
- package/schemas/probability-analysis-result.schema.json +25 -7
- 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/schemas/reference-context-input.schema.json +1 -1
- package/schemas/reference-read-input.schema.json +1 -1
- package/schemas/reference-search-input.schema.json +1 -1
- package/schemas/reference-sheets.schema.json +267 -0
- package/schemas/scenario-suite.schema.json +1 -1
- package/schemas/scenario-test-input.schema.json +1 -1
- package/schemas/script-validate-input.schema.json +1 -1
- package/schemas/shared-scenario.schema.json +1 -1
- package/schemas/source-lookup-input.schema.json +1 -1
- package/server.json +2 -2
|
@@ -0,0 +1,164 @@
|
|
|
1
|
+
/** A binary max-heap keyed by score, then by the lower ids. */
|
|
2
|
+
class CandidateHeap {
|
|
3
|
+
#items = [];
|
|
4
|
+
get size() {
|
|
5
|
+
return this.#items.length;
|
|
6
|
+
}
|
|
7
|
+
static #before(x, y) {
|
|
8
|
+
if (x.score !== y.score)
|
|
9
|
+
return x.score > y.score;
|
|
10
|
+
if (x.a !== y.a)
|
|
11
|
+
return x.a < y.a;
|
|
12
|
+
return x.b < y.b;
|
|
13
|
+
}
|
|
14
|
+
push(item) {
|
|
15
|
+
const items = this.#items;
|
|
16
|
+
let i = items.length;
|
|
17
|
+
items.push(item);
|
|
18
|
+
while (i > 0) {
|
|
19
|
+
const parent = (i - 1) >> 1;
|
|
20
|
+
if (!CandidateHeap.#before(items[i], items[parent]))
|
|
21
|
+
break;
|
|
22
|
+
[items[i], items[parent]] = [items[parent], items[i]];
|
|
23
|
+
i = parent;
|
|
24
|
+
}
|
|
25
|
+
}
|
|
26
|
+
pop() {
|
|
27
|
+
const items = this.#items;
|
|
28
|
+
if (items.length === 0)
|
|
29
|
+
return undefined;
|
|
30
|
+
const top = items[0];
|
|
31
|
+
const last = items.pop();
|
|
32
|
+
if (items.length > 0) {
|
|
33
|
+
items[0] = last;
|
|
34
|
+
let i = 0;
|
|
35
|
+
for (;;) {
|
|
36
|
+
const l = i * 2 + 1;
|
|
37
|
+
const r = l + 1;
|
|
38
|
+
let best = i;
|
|
39
|
+
if (l < items.length && CandidateHeap.#before(items[l], items[best]))
|
|
40
|
+
best = l;
|
|
41
|
+
if (r < items.length && CandidateHeap.#before(items[r], items[best]))
|
|
42
|
+
best = r;
|
|
43
|
+
if (best === i)
|
|
44
|
+
break;
|
|
45
|
+
[items[i], items[best]] = [items[best], items[i]];
|
|
46
|
+
i = best;
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
return top;
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
/**
|
|
53
|
+
* Cluster `members` (province ids) over the graph. Returns the cluster of every member, numbered
|
|
54
|
+
* from 0 by the smallest member id of each cluster.
|
|
55
|
+
*/
|
|
56
|
+
export function clusterProvinces(members, graph, options, hooks = {}) {
|
|
57
|
+
const lambda = options.lambda ?? 12;
|
|
58
|
+
const hard = options.hardBarrier ?? 0.6;
|
|
59
|
+
const unlike = options.unlikeGround ?? 0.55;
|
|
60
|
+
const sorted = [...members].sort((a, b) => a - b);
|
|
61
|
+
const local = new Map(sorted.map((id, index) => [id, index]));
|
|
62
|
+
const n = sorted.length;
|
|
63
|
+
const sizeOf = new Int32Array(n).fill(1);
|
|
64
|
+
const perimeter = new Float64Array(n);
|
|
65
|
+
const version = new Int32Array(n);
|
|
66
|
+
const alive = new Uint8Array(n).fill(1);
|
|
67
|
+
const affinity = Array.from({ length: n }, () => new Map());
|
|
68
|
+
const shared = Array.from({ length: n }, () => new Map());
|
|
69
|
+
for (let i = 0; i < n; i++) {
|
|
70
|
+
const id = sorted[i];
|
|
71
|
+
for (let e = graph.offsets[id]; e < graph.offsets[id + 1]; e++) {
|
|
72
|
+
perimeter[i] += graph.length[e];
|
|
73
|
+
const other = local.get(graph.to[e]);
|
|
74
|
+
if (other === undefined || other === i)
|
|
75
|
+
continue;
|
|
76
|
+
if (hooks.group !== undefined && hooks.group(id) !== hooks.group(graph.to[e]))
|
|
77
|
+
continue;
|
|
78
|
+
const strength = graph.barrier[e];
|
|
79
|
+
const damp = 1 / ((1 + lambda * strength) * (1 + lambda * strength));
|
|
80
|
+
let weight = graph.length[e] * damp;
|
|
81
|
+
if (strength > hard)
|
|
82
|
+
weight *= 0.05;
|
|
83
|
+
if (hooks.label !== undefined && hooks.label(id) !== hooks.label(graph.to[e]))
|
|
84
|
+
weight *= unlike;
|
|
85
|
+
affinity[i].set(other, weight);
|
|
86
|
+
shared[i].set(other, graph.length[e]);
|
|
87
|
+
}
|
|
88
|
+
}
|
|
89
|
+
const heap = new CandidateHeap();
|
|
90
|
+
const scoreOf = (a, b) => {
|
|
91
|
+
const total = sizeOf[a] + sizeOf[b];
|
|
92
|
+
if (total > options.max)
|
|
93
|
+
return 0;
|
|
94
|
+
let factor = total <= options.target ? 1 : (options.max - total) / (options.max - options.target + 1);
|
|
95
|
+
const small = Math.min(sizeOf[a], sizeOf[b]) < options.min;
|
|
96
|
+
if (small)
|
|
97
|
+
factor = Math.max(factor, 0.05) * 2;
|
|
98
|
+
if (factor <= 0)
|
|
99
|
+
return 0;
|
|
100
|
+
const base = affinity[a].get(b);
|
|
101
|
+
return (base / Math.sqrt(Math.max(1, perimeter[a]) * Math.max(1, perimeter[b]))) * factor;
|
|
102
|
+
};
|
|
103
|
+
const offer = (a, b) => {
|
|
104
|
+
const low = Math.min(a, b);
|
|
105
|
+
const high = Math.max(a, b);
|
|
106
|
+
const score = scoreOf(low, high);
|
|
107
|
+
if (score > 0)
|
|
108
|
+
heap.push({ score, a: low, b: high, versionA: version[low], versionB: version[high] });
|
|
109
|
+
};
|
|
110
|
+
for (let i = 0; i < n; i++)
|
|
111
|
+
for (const other of affinity[i].keys())
|
|
112
|
+
if (other > i)
|
|
113
|
+
offer(i, other);
|
|
114
|
+
const parent = Int32Array.from({ length: n }, (_, i) => i);
|
|
115
|
+
for (let top = heap.pop(); top !== undefined; top = heap.pop()) {
|
|
116
|
+
const { a, b } = top;
|
|
117
|
+
if (!alive[a] || !alive[b] || version[a] !== top.versionA || version[b] !== top.versionB)
|
|
118
|
+
continue;
|
|
119
|
+
// Merge b into a. Only pairs that involve a change, so only a's version moves on.
|
|
120
|
+
const between = shared[a].get(b) ?? 0;
|
|
121
|
+
perimeter[a] = perimeter[a] + perimeter[b] - 2 * between;
|
|
122
|
+
sizeOf[a] += sizeOf[b];
|
|
123
|
+
alive[b] = 0;
|
|
124
|
+
parent[b] = a;
|
|
125
|
+
affinity[a].delete(b);
|
|
126
|
+
shared[a].delete(b);
|
|
127
|
+
for (const [c, weight] of affinity[b]) {
|
|
128
|
+
if (c === a)
|
|
129
|
+
continue;
|
|
130
|
+
const combined = (affinity[a].get(c) ?? 0) + weight;
|
|
131
|
+
const length = (shared[a].get(c) ?? 0) + (shared[b].get(c) ?? 0);
|
|
132
|
+
affinity[a].set(c, combined);
|
|
133
|
+
shared[a].set(c, length);
|
|
134
|
+
affinity[c].delete(b);
|
|
135
|
+
shared[c].delete(b);
|
|
136
|
+
affinity[c].set(a, combined);
|
|
137
|
+
shared[c].set(a, length);
|
|
138
|
+
}
|
|
139
|
+
affinity[b].clear();
|
|
140
|
+
shared[b].clear();
|
|
141
|
+
version[a]++;
|
|
142
|
+
for (const c of affinity[a].keys())
|
|
143
|
+
offer(a, c);
|
|
144
|
+
}
|
|
145
|
+
// Number clusters by their smallest member (members are sorted, so the first one seen).
|
|
146
|
+
const root = (i) => {
|
|
147
|
+
let r = i;
|
|
148
|
+
while (parent[r] !== r)
|
|
149
|
+
r = parent[r];
|
|
150
|
+
return r;
|
|
151
|
+
};
|
|
152
|
+
const dense = new Map();
|
|
153
|
+
const result = new Map();
|
|
154
|
+
for (let i = 0; i < n; i++) {
|
|
155
|
+
const r = root(i);
|
|
156
|
+
let id = dense.get(r);
|
|
157
|
+
if (id === undefined) {
|
|
158
|
+
id = dense.size;
|
|
159
|
+
dense.set(r, id);
|
|
160
|
+
}
|
|
161
|
+
result.set(sorted[i], id);
|
|
162
|
+
}
|
|
163
|
+
return result;
|
|
164
|
+
}
|