@godot-mcp/control-plane 0.0.0 → 0.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 (156) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +105 -2
  3. package/dist/audit/jsonlAuditSink.d.ts +33 -0
  4. package/dist/audit/jsonlAuditSink.d.ts.map +1 -0
  5. package/dist/audit/jsonlAuditSink.js +57 -0
  6. package/dist/audit/jsonlAuditSink.js.map +1 -0
  7. package/dist/audit/redact.d.ts +2 -0
  8. package/dist/audit/redact.d.ts.map +1 -0
  9. package/dist/audit/redact.js +44 -0
  10. package/dist/audit/redact.js.map +1 -0
  11. package/dist/auth/pairingDescriptor.d.ts +44 -0
  12. package/dist/auth/pairingDescriptor.d.ts.map +1 -0
  13. package/dist/auth/pairingDescriptor.js +91 -0
  14. package/dist/auth/pairingDescriptor.js.map +1 -0
  15. package/dist/auth/runtimeDirectory.d.ts +3 -0
  16. package/dist/auth/runtimeDirectory.d.ts.map +1 -0
  17. package/dist/auth/runtimeDirectory.js +30 -0
  18. package/dist/auth/runtimeDirectory.js.map +1 -0
  19. package/dist/auth/sessionCrypto.d.ts +18 -0
  20. package/dist/auth/sessionCrypto.d.ts.map +1 -0
  21. package/dist/auth/sessionCrypto.js +118 -0
  22. package/dist/auth/sessionCrypto.js.map +1 -0
  23. package/dist/editor/editorMutationService.d.ts +21 -0
  24. package/dist/editor/editorMutationService.d.ts.map +1 -0
  25. package/dist/editor/editorMutationService.js +120 -0
  26. package/dist/editor/editorMutationService.js.map +1 -0
  27. package/dist/editor/mutationLedger.d.ts +30 -0
  28. package/dist/editor/mutationLedger.d.ts.map +1 -0
  29. package/dist/editor/mutationLedger.js +133 -0
  30. package/dist/editor/mutationLedger.js.map +1 -0
  31. package/dist/errors.d.ts +12 -0
  32. package/dist/errors.d.ts.map +1 -0
  33. package/dist/errors.js +23 -0
  34. package/dist/errors.js.map +1 -0
  35. package/dist/evidence/evidenceStore.d.ts +63 -0
  36. package/dist/evidence/evidenceStore.d.ts.map +1 -0
  37. package/dist/evidence/evidenceStore.js +350 -0
  38. package/dist/evidence/evidenceStore.js.map +1 -0
  39. package/dist/extensions/extensionRegistry.d.ts +33 -0
  40. package/dist/extensions/extensionRegistry.d.ts.map +1 -0
  41. package/dist/extensions/extensionRegistry.js +37 -0
  42. package/dist/extensions/extensionRegistry.js.map +1 -0
  43. package/dist/help/coreHelp.d.ts +10 -0
  44. package/dist/help/coreHelp.d.ts.map +1 -0
  45. package/dist/help/coreHelp.js +82 -0
  46. package/dist/help/coreHelp.js.map +1 -0
  47. package/dist/index.d.ts +37 -0
  48. package/dist/index.d.ts.map +1 -0
  49. package/dist/index.js +37 -0
  50. package/dist/index.js.map +1 -0
  51. package/dist/policy/authorize.d.ts +5 -0
  52. package/dist/policy/authorize.d.ts.map +1 -0
  53. package/dist/policy/authorize.js +19 -0
  54. package/dist/policy/authorize.js.map +1 -0
  55. package/dist/policy/capabilities.d.ts +36 -0
  56. package/dist/policy/capabilities.d.ts.map +1 -0
  57. package/dist/policy/capabilities.js +129 -0
  58. package/dist/policy/capabilities.js.map +1 -0
  59. package/dist/project/artifactStore.d.ts +32 -0
  60. package/dist/project/artifactStore.d.ts.map +1 -0
  61. package/dist/project/artifactStore.js +172 -0
  62. package/dist/project/artifactStore.js.map +1 -0
  63. package/dist/project/pathPolicy.d.ts +4 -0
  64. package/dist/project/pathPolicy.d.ts.map +1 -0
  65. package/dist/project/pathPolicy.js +74 -0
  66. package/dist/project/pathPolicy.js.map +1 -0
  67. package/dist/project/projectConfig.d.ts +10 -0
  68. package/dist/project/projectConfig.d.ts.map +1 -0
  69. package/dist/project/projectConfig.js +63 -0
  70. package/dist/project/projectConfig.js.map +1 -0
  71. package/dist/project/projectIdentity.d.ts +8 -0
  72. package/dist/project/projectIdentity.d.ts.map +1 -0
  73. package/dist/project/projectIdentity.js +58 -0
  74. package/dist/project/projectIdentity.js.map +1 -0
  75. package/dist/project/projectJobJournal.d.ts +49 -0
  76. package/dist/project/projectJobJournal.d.ts.map +1 -0
  77. package/dist/project/projectJobJournal.js +67 -0
  78. package/dist/project/projectJobJournal.js.map +1 -0
  79. package/dist/project/projectJobService.d.ts +52 -0
  80. package/dist/project/projectJobService.d.ts.map +1 -0
  81. package/dist/project/projectJobService.js +289 -0
  82. package/dist/project/projectJobService.js.map +1 -0
  83. package/dist/project/projectMutationService.d.ts +40 -0
  84. package/dist/project/projectMutationService.d.ts.map +1 -0
  85. package/dist/project/projectMutationService.js +145 -0
  86. package/dist/project/projectMutationService.js.map +1 -0
  87. package/dist/project/projectPreflight.d.ts +7 -0
  88. package/dist/project/projectPreflight.d.ts.map +1 -0
  89. package/dist/project/projectPreflight.js +50 -0
  90. package/dist/project/projectPreflight.js.map +1 -0
  91. package/dist/project/projectProcess.d.ts +40 -0
  92. package/dist/project/projectProcess.d.ts.map +1 -0
  93. package/dist/project/projectProcess.js +196 -0
  94. package/dist/project/projectProcess.js.map +1 -0
  95. package/dist/project/projectService.d.ts +20 -0
  96. package/dist/project/projectService.d.ts.map +1 -0
  97. package/dist/project/projectService.js +35 -0
  98. package/dist/project/projectService.js.map +1 -0
  99. package/dist/project/secureJournalFile.d.ts +3 -0
  100. package/dist/project/secureJournalFile.d.ts.map +1 -0
  101. package/dist/project/secureJournalFile.js +56 -0
  102. package/dist/project/secureJournalFile.js.map +1 -0
  103. package/dist/runtime/debugTokenStore.d.ts +41 -0
  104. package/dist/runtime/debugTokenStore.d.ts.map +1 -0
  105. package/dist/runtime/debugTokenStore.js +105 -0
  106. package/dist/runtime/debugTokenStore.js.map +1 -0
  107. package/dist/runtime/debuggerClient.d.ts +14 -0
  108. package/dist/runtime/debuggerClient.d.ts.map +1 -0
  109. package/dist/runtime/debuggerClient.js +21 -0
  110. package/dist/runtime/debuggerClient.js.map +1 -0
  111. package/dist/runtime/inputReceipt.d.ts +15 -0
  112. package/dist/runtime/inputReceipt.d.ts.map +1 -0
  113. package/dist/runtime/inputReceipt.js +36 -0
  114. package/dist/runtime/inputReceipt.js.map +1 -0
  115. package/dist/runtime/runtimeDescriptor.d.ts +50 -0
  116. package/dist/runtime/runtimeDescriptor.d.ts.map +1 -0
  117. package/dist/runtime/runtimeDescriptor.js +175 -0
  118. package/dist/runtime/runtimeDescriptor.js.map +1 -0
  119. package/dist/runtime/runtimeProcess.d.ts +39 -0
  120. package/dist/runtime/runtimeProcess.d.ts.map +1 -0
  121. package/dist/runtime/runtimeProcess.js +180 -0
  122. package/dist/runtime/runtimeProcess.js.map +1 -0
  123. package/dist/runtime/runtimeService.d.ts +130 -0
  124. package/dist/runtime/runtimeService.d.ts.map +1 -0
  125. package/dist/runtime/runtimeService.js +919 -0
  126. package/dist/runtime/runtimeService.js.map +1 -0
  127. package/dist/session/sessionService.d.ts +52 -0
  128. package/dist/session/sessionService.d.ts.map +1 -0
  129. package/dist/session/sessionService.js +72 -0
  130. package/dist/session/sessionService.js.map +1 -0
  131. package/dist/unsafe/unsafeFixtureAuthority.d.ts +27 -0
  132. package/dist/unsafe/unsafeFixtureAuthority.d.ts.map +1 -0
  133. package/dist/unsafe/unsafeFixtureAuthority.js +130 -0
  134. package/dist/unsafe/unsafeFixtureAuthority.js.map +1 -0
  135. package/dist/unsafe/unsafeFixtureProcess.d.ts +30 -0
  136. package/dist/unsafe/unsafeFixtureProcess.d.ts.map +1 -0
  137. package/dist/unsafe/unsafeFixtureProcess.js +119 -0
  138. package/dist/unsafe/unsafeFixtureProcess.js.map +1 -0
  139. package/dist/unsafe/unsafeFixtureService.d.ts +41 -0
  140. package/dist/unsafe/unsafeFixtureService.d.ts.map +1 -0
  141. package/dist/unsafe/unsafeFixtureService.js +162 -0
  142. package/dist/unsafe/unsafeFixtureService.js.map +1 -0
  143. package/dist/visual/pngComparison.d.ts +12 -0
  144. package/dist/visual/pngComparison.d.ts.map +1 -0
  145. package/dist/visual/pngComparison.js +136 -0
  146. package/dist/visual/pngComparison.js.map +1 -0
  147. package/dist/visual/scenarioService.d.ts +50 -0
  148. package/dist/visual/scenarioService.d.ts.map +1 -0
  149. package/dist/visual/scenarioService.js +421 -0
  150. package/dist/visual/scenarioService.js.map +1 -0
  151. package/dist/visual/visualService.d.ts +27 -0
  152. package/dist/visual/visualService.d.ts.map +1 -0
  153. package/dist/visual/visualService.js +70 -0
  154. package/dist/visual/visualService.js.map +1 -0
  155. package/package.json +26 -6
  156. package/index.js +0 -1
