hoi4-agent-tools 3.0.8 → 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.
Files changed (135) hide show
  1. package/CHANGELOG.md +35 -1
  2. package/README.md +4 -0
  3. package/dist/bin/stdio.js +23 -12
  4. package/dist/hoi4_agent_tools/core/analysis-checkpoints.js +82 -0
  5. package/dist/hoi4_agent_tools/core/artifact-resource.js +173 -0
  6. package/dist/hoi4_agent_tools/core/artifacts.js +84 -2
  7. package/dist/hoi4_agent_tools/core/condition-evaluator.js +399 -0
  8. package/dist/hoi4_agent_tools/core/condition-model.js +1 -0
  9. package/dist/hoi4_agent_tools/core/condition-schema.js +42 -0
  10. package/dist/hoi4_agent_tools/core/dependency-pages.js +216 -0
  11. package/dist/hoi4_agent_tools/core/dependency-walk.js +266 -0
  12. package/dist/hoi4_agent_tools/core/domain-validation.js +188 -0
  13. package/dist/hoi4_agent_tools/core/engine.js +48 -5
  14. package/dist/hoi4_agent_tools/core/helper-expansion.js +186 -0
  15. package/dist/hoi4_agent_tools/core/index-segments.js +137 -0
  16. package/dist/hoi4_agent_tools/core/index.js +47 -4
  17. package/dist/hoi4_agent_tools/core/job-controls.js +109 -0
  18. package/dist/hoi4_agent_tools/core/job-executor.js +190 -0
  19. package/dist/hoi4_agent_tools/core/job-service.js +112 -0
  20. package/dist/hoi4_agent_tools/core/job-store.js +641 -0
  21. package/dist/hoi4_agent_tools/core/job-transactions.js +126 -0
  22. package/dist/hoi4_agent_tools/core/job-worker-host.js +200 -0
  23. package/dist/hoi4_agent_tools/core/job-worker.js +62 -0
  24. package/dist/hoi4_agent_tools/core/operation-context.js +31 -0
  25. package/dist/hoi4_agent_tools/core/operation-result.js +412 -0
  26. package/dist/hoi4_agent_tools/core/operation-tasks.js +382 -0
  27. package/dist/hoi4_agent_tools/core/persistent-analysis-cache.js +383 -0
  28. package/dist/hoi4_agent_tools/core/result.js +1 -0
  29. package/dist/hoi4_agent_tools/core/scanner.js +15 -75
  30. package/dist/hoi4_agent_tools/core/scenario-state.js +97 -0
  31. package/dist/hoi4_agent_tools/core/semantic-dependencies.js +233 -0
  32. package/dist/hoi4_agent_tools/core/shared-request-capacity.js +74 -25
  33. package/dist/hoi4_agent_tools/core/source/cache.js +107 -0
  34. package/dist/hoi4_agent_tools/core/source/parser.js +11 -1
  35. package/dist/hoi4_agent_tools/core/transaction-execution.js +134 -0
  36. package/dist/hoi4_agent_tools/core/transactions.js +80 -27
  37. package/dist/hoi4_agent_tools/event/graph.js +214 -290
  38. package/dist/hoi4_agent_tools/event/helper-expansion.js +33 -0
  39. package/dist/hoi4_agent_tools/event/job-operations.js +51 -0
  40. package/dist/hoi4_agent_tools/event/operations.js +179 -0
  41. package/dist/hoi4_agent_tools/event/service.js +67 -15
  42. package/dist/hoi4_agent_tools/event/source-analysis.js +5 -4
  43. package/dist/hoi4_agent_tools/focus/job-operations.js +77 -0
  44. package/dist/hoi4_agent_tools/focus/tool-operations.js +669 -0
  45. package/dist/hoi4_agent_tools/focus/tool-support.js +123 -0
  46. package/dist/hoi4_agent_tools/gui/job-operations.js +81 -0
  47. package/dist/hoi4_agent_tools/gui/scenario-conditions.js +119 -0
  48. package/dist/hoi4_agent_tools/gui/scenario-generator.js +59 -73
  49. package/dist/hoi4_agent_tools/gui/scenario.js +3 -0
  50. package/dist/hoi4_agent_tools/gui/studio.js +5 -2
  51. package/dist/hoi4_agent_tools/gui/tool-operations.js +270 -0
  52. package/dist/hoi4_agent_tools/map/job-operations.js +76 -0
  53. package/dist/hoi4_agent_tools/map/tool-operations.js +493 -0
  54. package/dist/hoi4_agent_tools/mcp/prompts/probability.js +25 -0
  55. package/dist/hoi4_agent_tools/mcp/prompts/register-modern.js +29 -0
  56. package/dist/hoi4_agent_tools/mcp/resources/register-modern.js +34 -0
  57. package/dist/hoi4_agent_tools/mcp/resources/register.js +4 -150
  58. package/dist/hoi4_agent_tools/mcp/server/base-tools.js +3 -219
  59. package/dist/hoi4_agent_tools/mcp/server/create-modern-operations.js +188 -0
  60. package/dist/hoi4_agent_tools/mcp/server/create.js +16 -6
  61. package/dist/hoi4_agent_tools/mcp/server/instructions.js +2 -0
  62. package/dist/hoi4_agent_tools/mcp/server/job-task-store.js +67 -0
  63. package/dist/hoi4_agent_tools/mcp/server/legacy-task-tools.js +20 -0
  64. package/dist/hoi4_agent_tools/mcp/server/modern-tasks.js +168 -0
  65. package/dist/hoi4_agent_tools/mcp/server/progress.js +17 -15
  66. package/dist/hoi4_agent_tools/mcp/server/request-lifecycle.js +43 -0
  67. package/dist/hoi4_agent_tools/mcp/server/result.js +2 -412
  68. package/dist/hoi4_agent_tools/mcp/server/task-request-context.js +9 -0
  69. package/dist/hoi4_agent_tools/mcp/server/task-tool-catalog.js +14 -0
  70. package/dist/hoi4_agent_tools/mcp/server/task-tool-definition.js +1 -0
  71. package/dist/hoi4_agent_tools/mcp/server/transaction-execution.js +1 -123
  72. package/dist/hoi4_agent_tools/mcp/tools/chaosx.js +38 -21
  73. package/dist/hoi4_agent_tools/mcp/tools/event.js +24 -315
  74. package/dist/hoi4_agent_tools/mcp/tools/focus.js +34 -1039
  75. package/dist/hoi4_agent_tools/mcp/tools/gui.js +19 -504
  76. package/dist/hoi4_agent_tools/mcp/tools/job.js +46 -0
  77. package/dist/hoi4_agent_tools/mcp/tools/map.js +21 -600
  78. package/dist/hoi4_agent_tools/mcp/tools/probability.js +39 -463
  79. package/dist/hoi4_agent_tools/mcp/tools/technology.js +40 -304
  80. package/dist/hoi4_agent_tools/mcp/transports/http.js +58 -1
  81. package/dist/hoi4_agent_tools/mcp/transports/modern-task-routing.js +109 -0
  82. package/dist/hoi4_agent_tools/mcp/transports/negotiated-stdio.js +121 -0
  83. package/dist/hoi4_agent_tools/probability/job-operations.js +58 -0
  84. package/dist/hoi4_agent_tools/probability/operations.js +183 -0
  85. package/dist/hoi4_agent_tools/probability/scenario-state.js +2 -95
  86. package/dist/hoi4_agent_tools/probability/service.js +24 -3
  87. package/dist/hoi4_agent_tools/probability/trigger-evaluator.js +1 -287
  88. package/dist/hoi4_agent_tools/schemas/common.js +2 -0
  89. package/dist/hoi4_agent_tools/schemas/event.js +72 -1
  90. package/dist/hoi4_agent_tools/schemas/focus-requests.js +189 -0
  91. package/dist/hoi4_agent_tools/schemas/gui-requests.js +193 -0
  92. package/dist/hoi4_agent_tools/schemas/helper-expansion.js +58 -0
  93. package/dist/hoi4_agent_tools/schemas/map-requests.js +85 -0
  94. package/dist/hoi4_agent_tools/schemas/probability-requests.js +168 -0
  95. package/dist/hoi4_agent_tools/schemas/technology.js +90 -1
  96. package/dist/hoi4_agent_tools/schemas/transaction.js +1 -0
  97. package/dist/hoi4_agent_tools/technology/graph.js +83 -78
  98. package/dist/hoi4_agent_tools/technology/helper-expansion.js +33 -0
  99. package/dist/hoi4_agent_tools/technology/job-operations.js +60 -0
  100. package/dist/hoi4_agent_tools/technology/operations.js +125 -0
  101. package/dist/hoi4_agent_tools/technology/service.js +89 -15
  102. package/dist/hoi4_agent_tools/technology/source-analysis.js +2 -1
  103. package/dist/hoi4_agent_tools/version.js +1 -1
  104. package/docs/README.md +2 -0
  105. package/docs/development.md +2 -0
  106. package/docs/events.md +7 -2
  107. package/docs/gui.md +3 -1
  108. package/docs/helper-expansion.md +78 -0
  109. package/docs/http.md +2 -0
  110. package/docs/jobs.md +85 -0
  111. package/docs/technology.md +6 -2
  112. package/package.json +11 -5
  113. package/schemas/configuration.schema.json +1 -1
  114. package/schemas/continuous-focus-palette.schema.json +1 -1
  115. package/schemas/custom-weighted-pool.schema.json +1 -1
  116. package/schemas/event-feature-manifest.schema.json +1 -1
  117. package/schemas/focus-plan.schema.json +1 -1
  118. package/schemas/focus-planning-sidecar.schema.json +1 -1
  119. package/schemas/gui-animation-source.schema.json +1 -1
  120. package/schemas/gui-helper.schema.json +1 -1
  121. package/schemas/gui-scenario.schema.json +189 -33
  122. package/schemas/helper-expansion-request.schema.json +44 -0
  123. package/schemas/helper-expansion-summary.schema.json +70 -0
  124. package/schemas/map-operation.schema.json +1 -1
  125. package/schemas/operation-result.schema.json +1 -1
  126. package/schemas/probability-analysis-result.schema.json +1 -1
  127. package/schemas/probability-compare-input.schema.json +1 -1
  128. package/schemas/probability-evaluate-input.schema.json +1 -1
  129. package/schemas/probability-inspect-input.schema.json +1 -1
  130. package/schemas/probability-render-input.schema.json +1 -1
  131. package/schemas/probability-scenario-set.schema.json +1 -1
  132. package/schemas/probability-sequence-input.schema.json +1 -1
  133. package/schemas/probability-simulate-input.schema.json +1 -1
  134. package/schemas/probability-sweep-input.schema.json +1 -1
  135. package/server.json +2 -2
@@ -0,0 +1,193 @@
1
+ import { z } from 'zod/v4';
2
+ import { renderDimensionViolation, RenderBudget, RENDER_MAX_DIMENSION, } from '../core/render-budget.js';
3
+ import { ServiceError } from '../core/result.js';
4
+ import { SOURCE_MAX_BYTES } from '../core/source/index.js';
5
+ import { GUI_TEXT_PACKAGE_MAX_FILES, GuiHelperDocumentSchema } from '../gui/index.js';
6
+ import { GuiGeneratedScenarioOptionsSchema, GuiPreviewScenarioSchema } from '../gui/scenario.js';
7
+ import { backgroundRequestKeySchema, workspaceIdSchema, workspaceRelativePathSchema, } from './common.js';
8
+ function compact(schema, description) {
9
+ return z.unknown().describe(description).pipe(schema);
10
+ }
11
+ const compactGuiScenarioSchema = compact(GuiPreviewScenarioSchema, 'GUI preview scenario.');
12
+ const compactGeneratedScenarioOptionsSchema = compact(GuiGeneratedScenarioOptionsSchema, 'GUI generated-scenario options.');
13
+ const compactGuiHelperSchema = compact(GuiHelperDocumentSchema, 'GUI helper document.');
14
+ export const guiPreviewStateSchema = z.enum([
15
+ 'normal',
16
+ 'hover',
17
+ 'selected',
18
+ 'locked',
19
+ 'disabled',
20
+ 'warning',
21
+ 'active',
22
+ 'completed',
23
+ 'empty-list',
24
+ 'full-list',
25
+ 'minimum-value',
26
+ 'maximum-value',
27
+ 'long-text',
28
+ 'missing-localisation',
29
+ ]);
30
+ export const guiInspectRequestSchema = z
31
+ .object({
32
+ workspaceId: workspaceIdSchema,
33
+ windowName: z.string().min(1).max(256).optional(),
34
+ scenario: compactGuiScenarioSchema.optional(),
35
+ relatedScenarios: z.array(compactGuiScenarioSchema).max(32).optional(),
36
+ generatedScenarios: compactGeneratedScenarioOptionsSchema.optional(),
37
+ })
38
+ .strict()
39
+ .superRefine((value, context) => {
40
+ if ((value.windowName === undefined) !== (value.scenario === undefined))
41
+ context.addIssue({
42
+ code: 'custom',
43
+ message: 'windowName and scenario must be provided together',
44
+ });
45
+ if (value.relatedScenarios !== undefined && value.scenario === undefined)
46
+ context.addIssue({
47
+ code: 'custom',
48
+ path: ['relatedScenarios'],
49
+ message: 'relatedScenarios requires a window scenario',
50
+ });
51
+ if (value.generatedScenarios !== undefined && value.scenario === undefined)
52
+ context.addIssue({
53
+ code: 'custom',
54
+ path: ['generatedScenarios'],
55
+ message: 'generatedScenarios requires a window scenario',
56
+ });
57
+ });
58
+ export const guiResolutionSchema = z
59
+ .object({
60
+ width: z.number().int().min(320).max(RENDER_MAX_DIMENSION),
61
+ height: z.number().int().min(200).max(RENDER_MAX_DIMENSION),
62
+ uiScale: z
63
+ .number()
64
+ .min(0.25)
65
+ .max(4)
66
+ .optional()
67
+ .describe('In-game UI scale for this resolution. Use 1 at 1920x1080; do not use it to enlarge an artifact.'),
68
+ })
69
+ .strict()
70
+ .superRefine(({ width, height }, context) => {
71
+ const violation = renderDimensionViolation(width, height, 'GUI matrix resolution');
72
+ if (violation !== undefined)
73
+ context.addIssue({ code: 'custom', message: `${violation.code}: ${violation.message}` });
74
+ });
75
+ export const guiRenderRequestSchema = z
76
+ .object({
77
+ workspaceId: workspaceIdSchema,
78
+ windowName: z.string().min(1).max(256),
79
+ scenario: compactGuiScenarioSchema,
80
+ states: z.array(guiPreviewStateSchema).max(14).optional(),
81
+ resolutions: z.array(guiResolutionSchema).min(1).max(16).optional(),
82
+ relatedScenarios: z.array(compactGuiScenarioSchema).max(32).optional(),
83
+ generatedScenarios: compactGeneratedScenarioOptionsSchema.optional(),
84
+ comparisonScenario: compactGuiScenarioSchema.optional(),
85
+ })
86
+ .strict()
87
+ .superRefine(({ scenario, states, resolutions, relatedScenarios, generatedScenarios }, context) => {
88
+ const budget = new RenderBudget();
89
+ try {
90
+ const stateCount = states?.length ?? 14;
91
+ for (let index = 0; index < 9 + stateCount; index += 1)
92
+ budget.reserve(scenario.resolution.width, scenario.resolution.height, 'GUI request variant');
93
+ for (const resolution of resolutions ?? [
94
+ { width: 1280, height: 720 },
95
+ { width: 1920, height: 1080 },
96
+ { width: 2560, height: 1440 },
97
+ { width: 1920, height: 1080 },
98
+ ])
99
+ budget.reserve(resolution.width, resolution.height, 'GUI resolution variant');
100
+ const generatedCount = generatedScenarios?.enabled === false ? 0 : (generatedScenarios?.count ?? 1);
101
+ const scenarioCount = generatedCount === 0
102
+ ? 1 + (relatedScenarios?.length ?? 0)
103
+ : generatedCount +
104
+ (generatedScenarios?.preservePlaceholder === false ? 0 : 1) +
105
+ (relatedScenarios?.length ?? 0);
106
+ const stateColumns = Math.min(3, Math.max(1, stateCount));
107
+ const stateRows = Math.max(1, Math.ceil(stateCount / stateColumns));
108
+ budget.reserve(stateColumns * 420, 46 + stateRows * 280, 'GUI state gallery');
109
+ const resolutionCount = resolutions?.length ?? 4;
110
+ const resolutionColumns = Math.min(3, Math.max(1, resolutionCount));
111
+ const resolutionRows = Math.max(1, Math.ceil(resolutionCount / resolutionColumns));
112
+ budget.reserve(resolutionColumns * 420, 46 + resolutionRows * 280, 'GUI resolution gallery');
113
+ const scenarioBudget = new RenderBudget();
114
+ const scenarioColumns = Math.min(3, Math.max(1, scenarioCount));
115
+ const scenarioRows = Math.max(1, Math.ceil(scenarioCount / scenarioColumns));
116
+ scenarioBudget.reserve(scenarioColumns * 420, 46 + scenarioRows * 280, 'GUI scripted scenario gallery');
117
+ }
118
+ catch (error) {
119
+ if (error instanceof ServiceError) {
120
+ context.addIssue({ code: 'custom', message: `${error.code}: ${error.message}` });
121
+ return;
122
+ }
123
+ throw error;
124
+ }
125
+ });
126
+ export const guiRewriteRequestSchema = z
127
+ .object({
128
+ mode: z.enum(['source', 'helpers', 'patches']),
129
+ workspaceId: workspaceIdSchema,
130
+ relativePath: workspaceRelativePathSchema,
131
+ windowName: z.string().min(1).max(256),
132
+ scenario: compactGuiScenarioSchema,
133
+ requestKey: backgroundRequestKeySchema.optional(),
134
+ source: z.string().max(SOURCE_MAX_BYTES).optional(),
135
+ helper: compactGuiHelperSchema.optional(),
136
+ additionalFiles: z
137
+ .array(z
138
+ .object({
139
+ relativePath: workspaceRelativePathSchema,
140
+ source: z.string().max(SOURCE_MAX_BYTES),
141
+ })
142
+ .strict())
143
+ .max(GUI_TEXT_PACKAGE_MAX_FILES - 1)
144
+ .optional(),
145
+ expectedSourceHash: z
146
+ .string()
147
+ .regex(/^[a-f0-9]{64}$/u)
148
+ .optional(),
149
+ patches: z
150
+ .array(z
151
+ .object({
152
+ start: z.number().int().min(0),
153
+ end: z.number().int().min(0),
154
+ expectedText: z.string().max(5_000_000),
155
+ text: z.string().max(5_000_000),
156
+ description: z.string().min(1).max(1000),
157
+ })
158
+ .strict())
159
+ .min(1)
160
+ .max(1000)
161
+ .optional(),
162
+ })
163
+ .strict()
164
+ .superRefine((value, context) => {
165
+ if (value.mode === 'source' && value.source === undefined)
166
+ context.addIssue({ code: 'custom', message: 'source is required in source mode' });
167
+ if (value.mode === 'helpers' && value.helper === undefined)
168
+ context.addIssue({ code: 'custom', message: 'helper is required in helpers mode' });
169
+ if (value.mode === 'patches' &&
170
+ (value.patches === undefined || value.expectedSourceHash === undefined))
171
+ context.addIssue({
172
+ code: 'custom',
173
+ message: 'patches and expectedSourceHash are required in patches mode',
174
+ });
175
+ if (value.mode === 'source' && value.helper !== undefined)
176
+ context.addIssue({ code: 'custom', message: 'helper is forbidden in source mode' });
177
+ if (value.mode === 'helpers' && value.source !== undefined)
178
+ context.addIssue({ code: 'custom', message: 'source is forbidden in helpers mode' });
179
+ if (value.mode !== 'patches' &&
180
+ (value.patches !== undefined || value.expectedSourceHash !== undefined))
181
+ context.addIssue({
182
+ code: 'custom',
183
+ message: 'patch fields are accepted only in patches mode',
184
+ });
185
+ if (value.mode === 'patches' &&
186
+ (value.source !== undefined ||
187
+ value.helper !== undefined ||
188
+ value.additionalFiles !== undefined))
189
+ context.addIssue({
190
+ code: 'custom',
191
+ message: 'source, helper, and additionalFiles are forbidden in patches mode',
192
+ });
193
+ });
@@ -0,0 +1,58 @@
1
+ import { z } from 'zod/v4';
2
+ export const helperExpansionRequestSchema = z
3
+ .object({
4
+ rootIds: z.array(z.string().min(1).max(1_024)).min(1).max(2_000).optional(),
5
+ maxDepth: z.number().int().min(1).max(256).optional(),
6
+ maxRecords: z.number().int().min(1).max(5_000).optional(),
7
+ maxWork: z.number().int().min(1).max(100_000).optional(),
8
+ continuationUri: z
9
+ .string()
10
+ .min(1)
11
+ .max(8_192)
12
+ .regex(/^hoi4-agent:\/\//u)
13
+ .optional(),
14
+ })
15
+ .strict();
16
+ const count = z.number().int().nonnegative().max(Number.MAX_SAFE_INTEGER);
17
+ export const helperExpansionSummarySchema = z
18
+ .object({
19
+ complete: z.boolean(),
20
+ finished: z.boolean(),
21
+ sourceComplete: z.boolean(),
22
+ maxDepth: count,
23
+ records: count,
24
+ totalRecords: count,
25
+ work: count,
26
+ totalWork: count,
27
+ completedRoots: count,
28
+ totalRoots: count,
29
+ cycles: count,
30
+ depthStops: count,
31
+ continuationUri: z
32
+ .string()
33
+ .max(8_192)
34
+ .regex(/^hoi4-agent:\/\//u)
35
+ .optional(),
36
+ })
37
+ .strict();
38
+ /** A dedicated mode must not silently ignore filters belonging to other inspection modes. */
39
+ export function validateHelperExpansionMode(value, context) {
40
+ const fields = value;
41
+ if (fields.mode !== 'helper_expansion') {
42
+ if (fields.helperExpansion !== undefined)
43
+ context.addIssue({
44
+ code: 'custom',
45
+ path: ['helperExpansion'],
46
+ message: 'helperExpansion requires helper_expansion mode',
47
+ });
48
+ return;
49
+ }
50
+ const allowed = new Set(['workspaceId', 'mode', 'helperExpansion', 'refresh']);
51
+ for (const [field, content] of Object.entries(fields))
52
+ if (content !== undefined && !allowed.has(field))
53
+ context.addIssue({
54
+ code: 'custom',
55
+ path: [field],
56
+ message: 'Use helperExpansion rootIds and bounds in helper_expansion mode',
57
+ });
58
+ }
@@ -0,0 +1,85 @@
1
+ import { z } from 'zod/v4';
2
+ import { MAP_PROVINCE_GEOMETRY_SELECTOR_LIMIT } from '../map/limits.js';
3
+ import { backgroundRequestKeySchema, workspaceIdSchema } from './common.js';
4
+ import { mapAllocationRequestSchema, mapOperationSchema } from './map.js';
5
+ function compact(schema, description) {
6
+ return z.unknown().describe(description).pipe(schema);
7
+ }
8
+ const compactMapOperationSchema = compact(mapOperationSchema, 'Complete map operation.');
9
+ export const mapLayerSchema = z.enum([
10
+ 'province',
11
+ 'state',
12
+ 'strategic-region',
13
+ 'terrain',
14
+ 'continent',
15
+ 'owner',
16
+ 'controller',
17
+ 'cores',
18
+ 'claims',
19
+ 'coast',
20
+ ]);
21
+ export const mapOverlaySchema = z.enum([
22
+ 'coastlines',
23
+ 'ports',
24
+ 'victory-points',
25
+ 'resources',
26
+ 'state-buildings',
27
+ 'province-buildings',
28
+ 'supply-nodes',
29
+ 'railways',
30
+ 'adjacencies',
31
+ 'building-positions',
32
+ 'unit-positions',
33
+ 'weather-positions',
34
+ ]);
35
+ export const mapInspectRequestSchema = z
36
+ .object({
37
+ workspaceId: workspaceIdSchema,
38
+ provinceIds: z
39
+ .array(z.number().int().min(0))
40
+ .max(MAP_PROVINCE_GEOMETRY_SELECTOR_LIMIT)
41
+ .default([])
42
+ .describe(`Export row runs for up to ${MAP_PROVINCE_GEOMETRY_SELECTOR_LIMIT} province IDs`),
43
+ stateIds: z.array(z.number().int().positive()).max(1_000).default([]),
44
+ regionIds: z.array(z.number().int().positive()).max(1_000).default([]),
45
+ query: z.string().max(256).optional(),
46
+ queryLimit: z.number().int().min(1).max(1_000).default(100),
47
+ coordinates: z
48
+ .array(z.discriminatedUnion('kind', [
49
+ z
50
+ .object({
51
+ kind: z.literal('pixel'),
52
+ x: z.number().int().min(0),
53
+ y: z.number().int().min(0),
54
+ })
55
+ .strict(),
56
+ z
57
+ .object({
58
+ kind: z.literal('map'),
59
+ x: z.number(),
60
+ z: z.number(),
61
+ })
62
+ .strict(),
63
+ ]))
64
+ .max(100)
65
+ .default([]),
66
+ includeOverview: z.boolean().default(true),
67
+ allocationRequests: z.array(mapAllocationRequestSchema).max(100).default([]),
68
+ })
69
+ .strict();
70
+ export const mapRenderRequestSchema = z
71
+ .object({
72
+ workspaceId: workspaceIdSchema,
73
+ layer: mapLayerSchema.optional(),
74
+ overlays: z.array(mapOverlaySchema).max(12).optional(),
75
+ scale: z.number().int().min(1).max(16).optional(),
76
+ })
77
+ .strict();
78
+ export const mapRewriteRequestSchema = z
79
+ .object({
80
+ workspaceId: workspaceIdSchema,
81
+ operations: z.array(compactMapOperationSchema).min(1).max(100),
82
+ diffScale: z.number().int().min(1).max(16).optional(),
83
+ requestKey: backgroundRequestKeySchema.optional(),
84
+ })
85
+ .strict();
@@ -0,0 +1,168 @@
1
+ import { z } from 'zod/v4';
2
+ import { customWeightedPoolManifestSchema, probabilityAcceptanceBandSchema, probabilityAdapterIdSchema, probabilityDiagnosticThresholdsSchema, probabilityMetricSchema, probabilityOutputSchema, probabilityRenderFilterSchema, probabilityScenarioSetSchema, probabilitySamplingMethodSchema, probabilitySourceSchema, } from './probability.js';
3
+ import { workspaceIdSchema } from './common.js';
4
+ function compact(schema, description) {
5
+ return z.unknown().describe(description).pipe(schema);
6
+ }
7
+ const nestedSource = compact(probabilitySourceSchema, 'Source selector or proposed source.');
8
+ const nestedScenarios = compact(probabilityScenarioSetSchema, 'Explicit world-state scenarios.');
9
+ const nestedManifest = compact(customWeightedPoolManifestSchema, 'Declared custom weighted pool and state transitions.');
10
+ const nestedRenderFilter = compact(probabilityRenderFilterSchema, 'Optional scenario, candidate, metric, diagnostic, source, and page filter.');
11
+ const nestedAcceptanceBands = compact(z.array(probabilityAcceptanceBandSchema).max(100_000), 'Optional named metric acceptance bands.');
12
+ const nestedDiagnosticThresholds = compact(probabilityDiagnosticThresholdsSchema, 'Optional diagnostic thresholds.');
13
+ const candidatePool = z.array(z.string().min(1).max(512)).max(100_000).optional();
14
+ const outputs = z.array(probabilityOutputSchema).max(10).optional();
15
+ const commonShape = {
16
+ workspaceId: workspaceIdSchema,
17
+ adapter: probabilityAdapterIdSchema.optional(),
18
+ scenarioSet: nestedScenarios,
19
+ candidatePool,
20
+ horizonDays: z.number().positive().max(1_000_000).optional(),
21
+ metrics: z.array(probabilityMetricSchema).min(1).max(4).optional(),
22
+ acceptanceBands: nestedAcceptanceBands.optional(),
23
+ diagnosticThresholds: nestedDiagnosticThresholds.optional(),
24
+ outputs,
25
+ refresh: z.boolean().optional(),
26
+ };
27
+ export const probabilityInspectRequestSchema = z
28
+ .object({
29
+ workspaceId: workspaceIdSchema,
30
+ adapter: probabilityAdapterIdSchema.optional(),
31
+ source: nestedSource.optional(),
32
+ customPoolManifest: nestedManifest.optional(),
33
+ candidatePool,
34
+ refresh: z.boolean().optional(),
35
+ })
36
+ .strict()
37
+ .superRefine((value, context) => {
38
+ if (value.source !== undefined && value.customPoolManifest !== undefined)
39
+ context.addIssue({ code: 'custom', message: 'Provide either source or customPoolManifest' });
40
+ if (value.adapter !== undefined &&
41
+ value.source === undefined &&
42
+ value.customPoolManifest === undefined)
43
+ context.addIssue({
44
+ code: 'custom',
45
+ message: 'An adapter requires a source; provide a source alone to discover compatible adapters',
46
+ });
47
+ if (value.customPoolManifest !== undefined &&
48
+ value.adapter !== undefined &&
49
+ value.adapter !== 'custom_weighted_pool')
50
+ context.addIssue({
51
+ code: 'custom',
52
+ path: ['adapter'],
53
+ message: 'customPoolManifest requires adapter custom_weighted_pool',
54
+ });
55
+ });
56
+ export const probabilityEvaluateRequestSchema = z
57
+ .object({
58
+ ...commonShape,
59
+ source: nestedSource.optional(),
60
+ customPoolManifest: nestedManifest.optional(),
61
+ })
62
+ .strict()
63
+ .superRefine((value, context) => {
64
+ if ((value.source === undefined) === (value.customPoolManifest === undefined))
65
+ context.addIssue({
66
+ code: 'custom',
67
+ message: 'Provide exactly one source or customPoolManifest',
68
+ });
69
+ if (value.customPoolManifest !== undefined &&
70
+ value.adapter !== undefined &&
71
+ value.adapter !== 'custom_weighted_pool')
72
+ context.addIssue({
73
+ code: 'custom',
74
+ path: ['adapter'],
75
+ message: 'customPoolManifest requires adapter custom_weighted_pool',
76
+ });
77
+ });
78
+ export const probabilitySweepRequestSchema = z
79
+ .object({
80
+ ...commonShape,
81
+ source: nestedSource,
82
+ sweep: z
83
+ .object({
84
+ paths: z.array(z.string().min(1).max(1024)).min(1).max(32),
85
+ steps: z.number().int().min(2).max(10_000).default(25),
86
+ pairwise: z.boolean().default(false),
87
+ findRankReversals: z.boolean().default(true),
88
+ })
89
+ .strict(),
90
+ })
91
+ .strict();
92
+ export const probabilitySimulateRequestSchema = z
93
+ .object({
94
+ ...commonShape,
95
+ source: nestedSource,
96
+ samples: z.number().int().min(100).max(10_000_000).default(100_000),
97
+ seed: z.number().int().min(-2_147_483_648).max(2_147_483_647).default(1),
98
+ confidenceLevel: z.number().min(0.5).max(0.9999).default(0.95),
99
+ samplingMethod: probabilitySamplingMethodSchema.default('latin_hypercube'),
100
+ })
101
+ .strict();
102
+ export const probabilitySequenceRequestSchema = z
103
+ .object({
104
+ workspaceId: workspaceIdSchema,
105
+ scenarioSet: nestedScenarios,
106
+ customPoolManifest: nestedManifest,
107
+ horizonDays: z.number().positive().max(1_000_000),
108
+ maxSteps: z.number().int().min(1).max(100_000).default(1_000),
109
+ samples: z.number().int().min(100).max(10_000_000).default(100_000),
110
+ seed: z.number().int().min(-2_147_483_648).max(2_147_483_647).default(1),
111
+ confidenceLevel: z.number().min(0.5).max(0.9999).default(0.95),
112
+ acceptanceBands: nestedAcceptanceBands.optional(),
113
+ diagnosticThresholds: nestedDiagnosticThresholds.optional(),
114
+ outputs,
115
+ })
116
+ .strict();
117
+ export const probabilityCompareRequestSchema = z
118
+ .object({
119
+ workspaceId: workspaceIdSchema,
120
+ adapter: probabilityAdapterIdSchema.optional(),
121
+ before: nestedSource.optional(),
122
+ after: nestedSource.optional(),
123
+ beforeManifest: nestedManifest.optional(),
124
+ afterManifest: nestedManifest.optional(),
125
+ scenarioSet: nestedScenarios,
126
+ candidatePool,
127
+ horizonDays: z.number().positive().max(1_000_000).optional(),
128
+ acceptanceBands: nestedAcceptanceBands.optional(),
129
+ diagnosticThresholds: nestedDiagnosticThresholds.optional(),
130
+ outputs,
131
+ refresh: z.boolean().optional(),
132
+ })
133
+ .strict()
134
+ .superRefine((value, context) => {
135
+ const sourceMode = value.before !== undefined || value.after !== undefined;
136
+ const manifestMode = value.beforeManifest !== undefined || value.afterManifest !== undefined;
137
+ if (sourceMode === manifestMode)
138
+ context.addIssue({
139
+ code: 'custom',
140
+ message: 'Compare either before/after sources or beforeManifest/afterManifest',
141
+ });
142
+ if (sourceMode && (value.before === undefined || value.after === undefined))
143
+ context.addIssue({ code: 'custom', message: 'Source comparison requires before and after' });
144
+ if (manifestMode && (value.beforeManifest === undefined || value.afterManifest === undefined))
145
+ context.addIssue({
146
+ code: 'custom',
147
+ message: 'Custom-pool comparison requires beforeManifest and afterManifest',
148
+ });
149
+ if (manifestMode && value.adapter !== undefined && value.adapter !== 'custom_weighted_pool')
150
+ context.addIssue({
151
+ code: 'custom',
152
+ path: ['adapter'],
153
+ message: 'Manifest comparison requires adapter custom_weighted_pool',
154
+ });
155
+ });
156
+ export const probabilityRenderRequestSchema = z
157
+ .object({
158
+ workspaceId: workspaceIdSchema,
159
+ analysisId: z.string().min(1).max(256),
160
+ expectedScenarioHash: z
161
+ .string()
162
+ .regex(/^[a-f0-9]{64}$/u)
163
+ .optional(),
164
+ outputs: z.array(probabilityOutputSchema).min(1).max(10),
165
+ includeHtml: z.boolean().default(false),
166
+ filter: nestedRenderFilter.optional(),
167
+ })
168
+ .strict();
@@ -1,6 +1,7 @@
1
1
  import { z } from 'zod/v4';
2
2
  import { SOURCE_MAX_BYTES } from '../core/source/index.js';
3
- import { workspaceRelativePathSchema } from './common.js';
3
+ import { workspaceIdSchema, workspaceRelativePathSchema } from './common.js';
4
+ import { helperExpansionRequestSchema, validateHelperExpansionMode } from './helper-expansion.js';
4
5
  export const technologyIdSchema = z.string().min(1).max(512);
5
6
  export const technologyDirectionSchema = z.enum(['prerequisites', 'descendants', 'both']);
6
7
  export const technologyUnlockKindSchema = z.enum([
@@ -75,3 +76,91 @@ export const technologyProposedSourceSchema = z
75
76
  .optional(),
76
77
  })
77
78
  .strict();
79
+ export const technologyAnalysisModeSchema = z.enum([
80
+ 'scan',
81
+ 'folders',
82
+ 'trace',
83
+ 'explain',
84
+ 'unlocks',
85
+ 'bonus_coverage',
86
+ 'lint',
87
+ 'impact',
88
+ 'helper_expansion',
89
+ ]);
90
+ export function validateTechnologyInspectRequest(value, context) {
91
+ validateHelperExpansionMode(value, context);
92
+ if ((value.mode === 'trace' || value.mode === 'explain') && value.technologyId === undefined)
93
+ context.addIssue({
94
+ code: 'custom',
95
+ path: ['technologyId'],
96
+ message: `${value.mode} requires technologyId`,
97
+ });
98
+ if (value.mode === 'impact' && value.impact === undefined)
99
+ context.addIssue({
100
+ code: 'custom',
101
+ path: ['impact'],
102
+ message: 'Impact mode requires impact',
103
+ });
104
+ }
105
+ export const technologyInspectRequestSchema = z
106
+ .object({
107
+ workspaceId: workspaceIdSchema,
108
+ mode: technologyAnalysisModeSchema,
109
+ folderId: technologyIdSchema.optional(),
110
+ technologyId: technologyIdSchema.optional(),
111
+ categoryId: technologyIdSchema.optional(),
112
+ targetKind: technologyUnlockKindSchema.optional(),
113
+ targetId: technologyIdSchema.optional(),
114
+ direction: technologyDirectionSchema.optional(),
115
+ maxDepth: z.number().int().min(1).max(256).optional(),
116
+ maxNodes: z.number().int().min(1).max(25_000).optional(),
117
+ includeSubTechnologies: z.boolean().optional(),
118
+ classifications: z.array(technologyDefectClassSchema).max(4).optional(),
119
+ codes: z.array(z.string().min(1).max(256)).max(100).optional(),
120
+ impact: technologyImpactSchema.optional(),
121
+ helperExpansion: helperExpansionRequestSchema.optional(),
122
+ refresh: z.boolean().optional(),
123
+ })
124
+ .strict()
125
+ .superRefine(validateTechnologyInspectRequest);
126
+ export const technologyRenderRequestSchema = z
127
+ .object({
128
+ workspaceId: workspaceIdSchema,
129
+ view: technologyRenderViewSchema.exclude(['comparison']),
130
+ folderId: technologyIdSchema.optional(),
131
+ technologyId: technologyIdSchema.optional(),
132
+ categoryId: technologyIdSchema.optional(),
133
+ targetId: technologyIdSchema.optional(),
134
+ maxNodes: z.number().int().min(1).max(2_000).optional(),
135
+ includeHtml: z.boolean().optional(),
136
+ refresh: z.boolean().optional(),
137
+ })
138
+ .strict()
139
+ .superRefine((value, context) => {
140
+ if (value.view === 'folder' && value.folderId === undefined)
141
+ context.addIssue({
142
+ code: 'custom',
143
+ path: ['folderId'],
144
+ message: 'Folder view requires folderId',
145
+ });
146
+ });
147
+ export function validateTechnologyCompareRequest(value, context) {
148
+ if (value.after !== undefined && value.proposedSources !== undefined)
149
+ context.addIssue({
150
+ code: 'custom',
151
+ path: ['after'],
152
+ message: 'after conflicts with proposedSources',
153
+ });
154
+ }
155
+ export const technologyCompareRequestSchema = z
156
+ .object({
157
+ workspaceId: workspaceIdSchema,
158
+ before: technologyGraphReferenceSchema.optional(),
159
+ after: technologyGraphReferenceSchema.optional(),
160
+ proposedSources: z.array(technologyProposedSourceSchema).min(1).max(128).optional(),
161
+ render: z.boolean().optional(),
162
+ maxRenderNodes: z.number().int().min(1).max(2_000).optional(),
163
+ refresh: z.boolean().optional(),
164
+ })
165
+ .strict()
166
+ .superRefine(validateTechnologyCompareRequest);
@@ -96,6 +96,7 @@ export const transactionManifestSchema = z
96
96
  diagnostics: z.array(diagnosticSchema).max(TRANSACTION_MAX_DIAGNOSTICS),
97
97
  validation: validationSummarySchema,
98
98
  artifacts: z.array(artifactLinkSchema).max(TRANSACTION_MAX_ARTIFACTS),
99
+ executionArtifacts: z.array(artifactLinkSchema).max(TRANSACTION_MAX_ARTIFACTS).optional(),
99
100
  appliedFiles: z.array(workspaceRelativePathSchema).max(TRANSACTION_MAX_APPLIED_FILES),
100
101
  rollbackStatus: z.enum(['available', 'applied', 'failed']),
101
102
  failure: z.object({ code: identifierSchema, message: summarySchema }).strict().optional(),