@@ -0,0 +1,421 @@
1
+ import { createHash, randomBytes, randomUUID } from "node:crypto";
2
+ import { canonicalJson, RuntimeCaptureFrameMetadataSchema, RuntimeLaunchPinsSchema, ScenarioDeclarationSchema, ScenarioJobReceiptSchema, ScenarioReportSchema, VisualComparisonResultSchema, } from "@godot-mcp/protocol";
3
+ import { GodotMcpException } from "../errors.js";
4
+ import { comparePng } from "./pngComparison.js";
5
+ function scenarioError(code, message, evidence = []) {
6
+ const error = new GodotMcpException({
7
+ code,
8
+ message,
9
+ retryable: false,
10
+ correlationId: randomUUID(),
11
+ partialEffects: false,
12
+ rollback: "not_needed",
13
+ });
14
+ return evidence.length === 0 ? error : Object.assign(error, { evidence: [...evidence] });
15
+ }
16
+ function isRecord(value) {
17
+ return typeof value === "object" && value !== null && !Array.isArray(value);
18
+ }
19
+ function errorCode(error) {
20
+ return isRecord(error) && typeof error.code === "string" ? error.code : "GODOT_RUNTIME_ERROR";
21
+ }
22
+ function errorEvidence(error) {
23
+ if (!isRecord(error) || !Array.isArray(error.evidence))
24
+ return [];
25
+ return error.evidence.filter((entry) => typeof entry === "string" && entry.startsWith("godot-mcp://evidence/"));
26
+ }
27
+ function rethrowIfInterrupted(error) {
28
+ if (errorCode(error) === "CANCELLED" || errorCode(error) === "TIMEOUT")
29
+ throw error;
30
+ }
31
+ function digest(value) {
32
+ return createHash("sha256").update(canonicalJson(value)).digest("hex");
33
+ }
34
+ function wildcardMatches(value, pattern) {
35
+ const escaped = pattern.replace(/[.*+?^${}()|[\]\\]/g, "\\$&").replace(/\\\*/g, ".*").replace(/\\\?/g, ".");
36
+ return new RegExp(`^${escaped}$`, "u").test(value);
37
+ }
38
+ export class ScenarioService {
39
+ dependencies;
40
+ job;
41
+ now;
42
+ constructor(dependencies) {
43
+ this.dependencies = dependencies;
44
+ this.now = dependencies.now ?? (() => Date.now());
45
+ }
46
+ hasActiveJob() {
47
+ return this.job !== undefined && (this.job.state === "queued" || this.job.state === "running");
48
+ }
49
+ start(input) {
50
+ if (this.job && (this.job.state === "queued" || this.job.state === "running")) {
51
+ throw scenarioError("CONFLICT", "A visual scenario job is already active");
52
+ }
53
+ const sessionId = this.dependencies.sessionId();
54
+ if (!sessionId)
55
+ throw scenarioError("NOT_ATTACHED", "Godot editor addon is not attached");
56
+ const scenario = ScenarioDeclarationSchema.parse(input);
57
+ const token = `vsj_${randomBytes(32).toString("base64url")}`;
58
+ const startedAtMs = Math.floor(this.now());
59
+ const job = {
60
+ token,
61
+ sessionId,
62
+ scenario,
63
+ state: "queued",
64
+ completedSteps: 0,
65
+ controller: new AbortController(),
66
+ startedAtMs,
67
+ deadlineAtMs: startedAtMs + scenario.deadlineMs,
68
+ };
69
+ this.job = job;
70
+ queueMicrotask(() => void this.run(job));
71
+ return this.receipt(job);
72
+ }
73
+ status(jobToken) {
74
+ return this.receipt(this.requireJob(jobToken));
75
+ }
76
+ cancel(jobToken) {
77
+ const job = this.requireJob(jobToken);
78
+ if (job.state === "queued" || job.state === "running") {
79
+ job.controller.abort(scenarioError("CANCELLED", "Visual scenario was cancelled"));
80
+ }
81
+ return this.receipt(job);
82
+ }
83
+ result(jobToken) {
84
+ const job = this.requireJob(jobToken);
85
+ if (!job.report)
86
+ throw scenarioError("CONFLICT", "Visual scenario result is not terminal");
87
+ return ScenarioReportSchema.parse(job.report);
88
+ }
89
+ async close() {
90
+ const job = this.job;
91
+ if (!job || !["queued", "running"].includes(job.state))
92
+ return;
93
+ job.controller.abort(scenarioError("CANCELLED", "Visual scenario service closed"));
94
+ for (let attempt = 0; attempt < 200 && !job.report; attempt += 1) {
95
+ await new Promise((resolve) => setTimeout(resolve, 5));
96
+ }
97
+ }
98
+ requireJob(jobToken) {
99
+ const job = this.job;
100
+ if (!job || job.token !== jobToken || this.dependencies.sessionId() !== job.sessionId) {
101
+ throw scenarioError("STALE_HANDLE", "Visual scenario job token is stale or belongs to another session");
102
+ }
103
+ return job;
104
+ }
105
+ receipt(job) {
106
+ return ScenarioJobReceiptSchema.parse({
107
+ jobToken: job.token,
108
+ state: job.state,
109
+ completedSteps: job.completedSteps,
110
+ totalSteps: job.scenario.steps.length,
111
+ });
112
+ }
113
+ async run(job) {
114
+ if (this.job !== job)
115
+ return;
116
+ job.state = "running";
117
+ let handle;
118
+ let observedGodotVersion;
119
+ let observedPins;
120
+ let paused = false;
121
+ let terminalState = "failed";
122
+ let failedStepIndex = null;
123
+ let cleanup = "not_needed";
124
+ const stepReceipts = [];
125
+ const captures = new Map();
126
+ try {
127
+ this.assertJobActive(job);
128
+ const launchPromise = this.dependencies.runtime.launch({
129
+ scenePath: job.scenario.scenePath,
130
+ startupTimeoutMs: job.scenario.startupTimeoutMs,
131
+ pins: job.scenario.pins,
132
+ });
133
+ const adoptLaunch = (launched) => {
134
+ handle = launched.handle;
135
+ if (isRecord(launched.root) && typeof launched.root.godotVersion === "string")
136
+ observedGodotVersion = launched.root.godotVersion;
137
+ if (isRecord(launched.root)) {
138
+ const parsedObservedPins = RuntimeLaunchPinsSchema.safeParse(launched.root.observedPins);
139
+ if (parsedObservedPins.success)
140
+ observedPins = parsedObservedPins.data;
141
+ }
142
+ };
143
+ try {
144
+ adoptLaunch(await this.boundary(job, launchPromise));
145
+ }
146
+ catch (error) {
147
+ if (errorCode(error) === "CANCELLED" || errorCode(error) === "TIMEOUT") {
148
+ try {
149
+ adoptLaunch(await launchPromise);
150
+ }
151
+ catch {
152
+ // Runtime launch owns cleanup when it rejects before yielding a handle.
153
+ }
154
+ }
155
+ throw error;
156
+ }
157
+ const activeHandle = handle;
158
+ if (!activeHandle)
159
+ throw scenarioError("GODOT_RUNTIME_ERROR", "Runtime launch did not yield a handle");
160
+ for (const [index, step] of job.scenario.steps.entries()) {
161
+ const startedMonotonicMs = Math.max(0, Math.floor(this.now() - job.startedAtMs));
162
+ try {
163
+ const outcome = await this.runStep(job, activeHandle, step, captures, paused);
164
+ paused = outcome.paused;
165
+ const finishedMonotonicMs = Math.max(startedMonotonicMs, Math.floor(this.now() - job.startedAtMs));
166
+ stepReceipts.push({
167
+ index,
168
+ kind: step.kind,
169
+ state: "completed",
170
+ startedMonotonicMs,
171
+ finishedMonotonicMs,
172
+ summary: outcome.summary,
173
+ evidence: outcome.evidence,
174
+ });
175
+ job.completedSteps += 1;
176
+ }
177
+ catch (error) {
178
+ failedStepIndex = index;
179
+ const cancelled = errorCode(error) === "CANCELLED";
180
+ const finishedMonotonicMs = Math.max(startedMonotonicMs, Math.floor(this.now() - job.startedAtMs));
181
+ stepReceipts.push({
182
+ index,
183
+ kind: step.kind,
184
+ state: cancelled ? "cancelled" : "failed",
185
+ startedMonotonicMs,
186
+ finishedMonotonicMs,
187
+ summary: { errorCode: errorCode(error) },
188
+ evidence: errorEvidence(error),
189
+ });
190
+ throw error;
191
+ }
192
+ }
193
+ terminalState = "completed";
194
+ }
195
+ catch (error) {
196
+ terminalState = errorCode(error) === "CANCELLED" ? "cancelled" : "failed";
197
+ }
198
+ finally {
199
+ if (handle) {
200
+ try {
201
+ await this.dependencies.runtime.execute({ operation: "stop", handle });
202
+ cleanup = "succeeded";
203
+ }
204
+ catch {
205
+ cleanup = "failed";
206
+ terminalState = "failed";
207
+ }
208
+ }
209
+ const reportWithoutDigest = {
210
+ schemaVersion: 1,
211
+ comparisonContractVersion: 1,
212
+ jobToken: job.token,
213
+ scenarioName: job.scenario.name,
214
+ projectId: this.dependencies.projectId,
215
+ scenePath: job.scenario.scenePath,
216
+ ...(handle ? { handle } : {}),
217
+ pins: job.scenario.pins,
218
+ ...(observedGodotVersion ? { observedGodotVersion } : {}),
219
+ ...(observedPins ? { observedPins } : {}),
220
+ state: terminalState,
221
+ failedStepIndex,
222
+ steps: stepReceipts,
223
+ durationMs: Math.min(job.scenario.deadlineMs, Math.max(0, Math.floor(this.now() - job.startedAtMs))),
224
+ cleanup,
225
+ };
226
+ let report = ScenarioReportSchema.parse({ ...reportWithoutDigest, reportSha256: digest(reportWithoutDigest) });
227
+ try {
228
+ const evidence = await this.dependencies.evidence.putJson(job.sessionId, report, { kind: "scenario_report" });
229
+ report = ScenarioReportSchema.parse({ ...report, reportObservationUri: evidence.observationUri });
230
+ }
231
+ catch {
232
+ if (report.state === "completed") {
233
+ const failedReportWithoutDigest = { ...reportWithoutDigest, state: "failed" };
234
+ report = ScenarioReportSchema.parse({
235
+ ...failedReportWithoutDigest,
236
+ reportSha256: digest(failedReportWithoutDigest),
237
+ });
238
+ terminalState = "failed";
239
+ }
240
+ }
241
+ job.report = report;
242
+ job.state = terminalState;
243
+ }
244
+ }
245
+ async runStep(job, handle, step, captures, paused) {
246
+ this.assertJobActive(job);
247
+ switch (step.kind) {
248
+ case "wait":
249
+ await this.boundary(job, this.dependencies.runtime.execute({ operation: "wait", handle, timeoutMs: step.timeoutMs, condition: step.condition }));
250
+ return { paused, summary: { satisfied: true }, evidence: [] };
251
+ case "assert":
252
+ await this.assertRuntime(job, handle, step.assertion);
253
+ return { paused, summary: { passed: true, assertion: step.assertion.type }, evidence: [] };
254
+ case "control": {
255
+ const input = step.action === "step"
256
+ ? { operation: "step", handle, frames: step.frames }
257
+ : { operation: step.action, handle };
258
+ await this.boundary(job, this.dependencies.runtime.execute(input));
259
+ return { paused: step.action === "pause" || (step.action === "step" && paused), summary: { action: step.action }, evidence: [] };
260
+ }
261
+ case "input": {
262
+ if (step.mode === "deterministic" && !paused)
263
+ throw scenarioError("ASSERTION_FAILED", "Deterministic input requires a paused runtime");
264
+ const input = step.mode === "deterministic"
265
+ ? { operation: "replay", handle, mode: "deterministic", timeoutMs: step.timeoutMs, trace: step.trace }
266
+ : { operation: "sequence", handle, mode: "realtime", timeoutMs: step.timeoutMs, events: step.trace.events };
267
+ await this.boundary(job, this.dependencies.runtime.input(input));
268
+ return { paused, summary: { mode: step.mode, eventCount: step.trace.events.length }, evidence: [] };
269
+ }
270
+ case "capture": {
271
+ const captured = await this.boundary(job, this.dependencies.runtime.capture({
272
+ handle,
273
+ maxWidth: step.maxWidth,
274
+ maxHeight: step.maxHeight,
275
+ frameCount: step.frameCount,
276
+ intervalFrames: step.intervalFrames,
277
+ advancePaused: step.advancePaused,
278
+ }));
279
+ if (captured.frames.length !== step.frameCount)
280
+ throw scenarioError("GODOT_RUNTIME_ERROR", "Scenario capture returned an unexpected frame count");
281
+ const frames = [];
282
+ for (const [index, candidate] of captured.frames.entries()) {
283
+ const metadata = RuntimeCaptureFrameMetadataSchema.parse(candidate.metadata);
284
+ const sha256 = createHash("sha256").update(candidate.data).digest("hex");
285
+ if (metadata.frameIndex !== index || metadata.byteLength !== candidate.data.byteLength || metadata.sha256 !== sha256) {
286
+ throw scenarioError("GODOT_RUNTIME_ERROR", "Scenario capture metadata conflicts with PNG evidence");
287
+ }
288
+ const stored = await this.boundary(job, this.dependencies.evidence.putPng(job.sessionId, candidate.data, {
289
+ source: "runtime",
290
+ viewport: "runtime",
291
+ width: metadata.width,
292
+ height: metadata.height,
293
+ runId: handle.runId,
294
+ generation: handle.generation,
295
+ frameIndex: index,
296
+ }));
297
+ frames.push({ data: candidate.data, metadata, observationUri: stored.observationUri });
298
+ }
299
+ captures.set(step.label, frames);
300
+ return { paused, summary: { label: step.label, frameCount: frames.length }, evidence: frames.map((frame) => frame.observationUri) };
301
+ }
302
+ case "compare": {
303
+ const frame = captures.get(step.captureLabel)?.[step.frameIndex];
304
+ if (!frame)
305
+ throw scenarioError("ASSERTION_FAILED", "Scenario comparison capture is unavailable");
306
+ const baseline = await this.boundary(job, this.dependencies.evidence.readPngBaselineData(step.baselineName));
307
+ const compared = comparePng({ baseline: baseline.data, current: frame.data, settings: step.settings });
308
+ const evidence = [frame.observationUri];
309
+ let result = compared.result;
310
+ if (compared.diffPng) {
311
+ const storedDiff = await this.boundary(job, this.dependencies.evidence.putPng(job.sessionId, compared.diffPng, {
312
+ source: "runtime",
313
+ viewport: "runtime",
314
+ width: frame.metadata.width,
315
+ height: frame.metadata.height,
316
+ runId: handle.runId,
317
+ generation: handle.generation,
318
+ frameIndex: step.frameIndex,
319
+ }));
320
+ evidence.push(storedDiff.observationUri);
321
+ result = VisualComparisonResultSchema.parse({ ...result, diffObservationUri: storedDiff.observationUri });
322
+ }
323
+ const report = await this.boundary(job, this.dependencies.evidence.putJson(job.sessionId, result, { kind: "visual_comparison" }));
324
+ evidence.push(report.observationUri);
325
+ result = VisualComparisonResultSchema.parse({ ...result, reportObservationUri: report.observationUri });
326
+ if (!result.passed)
327
+ throw scenarioError("ASSERTION_FAILED", "Visual comparison did not satisfy its declared tolerances", evidence);
328
+ return { paused, summary: { passed: true, resultSha256: result.resultSha256 }, evidence };
329
+ }
330
+ }
331
+ }
332
+ async assertRuntime(job, handle, assertion) {
333
+ if (assertion.type === "log_matches") {
334
+ await this.boundary(job, this.dependencies.runtime.execute({
335
+ operation: "wait",
336
+ handle,
337
+ timeoutMs: 1,
338
+ condition: assertion,
339
+ })).catch((error) => {
340
+ rethrowIfInterrupted(error);
341
+ throw scenarioError("ASSERTION_FAILED", "Runtime log assertion failed");
342
+ });
343
+ return;
344
+ }
345
+ if (assertion.type === "no_error_logs") {
346
+ const response = await this.boundary(job, this.dependencies.runtime.execute({
347
+ operation: "logs",
348
+ handle,
349
+ afterSequence: 0,
350
+ levels: ["error", "script", "shader"],
351
+ limit: 1,
352
+ }));
353
+ if (!isRecord(response) || !Array.isArray(response.records) || response.records.length > 0) {
354
+ throw scenarioError("ASSERTION_FAILED", "Runtime error-log assertion failed");
355
+ }
356
+ return;
357
+ }
358
+ let response;
359
+ try {
360
+ response = await this.boundary(job, this.dependencies.runtime.execute({
361
+ operation: "node",
362
+ handle,
363
+ nodePath: assertion.nodePath,
364
+ includeProperties: assertion.type === "property_equals" || assertion.type === "property_matches",
365
+ includeSignals: false,
366
+ }));
367
+ }
368
+ catch (error) {
369
+ rethrowIfInterrupted(error);
370
+ if (assertion.type === "node_missing" && errorCode(error) === "TARGET_NOT_FOUND")
371
+ return;
372
+ throw scenarioError("ASSERTION_FAILED", "Runtime node assertion failed");
373
+ }
374
+ if (assertion.type === "node_missing")
375
+ throw scenarioError("ASSERTION_FAILED", "Runtime node-missing assertion failed");
376
+ if (assertion.type === "node_exists")
377
+ return;
378
+ if (!isRecord(response) || !Array.isArray(response.properties))
379
+ throw scenarioError("ASSERTION_FAILED", "Runtime property assertion failed");
380
+ const property = response.properties.find((entry) => isRecord(entry) && entry.name === assertion.property);
381
+ if (!isRecord(property))
382
+ throw scenarioError("ASSERTION_FAILED", "Runtime property assertion failed");
383
+ if (assertion.type === "property_equals") {
384
+ if (!Object.is(property.value, assertion.value))
385
+ throw scenarioError("ASSERTION_FAILED", "Runtime property equality assertion failed");
386
+ return;
387
+ }
388
+ if (typeof property.value !== "string" || !wildcardMatches(property.value, assertion.pattern)) {
389
+ throw scenarioError("ASSERTION_FAILED", "Runtime property pattern assertion failed");
390
+ }
391
+ }
392
+ async boundary(job, promise) {
393
+ this.assertJobActive(job);
394
+ const remaining = job.deadlineAtMs - Math.floor(this.now());
395
+ if (remaining <= 0)
396
+ throw scenarioError("TIMEOUT", "Visual scenario deadline expired");
397
+ let timeout;
398
+ let abortListener;
399
+ const interruption = new Promise((_resolve, reject) => {
400
+ timeout = setTimeout(() => reject(scenarioError("TIMEOUT", "Visual scenario deadline expired")), remaining);
401
+ abortListener = () => reject(job.controller.signal.reason ?? scenarioError("CANCELLED", "Visual scenario was cancelled"));
402
+ job.controller.signal.addEventListener("abort", abortListener, { once: true });
403
+ });
404
+ promise.catch(() => undefined);
405
+ try {
406
+ return await Promise.race([promise, interruption]);
407
+ }
408
+ finally {
409
+ if (timeout)
410
+ clearTimeout(timeout);
411
+ if (abortListener)
412
+ job.controller.signal.removeEventListener("abort", abortListener);
413
+ }
414
+ }
415
+ assertJobActive(job) {
416
+ if (job.controller.signal.aborted) {
417
+ throw job.controller.signal.reason ?? scenarioError("CANCELLED", "Visual scenario was cancelled");
418
+ }
419
+ }
420
+ }
421
+ //# sourceMappingURL=scenarioService.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"scenarioService.js","sourceRoot":"","sources":["../../src/visual/scenarioService.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,27 @@
1
+ import { type VisualOperationInput } from "@godot-mcp/protocol";
2
+ import type { EvidenceStore } from "../evidence/evidenceStore.js";
3
+ export interface VisualScenarioController {
4
+ start(input: unknown): unknown;
5
+ status(jobToken: string): unknown;
6
+ cancel(jobToken: string): unknown;
7
+ result(jobToken: string): unknown;
8
+ }
9
+ export interface VisualServiceDependencies {
10
+ sessionId(): string | null;
11
+ evidence: EvidenceStore;
12
+ scenario: VisualScenarioController;
13
+ }
14
+ export interface VisualExecutionResult {
15
+ data: unknown;
16
+ evidence?: string[];
17
+ images?: Array<{
18
+ data: Uint8Array;
19
+ mimeType: "image/png";
20
+ }>;
21
+ }
22
+ export declare class VisualService {
23
+ private readonly dependencies;
24
+ constructor(dependencies: VisualServiceDependencies);
25
+ execute(rawInput: VisualOperationInput): Promise<VisualExecutionResult>;
26
+ }
27
+ //# sourceMappingURL=visualService.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"visualService.d.ts","sourceRoot":"","sources":["../../src/visual/visualService.ts"],"names":[],"mappings":"AAEA,OAAO,EAGL,KAAK,oBAAoB,EAC1B,MAAM,qBAAqB,CAAC;AAG7B,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,8BAA8B,CAAC;AAGlE,MAAM,WAAW,wBAAwB;IACvC,KAAK,CAAC,KAAK,EAAE,OAAO,GAAG,OAAO,CAAC;IAC/B,MAAM,CAAC,QAAQ,EAAE,MAAM,GAAG,OAAO,CAAC;IAClC,MAAM,CAAC,QAAQ,EAAE,MAAM,GAAG,OAAO,CAAC;IAClC,MAAM,CAAC,QAAQ,EAAE,MAAM,GAAG,OAAO,CAAC;CACnC;AAED,MAAM,WAAW,yBAAyB;IACxC,SAAS,IAAI,MAAM,GAAG,IAAI,CAAC;IAC3B,QAAQ,EAAE,aAAa,CAAC;IACxB,QAAQ,EAAE,wBAAwB,CAAC;CACpC;AAED,MAAM,WAAW,qBAAqB;IACpC,IAAI,EAAE,OAAO,CAAC;IACd,QAAQ,CAAC,EAAE,MAAM,EAAE,CAAC;IACpB,MAAM,CAAC,EAAE,KAAK,CAAC;QAAE,IAAI,EAAE,UAAU,CAAC;QAAC,QAAQ,EAAE,WAAW,CAAA;KAAE,CAAC,CAAC;CAC7D;AAiBD,qBAAa,aAAa;IACZ,OAAO,CAAC,QAAQ,CAAC,YAAY;gBAAZ,YAAY,EAAE,yBAAyB;IAE9D,OAAO,CAAC,QAAQ,EAAE,oBAAoB,GAAG,OAAO,CAAC,qBAAqB,CAAC;CA0C9E"}
@@ -0,0 +1,70 @@
1
+ import { randomUUID } from "node:crypto";
2
+ import { VisualComparisonResultSchema, VisualOperationInputSchema, } from "@godot-mcp/protocol";
3
+ import { GodotMcpException } from "../errors.js";
4
+ import { comparePng } from "./pngComparison.js";
5
+ function visualError(code, message) {
6
+ return new GodotMcpException({
7
+ code,
8
+ message,
9
+ retryable: false,
10
+ correlationId: randomUUID(),
11
+ partialEffects: false,
12
+ rollback: "not_needed",
13
+ });
14
+ }
15
+ function isRecord(value) {
16
+ return typeof value === "object" && value !== null && !Array.isArray(value);
17
+ }
18
+ export class VisualService {
19
+ dependencies;
20
+ constructor(dependencies) {
21
+ this.dependencies = dependencies;
22
+ }
23
+ async execute(rawInput) {
24
+ const input = VisualOperationInputSchema.parse(rawInput);
25
+ if (input.operation === "scenario_start")
26
+ return { data: this.dependencies.scenario.start(input.scenario) };
27
+ if (input.operation === "scenario_status")
28
+ return { data: this.dependencies.scenario.status(input.jobToken) };
29
+ if (input.operation === "scenario_cancel")
30
+ return { data: this.dependencies.scenario.cancel(input.jobToken) };
31
+ if (input.operation === "scenario_result") {
32
+ const report = this.dependencies.scenario.result(input.jobToken);
33
+ const reportObservationUri = isRecord(report) && typeof report.reportObservationUri === "string"
34
+ ? report.reportObservationUri
35
+ : undefined;
36
+ return { data: report, ...(reportObservationUri ? { evidence: [reportObservationUri] } : {}) };
37
+ }
38
+ const sessionId = this.dependencies.sessionId();
39
+ if (!sessionId)
40
+ throw visualError("NOT_ATTACHED", "Godot editor addon is not attached");
41
+ if (input.operation === "baseline_create") {
42
+ return { data: await this.dependencies.evidence.createPngBaseline(sessionId, input.name, input.observationUri) };
43
+ }
44
+ if (input.operation === "baseline_get") {
45
+ return { data: await this.dependencies.evidence.readPngBaseline(input.name) };
46
+ }
47
+ const current = await this.dependencies.evidence.readSessionPngObservation(sessionId, input.observationUri);
48
+ const baseline = await this.dependencies.evidence.readPngBaselineData(input.name);
49
+ const compared = comparePng({ baseline: baseline.data, current: current.data, settings: input.settings });
50
+ const evidence = [current.observationUri];
51
+ let result = compared.result;
52
+ let images;
53
+ if (compared.diffPng) {
54
+ const diff = await this.dependencies.evidence.putPng(sessionId, compared.diffPng, {
55
+ source: "runtime",
56
+ viewport: "runtime",
57
+ width: current.width,
58
+ height: current.height,
59
+ });
60
+ evidence.push(diff.observationUri);
61
+ result = VisualComparisonResultSchema.parse({ ...result, diffObservationUri: diff.observationUri });
62
+ images = [{ data: compared.diffPng, mimeType: "image/png" }];
63
+ }
64
+ const report = await this.dependencies.evidence.putJson(sessionId, result, { kind: "visual_comparison" });
65
+ evidence.push(report.observationUri);
66
+ result = VisualComparisonResultSchema.parse({ ...result, reportObservationUri: report.observationUri });
67
+ return { data: result, evidence, ...(images ? { images } : {}) };
68
+ }
69
+ }
70
+ //# sourceMappingURL=visualService.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"visualService.js","sourceRoot":"","sources":["../../src/visual/visualService.ts"],"names":[],"mappings":"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"}
package/package.json CHANGED
@@ -1,11 +1,31 @@
1
1
  {
2
2
  "name": "@godot-mcp/control-plane",
3
- "version": "0.0.0",
4
- "description": "Namespace bootstrap for the Godot MCP control-plane package.",
3
+ "version": "0.1.0",
5
4
  "type": "module",
6
- "main": "index.js",
7
- "files": ["index.js", "README.md"],
5
+ "exports": {
6
+ ".": "./dist/index.js"
7
+ },
8
+ "types": "./dist/index.d.ts",
9
+ "files": [
10
+ "dist",
11
+ "README.md",
12
+ "LICENSE"
13
+ ],
14
+ "scripts": {
15
+ "build": "tsc -p tsconfig.json",
16
+ "typecheck": "tsc -p tsconfig.json --noEmit"
17
+ },
18
+ "dependencies": {
19
+ "@godot-mcp/protocol": "0.1.0",
20
+ "pngjs": "7.0.0",
21
+ "zod": "4.4.3"
22
+ },
8
23
  "license": "MIT",
9
- "repository": "git+https://github.com/k0nkupa/godot-mcp.git",
10
- "publishConfig": { "access": "public", "tag": "bootstrap" }
24
+ "engines": {
25
+ "node": ">=22 <23"
26
+ },
27
+ "repository": {
28
+ "type": "git",
29
+ "url": "git+https://github.com/k0nkupa/godot-mcp.git"
30
+ }
11
31
  }
package/index.js DELETED
@@ -1 +0,0 @@
1
- export {};