@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.
- package/LICENSE +21 -0
- package/README.md +105 -2
- package/dist/audit/jsonlAuditSink.d.ts +33 -0
- package/dist/audit/jsonlAuditSink.d.ts.map +1 -0
- package/dist/audit/jsonlAuditSink.js +57 -0
- package/dist/audit/jsonlAuditSink.js.map +1 -0
- package/dist/audit/redact.d.ts +2 -0
- package/dist/audit/redact.d.ts.map +1 -0
- package/dist/audit/redact.js +44 -0
- package/dist/audit/redact.js.map +1 -0
- package/dist/auth/pairingDescriptor.d.ts +44 -0
- package/dist/auth/pairingDescriptor.d.ts.map +1 -0
- package/dist/auth/pairingDescriptor.js +91 -0
- package/dist/auth/pairingDescriptor.js.map +1 -0
- package/dist/auth/runtimeDirectory.d.ts +3 -0
- package/dist/auth/runtimeDirectory.d.ts.map +1 -0
- package/dist/auth/runtimeDirectory.js +30 -0
- package/dist/auth/runtimeDirectory.js.map +1 -0
- package/dist/auth/sessionCrypto.d.ts +18 -0
- package/dist/auth/sessionCrypto.d.ts.map +1 -0
- package/dist/auth/sessionCrypto.js +118 -0
- package/dist/auth/sessionCrypto.js.map +1 -0
- package/dist/editor/editorMutationService.d.ts +21 -0
- package/dist/editor/editorMutationService.d.ts.map +1 -0
- package/dist/editor/editorMutationService.js +120 -0
- package/dist/editor/editorMutationService.js.map +1 -0
- package/dist/editor/mutationLedger.d.ts +30 -0
- package/dist/editor/mutationLedger.d.ts.map +1 -0
- package/dist/editor/mutationLedger.js +133 -0
- package/dist/editor/mutationLedger.js.map +1 -0
- package/dist/errors.d.ts +12 -0
- package/dist/errors.d.ts.map +1 -0
- package/dist/errors.js +23 -0
- package/dist/errors.js.map +1 -0
- package/dist/evidence/evidenceStore.d.ts +63 -0
- package/dist/evidence/evidenceStore.d.ts.map +1 -0
- package/dist/evidence/evidenceStore.js +350 -0
- package/dist/evidence/evidenceStore.js.map +1 -0
- package/dist/extensions/extensionRegistry.d.ts +33 -0
- package/dist/extensions/extensionRegistry.d.ts.map +1 -0
- package/dist/extensions/extensionRegistry.js +37 -0
- package/dist/extensions/extensionRegistry.js.map +1 -0
- package/dist/help/coreHelp.d.ts +10 -0
- package/dist/help/coreHelp.d.ts.map +1 -0
- package/dist/help/coreHelp.js +82 -0
- package/dist/help/coreHelp.js.map +1 -0
- package/dist/index.d.ts +37 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +37 -0
- package/dist/index.js.map +1 -0
- package/dist/policy/authorize.d.ts +5 -0
- package/dist/policy/authorize.d.ts.map +1 -0
- package/dist/policy/authorize.js +19 -0
- package/dist/policy/authorize.js.map +1 -0
- package/dist/policy/capabilities.d.ts +36 -0
- package/dist/policy/capabilities.d.ts.map +1 -0
- package/dist/policy/capabilities.js +129 -0
- package/dist/policy/capabilities.js.map +1 -0
- package/dist/project/artifactStore.d.ts +32 -0
- package/dist/project/artifactStore.d.ts.map +1 -0
- package/dist/project/artifactStore.js +172 -0
- package/dist/project/artifactStore.js.map +1 -0
- package/dist/project/pathPolicy.d.ts +4 -0
- package/dist/project/pathPolicy.d.ts.map +1 -0
- package/dist/project/pathPolicy.js +74 -0
- package/dist/project/pathPolicy.js.map +1 -0
- package/dist/project/projectConfig.d.ts +10 -0
- package/dist/project/projectConfig.d.ts.map +1 -0
- package/dist/project/projectConfig.js +63 -0
- package/dist/project/projectConfig.js.map +1 -0
- package/dist/project/projectIdentity.d.ts +8 -0
- package/dist/project/projectIdentity.d.ts.map +1 -0
- package/dist/project/projectIdentity.js +58 -0
- package/dist/project/projectIdentity.js.map +1 -0
- package/dist/project/projectJobJournal.d.ts +49 -0
- package/dist/project/projectJobJournal.d.ts.map +1 -0
- package/dist/project/projectJobJournal.js +67 -0
- package/dist/project/projectJobJournal.js.map +1 -0
- package/dist/project/projectJobService.d.ts +52 -0
- package/dist/project/projectJobService.d.ts.map +1 -0
- package/dist/project/projectJobService.js +289 -0
- package/dist/project/projectJobService.js.map +1 -0
- package/dist/project/projectMutationService.d.ts +40 -0
- package/dist/project/projectMutationService.d.ts.map +1 -0
- package/dist/project/projectMutationService.js +145 -0
- package/dist/project/projectMutationService.js.map +1 -0
- package/dist/project/projectPreflight.d.ts +7 -0
- package/dist/project/projectPreflight.d.ts.map +1 -0
- package/dist/project/projectPreflight.js +50 -0
- package/dist/project/projectPreflight.js.map +1 -0
- package/dist/project/projectProcess.d.ts +40 -0
- package/dist/project/projectProcess.d.ts.map +1 -0
- package/dist/project/projectProcess.js +196 -0
- package/dist/project/projectProcess.js.map +1 -0
- package/dist/project/projectService.d.ts +20 -0
- package/dist/project/projectService.d.ts.map +1 -0
- package/dist/project/projectService.js +35 -0
- package/dist/project/projectService.js.map +1 -0
- package/dist/project/secureJournalFile.d.ts +3 -0
- package/dist/project/secureJournalFile.d.ts.map +1 -0
- package/dist/project/secureJournalFile.js +56 -0
- package/dist/project/secureJournalFile.js.map +1 -0
- package/dist/runtime/debugTokenStore.d.ts +41 -0
- package/dist/runtime/debugTokenStore.d.ts.map +1 -0
- package/dist/runtime/debugTokenStore.js +105 -0
- package/dist/runtime/debugTokenStore.js.map +1 -0
- package/dist/runtime/debuggerClient.d.ts +14 -0
- package/dist/runtime/debuggerClient.d.ts.map +1 -0
- package/dist/runtime/debuggerClient.js +21 -0
- package/dist/runtime/debuggerClient.js.map +1 -0
- package/dist/runtime/inputReceipt.d.ts +15 -0
- package/dist/runtime/inputReceipt.d.ts.map +1 -0
- package/dist/runtime/inputReceipt.js +36 -0
- package/dist/runtime/inputReceipt.js.map +1 -0
- package/dist/runtime/runtimeDescriptor.d.ts +50 -0
- package/dist/runtime/runtimeDescriptor.d.ts.map +1 -0
- package/dist/runtime/runtimeDescriptor.js +175 -0
- package/dist/runtime/runtimeDescriptor.js.map +1 -0
- package/dist/runtime/runtimeProcess.d.ts +39 -0
- package/dist/runtime/runtimeProcess.d.ts.map +1 -0
- package/dist/runtime/runtimeProcess.js +180 -0
- package/dist/runtime/runtimeProcess.js.map +1 -0
- package/dist/runtime/runtimeService.d.ts +130 -0
- package/dist/runtime/runtimeService.d.ts.map +1 -0
- package/dist/runtime/runtimeService.js +919 -0
- package/dist/runtime/runtimeService.js.map +1 -0
- package/dist/session/sessionService.d.ts +52 -0
- package/dist/session/sessionService.d.ts.map +1 -0
- package/dist/session/sessionService.js +72 -0
- package/dist/session/sessionService.js.map +1 -0
- package/dist/unsafe/unsafeFixtureAuthority.d.ts +27 -0
- package/dist/unsafe/unsafeFixtureAuthority.d.ts.map +1 -0
- package/dist/unsafe/unsafeFixtureAuthority.js +130 -0
- package/dist/unsafe/unsafeFixtureAuthority.js.map +1 -0
- package/dist/unsafe/unsafeFixtureProcess.d.ts +30 -0
- package/dist/unsafe/unsafeFixtureProcess.d.ts.map +1 -0
- package/dist/unsafe/unsafeFixtureProcess.js +119 -0
- package/dist/unsafe/unsafeFixtureProcess.js.map +1 -0
- package/dist/unsafe/unsafeFixtureService.d.ts +41 -0
- package/dist/unsafe/unsafeFixtureService.d.ts.map +1 -0
- package/dist/unsafe/unsafeFixtureService.js +162 -0
- package/dist/unsafe/unsafeFixtureService.js.map +1 -0
- package/dist/visual/pngComparison.d.ts +12 -0
- package/dist/visual/pngComparison.d.ts.map +1 -0
- package/dist/visual/pngComparison.js +136 -0
- package/dist/visual/pngComparison.js.map +1 -0
- package/dist/visual/scenarioService.d.ts +50 -0
- package/dist/visual/scenarioService.d.ts.map +1 -0
- package/dist/visual/scenarioService.js +421 -0
- package/dist/visual/scenarioService.js.map +1 -0
- package/dist/visual/visualService.d.ts +27 -0
- package/dist/visual/visualService.d.ts.map +1 -0
- package/dist/visual/visualService.js +70 -0
- package/dist/visual/visualService.js.map +1 -0
- package/package.json +26 -6
- package/index.js +0 -1
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import { type EditorMutationInput, type EditorMutationResult } from "@godot-mcp/protocol";
|
|
2
|
+
import type { MutationLedger } from "./mutationLedger.js";
|
|
3
|
+
export interface EditorMutationBridge {
|
|
4
|
+
request<T>(method: "editor.mutate", params: unknown, options: {
|
|
5
|
+
timeoutMs: number;
|
|
6
|
+
maxResponseBytes: number;
|
|
7
|
+
correlationId: string;
|
|
8
|
+
}): Promise<{
|
|
9
|
+
requestId: string;
|
|
10
|
+
data: T;
|
|
11
|
+
}>;
|
|
12
|
+
}
|
|
13
|
+
export declare function editorMutationRequestDigest(input: EditorMutationInput): string;
|
|
14
|
+
export declare class EditorMutationService {
|
|
15
|
+
private readonly bridge;
|
|
16
|
+
private readonly ledger;
|
|
17
|
+
constructor(bridge: () => EditorMutationBridge | null, ledger: MutationLedger);
|
|
18
|
+
execute(inputValue: EditorMutationInput, correlationId: string): Promise<EditorMutationResult>;
|
|
19
|
+
private validateTransition;
|
|
20
|
+
}
|
|
21
|
+
//# sourceMappingURL=editorMutationService.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"editorMutationService.d.ts","sourceRoot":"","sources":["../../src/editor/editorMutationService.ts"],"names":[],"mappings":"AAEA,OAAO,EAGL,KAAK,mBAAmB,EACxB,KAAK,oBAAoB,EAC1B,MAAM,qBAAqB,CAAC;AAG7B,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,qBAAqB,CAAC;AAE1D,MAAM,WAAW,oBAAoB;IACnC,OAAO,CAAC,CAAC,EACP,MAAM,EAAE,eAAe,EACvB,MAAM,EAAE,OAAO,EACf,OAAO,EAAE;QAAE,SAAS,EAAE,MAAM,CAAC;QAAC,gBAAgB,EAAE,MAAM,CAAC;QAAC,aAAa,EAAE,MAAM,CAAA;KAAE,GAC9E,OAAO,CAAC;QAAE,SAAS,EAAE,MAAM,CAAC;QAAC,IAAI,EAAE,CAAC,CAAA;KAAE,CAAC,CAAC;CAC5C;AA6BD,wBAAgB,2BAA2B,CAAC,KAAK,EAAE,mBAAmB,GAAG,MAAM,CAK9E;AAkBD,qBAAa,qBAAqB;IAE9B,OAAO,CAAC,QAAQ,CAAC,MAAM;IACvB,OAAO,CAAC,QAAQ,CAAC,MAAM;gBADN,MAAM,EAAE,MAAM,oBAAoB,GAAG,IAAI,EACzC,MAAM,EAAE,cAAc;IAGnC,OAAO,CAAC,UAAU,EAAE,mBAAmB,EAAE,aAAa,EAAE,MAAM,GAAG,OAAO,CAAC,oBAAoB,CAAC;IA8CpG,OAAO,CAAC,kBAAkB;CA2B3B"}
|
|
@@ -0,0 +1,120 @@
|
|
|
1
|
+
import { createHash } from "node:crypto";
|
|
2
|
+
import { EditorMutationInputSchema, EditorMutationResultSchema, } from "@godot-mcp/protocol";
|
|
3
|
+
import { GodotMcpException } from "../errors.js";
|
|
4
|
+
function normalize(value, ancestors) {
|
|
5
|
+
if (value === null || typeof value === "boolean" || typeof value === "string")
|
|
6
|
+
return value;
|
|
7
|
+
if (typeof value === "number") {
|
|
8
|
+
if (!Number.isFinite(value))
|
|
9
|
+
throw new TypeError("Mutation digest accepts only finite numbers");
|
|
10
|
+
return Object.is(value, -0) ? 0 : value;
|
|
11
|
+
}
|
|
12
|
+
if (typeof value !== "object")
|
|
13
|
+
throw new TypeError(`Mutation digest does not support ${typeof value}`);
|
|
14
|
+
if (ancestors.has(value))
|
|
15
|
+
throw new TypeError("Mutation digest does not support cyclic values");
|
|
16
|
+
ancestors.add(value);
|
|
17
|
+
try {
|
|
18
|
+
if (Array.isArray(value))
|
|
19
|
+
return value.map((item) => normalize(item, ancestors));
|
|
20
|
+
const prototype = Object.getPrototypeOf(value);
|
|
21
|
+
if (prototype !== Object.prototype && prototype !== null) {
|
|
22
|
+
throw new TypeError("Mutation digest accepts only arrays and plain objects");
|
|
23
|
+
}
|
|
24
|
+
const output = {};
|
|
25
|
+
for (const key of Object.keys(value).sort()) {
|
|
26
|
+
output[key] = normalize(value[key], ancestors);
|
|
27
|
+
}
|
|
28
|
+
return output;
|
|
29
|
+
}
|
|
30
|
+
finally {
|
|
31
|
+
ancestors.delete(value);
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
export function editorMutationRequestDigest(input) {
|
|
35
|
+
const parsed = EditorMutationInputSchema.parse(input);
|
|
36
|
+
return createHash("sha256")
|
|
37
|
+
.update(JSON.stringify(normalize(parsed, new Set())))
|
|
38
|
+
.digest("hex");
|
|
39
|
+
}
|
|
40
|
+
function exception(code, message, correlationId, partialEffects = false) {
|
|
41
|
+
return new GodotMcpException({
|
|
42
|
+
code,
|
|
43
|
+
message,
|
|
44
|
+
retryable: code === "NOT_ATTACHED",
|
|
45
|
+
correlationId,
|
|
46
|
+
partialEffects,
|
|
47
|
+
rollback: partialEffects ? "not_attempted" : "not_needed",
|
|
48
|
+
});
|
|
49
|
+
}
|
|
50
|
+
export class EditorMutationService {
|
|
51
|
+
bridge;
|
|
52
|
+
ledger;
|
|
53
|
+
constructor(bridge, ledger) {
|
|
54
|
+
this.bridge = bridge;
|
|
55
|
+
this.ledger = ledger;
|
|
56
|
+
}
|
|
57
|
+
async execute(inputValue, correlationId) {
|
|
58
|
+
const input = EditorMutationInputSchema.parse(inputValue);
|
|
59
|
+
const bridge = this.bridge();
|
|
60
|
+
if (!bridge)
|
|
61
|
+
throw exception("NOT_ATTACHED", "Godot editor addon is not attached", correlationId);
|
|
62
|
+
if (input.operation === "preview") {
|
|
63
|
+
const response = await bridge.request("editor.mutate", input, {
|
|
64
|
+
timeoutMs: 10_000,
|
|
65
|
+
maxResponseBytes: 512 * 1024,
|
|
66
|
+
correlationId,
|
|
67
|
+
});
|
|
68
|
+
return this.validateTransition(input, response.data, correlationId);
|
|
69
|
+
}
|
|
70
|
+
const requestDigest = editorMutationRequestDigest(input);
|
|
71
|
+
const reconciliation = await this.ledger.reconcile(input.idempotencyKey, requestDigest);
|
|
72
|
+
if (reconciliation.state === "completed")
|
|
73
|
+
return reconciliation.result;
|
|
74
|
+
if (reconciliation.state === "unknown") {
|
|
75
|
+
throw exception("CONFLICT", "A prior mutation with this idempotency key has an unknown outcome; preview current targets and reconcile their revisions before retrying with a new key", correlationId, true);
|
|
76
|
+
}
|
|
77
|
+
await this.ledger.begin({
|
|
78
|
+
idempotencyKey: input.idempotencyKey,
|
|
79
|
+
requestDigest,
|
|
80
|
+
correlationId,
|
|
81
|
+
});
|
|
82
|
+
const response = await bridge.request("editor.mutate", input, {
|
|
83
|
+
timeoutMs: 30_000,
|
|
84
|
+
maxResponseBytes: 512 * 1024,
|
|
85
|
+
correlationId,
|
|
86
|
+
});
|
|
87
|
+
const result = this.validateTransition(input, response.data, correlationId);
|
|
88
|
+
await this.ledger.complete({
|
|
89
|
+
idempotencyKey: input.idempotencyKey,
|
|
90
|
+
requestDigest,
|
|
91
|
+
correlationId,
|
|
92
|
+
result,
|
|
93
|
+
});
|
|
94
|
+
return result;
|
|
95
|
+
}
|
|
96
|
+
validateTransition(input, value, correlationId) {
|
|
97
|
+
const parsed = EditorMutationResultSchema.safeParse(value);
|
|
98
|
+
if (!parsed.success) {
|
|
99
|
+
throw exception("INVALID_REQUEST", "Godot returned an invalid editor mutation result", correlationId);
|
|
100
|
+
}
|
|
101
|
+
const expectedState = input.operation === "preview"
|
|
102
|
+
? "previewed"
|
|
103
|
+
: input.operation === "apply"
|
|
104
|
+
? "applied"
|
|
105
|
+
: input.operation === "undo"
|
|
106
|
+
? "undone"
|
|
107
|
+
: "redone";
|
|
108
|
+
if (parsed.data.state !== expectedState) {
|
|
109
|
+
throw exception("INVALID_REQUEST", `Godot returned ${parsed.data.state} for ${input.operation}`, correlationId);
|
|
110
|
+
}
|
|
111
|
+
if (input.operation === "apply" && parsed.data.planDigest !== input.expectedPlanDigest) {
|
|
112
|
+
throw exception("INVALID_REQUEST", "Godot apply result plan digest did not match the authorized preview", correlationId);
|
|
113
|
+
}
|
|
114
|
+
if ((input.operation === "undo" || input.operation === "redo") && parsed.data.actionId !== input.actionId) {
|
|
115
|
+
throw exception("INVALID_REQUEST", "Godot action result did not match the requested action", correlationId);
|
|
116
|
+
}
|
|
117
|
+
return parsed.data;
|
|
118
|
+
}
|
|
119
|
+
}
|
|
120
|
+
//# sourceMappingURL=editorMutationService.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"editorMutationService.js","sourceRoot":"","sources":["../../src/editor/editorMutationService.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
import { type EditorMutationResult } from "@godot-mcp/protocol";
|
|
2
|
+
export interface MutationLedgerKeyInput {
|
|
3
|
+
idempotencyKey: string;
|
|
4
|
+
requestDigest: string;
|
|
5
|
+
correlationId: string;
|
|
6
|
+
}
|
|
7
|
+
export interface MutationLedgerCompleteInput extends MutationLedgerKeyInput {
|
|
8
|
+
result: EditorMutationResult;
|
|
9
|
+
}
|
|
10
|
+
export type MutationReconciliation = {
|
|
11
|
+
state: "missing";
|
|
12
|
+
} | {
|
|
13
|
+
state: "unknown";
|
|
14
|
+
} | {
|
|
15
|
+
state: "completed";
|
|
16
|
+
result: EditorMutationResult;
|
|
17
|
+
};
|
|
18
|
+
export declare class MutationLedger {
|
|
19
|
+
private readonly path;
|
|
20
|
+
private readonly latest;
|
|
21
|
+
private tail;
|
|
22
|
+
static open(path: string): Promise<MutationLedger>;
|
|
23
|
+
private constructor();
|
|
24
|
+
reconcile(idempotencyKey: string, requestDigest: string): Promise<MutationReconciliation>;
|
|
25
|
+
begin(input: MutationLedgerKeyInput): Promise<void>;
|
|
26
|
+
complete(input: MutationLedgerCompleteInput): Promise<void>;
|
|
27
|
+
private append;
|
|
28
|
+
private remember;
|
|
29
|
+
}
|
|
30
|
+
//# sourceMappingURL=mutationLedger.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"mutationLedger.d.ts","sourceRoot":"","sources":["../../src/editor/mutationLedger.ts"],"names":[],"mappings":"AAIA,OAAO,EAA8B,KAAK,oBAAoB,EAAE,MAAM,qBAAqB,CAAC;AA+B5F,MAAM,WAAW,sBAAsB;IACrC,cAAc,EAAE,MAAM,CAAC;IACvB,aAAa,EAAE,MAAM,CAAC;IACtB,aAAa,EAAE,MAAM,CAAC;CACvB;AAED,MAAM,WAAW,2BAA4B,SAAQ,sBAAsB;IACzE,MAAM,EAAE,oBAAoB,CAAC;CAC9B;AAED,MAAM,MAAM,sBAAsB,GAC9B;IAAE,KAAK,EAAE,SAAS,CAAA;CAAE,GACpB;IAAE,KAAK,EAAE,SAAS,CAAA;CAAE,GACpB;IAAE,KAAK,EAAE,WAAW,CAAC;IAAC,MAAM,EAAE,oBAAoB,CAAA;CAAE,CAAC;AAiBzD,qBAAa,cAAc;IA4BL,OAAO,CAAC,QAAQ,CAAC,IAAI;IA3BzC,OAAO,CAAC,QAAQ,CAAC,MAAM,CAAmC;IAC1D,OAAO,CAAC,IAAI,CAAuC;WAEtC,IAAI,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,cAAc,CAAC;IAwBxD,OAAO;IAED,SAAS,CAAC,cAAc,EAAE,MAAM,EAAE,aAAa,EAAE,MAAM,GAAG,OAAO,CAAC,sBAAsB,CAAC;IAWzF,KAAK,CAAC,KAAK,EAAE,sBAAsB,GAAG,OAAO,CAAC,IAAI,CAAC;IAWnD,QAAQ,CAAC,KAAK,EAAE,2BAA2B,GAAG,OAAO,CAAC,IAAI,CAAC;YAYnD,MAAM;IAepB,OAAO,CAAC,QAAQ;CASjB"}
|
|
@@ -0,0 +1,133 @@
|
|
|
1
|
+
import { createHash, randomUUID } from "node:crypto";
|
|
2
|
+
import { mkdir, open, readFile, stat } from "node:fs/promises";
|
|
3
|
+
import { dirname } from "node:path";
|
|
4
|
+
import { EditorMutationResultSchema } from "@godot-mcp/protocol";
|
|
5
|
+
import { z } from "zod";
|
|
6
|
+
import { GodotMcpException } from "../errors.js";
|
|
7
|
+
const MAX_LEDGER_BYTES = 4 * 1024 * 1024;
|
|
8
|
+
const MAX_KEYS = 256;
|
|
9
|
+
const Sha256Schema = z.string().regex(/^[a-f0-9]{64}$/);
|
|
10
|
+
const StartedRecordSchema = z.object({
|
|
11
|
+
schemaVersion: z.literal(1),
|
|
12
|
+
state: z.literal("started"),
|
|
13
|
+
idempotencyKeySha256: Sha256Schema,
|
|
14
|
+
requestDigest: Sha256Schema,
|
|
15
|
+
correlationId: z.string().min(1).max(256),
|
|
16
|
+
recordedAt: z.string().datetime(),
|
|
17
|
+
}).strict();
|
|
18
|
+
const CompletedRecordSchema = z.object({
|
|
19
|
+
schemaVersion: z.literal(1),
|
|
20
|
+
state: z.literal("completed"),
|
|
21
|
+
idempotencyKeySha256: Sha256Schema,
|
|
22
|
+
requestDigest: Sha256Schema,
|
|
23
|
+
correlationId: z.string().min(1).max(256),
|
|
24
|
+
recordedAt: z.string().datetime(),
|
|
25
|
+
result: EditorMutationResultSchema,
|
|
26
|
+
}).strict();
|
|
27
|
+
const LedgerRecordSchema = z.discriminatedUnion("state", [StartedRecordSchema, CompletedRecordSchema]);
|
|
28
|
+
function sha256(value) {
|
|
29
|
+
return createHash("sha256").update(value).digest("hex");
|
|
30
|
+
}
|
|
31
|
+
function conflict(message) {
|
|
32
|
+
return new GodotMcpException({
|
|
33
|
+
code: "CONFLICT",
|
|
34
|
+
message,
|
|
35
|
+
retryable: false,
|
|
36
|
+
correlationId: randomUUID(),
|
|
37
|
+
partialEffects: false,
|
|
38
|
+
rollback: "not_attempted",
|
|
39
|
+
});
|
|
40
|
+
}
|
|
41
|
+
export class MutationLedger {
|
|
42
|
+
path;
|
|
43
|
+
latest = new Map();
|
|
44
|
+
tail = Promise.resolve();
|
|
45
|
+
static async open(path) {
|
|
46
|
+
const ledger = new MutationLedger(path);
|
|
47
|
+
let metadata;
|
|
48
|
+
try {
|
|
49
|
+
metadata = await stat(path);
|
|
50
|
+
}
|
|
51
|
+
catch (error) {
|
|
52
|
+
if (error.code === "ENOENT")
|
|
53
|
+
return ledger;
|
|
54
|
+
throw error;
|
|
55
|
+
}
|
|
56
|
+
if (metadata.size > MAX_LEDGER_BYTES) {
|
|
57
|
+
throw conflict("Mutation journal exceeds 4 MiB; inspect and archive it outside MCP before reconnecting");
|
|
58
|
+
}
|
|
59
|
+
const text = await readFile(path, "utf8");
|
|
60
|
+
for (const [index, line] of text.split("\n").entries()) {
|
|
61
|
+
if (line.length === 0)
|
|
62
|
+
continue;
|
|
63
|
+
try {
|
|
64
|
+
ledger.remember(LedgerRecordSchema.parse(JSON.parse(line)));
|
|
65
|
+
}
|
|
66
|
+
catch {
|
|
67
|
+
throw conflict(`Mutation journal record ${index + 1} is malformed; reconcile it outside MCP before reconnecting`);
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
return ledger;
|
|
71
|
+
}
|
|
72
|
+
constructor(path) {
|
|
73
|
+
this.path = path;
|
|
74
|
+
}
|
|
75
|
+
async reconcile(idempotencyKey, requestDigest) {
|
|
76
|
+
const record = this.latest.get(sha256(idempotencyKey));
|
|
77
|
+
if (!record)
|
|
78
|
+
return { state: "missing" };
|
|
79
|
+
if (record.requestDigest !== requestDigest) {
|
|
80
|
+
throw conflict("Idempotency key was already used for a different editor mutation request");
|
|
81
|
+
}
|
|
82
|
+
return record.state === "completed"
|
|
83
|
+
? { state: "completed", result: record.result }
|
|
84
|
+
: { state: "unknown" };
|
|
85
|
+
}
|
|
86
|
+
async begin(input) {
|
|
87
|
+
await this.append({
|
|
88
|
+
schemaVersion: 1,
|
|
89
|
+
state: "started",
|
|
90
|
+
idempotencyKeySha256: sha256(input.idempotencyKey),
|
|
91
|
+
requestDigest: Sha256Schema.parse(input.requestDigest),
|
|
92
|
+
correlationId: input.correlationId,
|
|
93
|
+
recordedAt: new Date().toISOString(),
|
|
94
|
+
});
|
|
95
|
+
}
|
|
96
|
+
async complete(input) {
|
|
97
|
+
await this.append({
|
|
98
|
+
schemaVersion: 1,
|
|
99
|
+
state: "completed",
|
|
100
|
+
idempotencyKeySha256: sha256(input.idempotencyKey),
|
|
101
|
+
requestDigest: Sha256Schema.parse(input.requestDigest),
|
|
102
|
+
correlationId: input.correlationId,
|
|
103
|
+
recordedAt: new Date().toISOString(),
|
|
104
|
+
result: EditorMutationResultSchema.parse(input.result),
|
|
105
|
+
});
|
|
106
|
+
}
|
|
107
|
+
async append(record) {
|
|
108
|
+
const write = this.tail.then(async () => {
|
|
109
|
+
await mkdir(dirname(this.path), { recursive: true, mode: 0o700 });
|
|
110
|
+
const handle = await open(this.path, "a", 0o600);
|
|
111
|
+
try {
|
|
112
|
+
await handle.writeFile(`${JSON.stringify(record)}\n`, "utf8");
|
|
113
|
+
}
|
|
114
|
+
finally {
|
|
115
|
+
await handle.close();
|
|
116
|
+
}
|
|
117
|
+
this.remember(record);
|
|
118
|
+
});
|
|
119
|
+
this.tail = write.catch(() => undefined);
|
|
120
|
+
await write;
|
|
121
|
+
}
|
|
122
|
+
remember(record) {
|
|
123
|
+
this.latest.delete(record.idempotencyKeySha256);
|
|
124
|
+
this.latest.set(record.idempotencyKeySha256, record);
|
|
125
|
+
while (this.latest.size > MAX_KEYS) {
|
|
126
|
+
const oldest = this.latest.keys().next().value;
|
|
127
|
+
if (oldest === undefined)
|
|
128
|
+
break;
|
|
129
|
+
this.latest.delete(oldest);
|
|
130
|
+
}
|
|
131
|
+
}
|
|
132
|
+
}
|
|
133
|
+
//# sourceMappingURL=mutationLedger.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"mutationLedger.js","sourceRoot":"","sources":["../../src/editor/mutationLedger.ts"],"names":[],"mappings":"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"}
|
package/dist/errors.d.ts
ADDED
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import { type GodotMcpError } from "@godot-mcp/protocol";
|
|
2
|
+
export declare class GodotMcpException extends Error {
|
|
3
|
+
readonly code: GodotMcpError["code"];
|
|
4
|
+
readonly retryable: boolean;
|
|
5
|
+
readonly correlationId: string;
|
|
6
|
+
readonly partialEffects: boolean;
|
|
7
|
+
readonly rollback: GodotMcpError["rollback"];
|
|
8
|
+
readonly failedPhase: string;
|
|
9
|
+
readonly safeRecovery: string;
|
|
10
|
+
constructor(input: Omit<GodotMcpError, "failedPhase" | "safeRecovery"> & Partial<Pick<GodotMcpError, "failedPhase" | "safeRecovery">>);
|
|
11
|
+
}
|
|
12
|
+
//# sourceMappingURL=errors.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"errors.d.ts","sourceRoot":"","sources":["../src/errors.ts"],"names":[],"mappings":"AAAA,OAAO,EAAuB,KAAK,aAAa,EAAE,MAAM,qBAAqB,CAAC;AAE9E,qBAAa,iBAAkB,SAAQ,KAAK;IAC1C,QAAQ,CAAC,IAAI,EAAE,aAAa,CAAC,MAAM,CAAC,CAAC;IACrC,QAAQ,CAAC,SAAS,EAAE,OAAO,CAAC;IAC5B,QAAQ,CAAC,aAAa,EAAE,MAAM,CAAC;IAC/B,QAAQ,CAAC,cAAc,EAAE,OAAO,CAAC;IACjC,QAAQ,CAAC,QAAQ,EAAE,aAAa,CAAC,UAAU,CAAC,CAAC;IAC7C,QAAQ,CAAC,WAAW,EAAE,MAAM,CAAC;IAC7B,QAAQ,CAAC,YAAY,EAAE,MAAM,CAAC;gBAElB,KAAK,EAAE,IAAI,CAAC,aAAa,EAAE,aAAa,GAAG,cAAc,CAAC,GAAG,OAAO,CAAC,IAAI,CAAC,aAAa,EAAE,aAAa,GAAG,cAAc,CAAC,CAAC;CAYtI"}
|
package/dist/errors.js
ADDED
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
import { GodotMcpErrorSchema } from "@godot-mcp/protocol";
|
|
2
|
+
export class GodotMcpException extends Error {
|
|
3
|
+
code;
|
|
4
|
+
retryable;
|
|
5
|
+
correlationId;
|
|
6
|
+
partialEffects;
|
|
7
|
+
rollback;
|
|
8
|
+
failedPhase;
|
|
9
|
+
safeRecovery;
|
|
10
|
+
constructor(input) {
|
|
11
|
+
const error = GodotMcpErrorSchema.parse(input);
|
|
12
|
+
super(error.message);
|
|
13
|
+
this.name = "GodotMcpException";
|
|
14
|
+
this.code = error.code;
|
|
15
|
+
this.retryable = error.retryable;
|
|
16
|
+
this.correlationId = error.correlationId;
|
|
17
|
+
this.partialEffects = error.partialEffects;
|
|
18
|
+
this.rollback = error.rollback;
|
|
19
|
+
this.failedPhase = error.failedPhase;
|
|
20
|
+
this.safeRecovery = error.safeRecovery;
|
|
21
|
+
}
|
|
22
|
+
}
|
|
23
|
+
//# sourceMappingURL=errors.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"errors.js","sourceRoot":"","sources":["../src/errors.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,mBAAmB,EAAsB,MAAM,qBAAqB,CAAC;AAE9E,MAAM,OAAO,iBAAkB,SAAQ,KAAK;IACjC,IAAI,CAAwB;IAC5B,SAAS,CAAU;IACnB,aAAa,CAAS;IACtB,cAAc,CAAU;IACxB,QAAQ,CAA4B;IACpC,WAAW,CAAS;IACpB,YAAY,CAAS;IAE9B,YAAY,KAAyH;QACnI,MAAM,KAAK,GAAG,mBAAmB,CAAC,KAAK,CAAC,KAAK,CAAC,CAAC;QAC/C,KAAK,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC;QACrB,IAAI,CAAC,IAAI,GAAG,mBAAmB,CAAC;QAChC,IAAI,CAAC,IAAI,GAAG,KAAK,CAAC,IAAI,CAAC;QACvB,IAAI,CAAC,SAAS,GAAG,KAAK,CAAC,SAAS,CAAC;QACjC,IAAI,CAAC,aAAa,GAAG,KAAK,CAAC,aAAa,CAAC;QACzC,IAAI,CAAC,cAAc,GAAG,KAAK,CAAC,cAAc,CAAC;QAC3C,IAAI,CAAC,QAAQ,GAAG,KAAK,CAAC,QAAQ,CAAC;QAC/B,IAAI,CAAC,WAAW,GAAG,KAAK,CAAC,WAAW,CAAC;QACrC,IAAI,CAAC,YAAY,GAAG,KAAK,CAAC,YAAY,CAAC;IACzC,CAAC;CACF"}
|
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
export interface PngEvidenceMetadata {
|
|
2
|
+
viewport: "2d" | "3d" | "runtime";
|
|
3
|
+
width: number;
|
|
4
|
+
height: number;
|
|
5
|
+
viewportIndex?: number;
|
|
6
|
+
source?: "editor" | "runtime";
|
|
7
|
+
runId?: string;
|
|
8
|
+
generation?: number;
|
|
9
|
+
frameIndex?: number;
|
|
10
|
+
}
|
|
11
|
+
export interface EvidenceReference {
|
|
12
|
+
uri: `godot-mcp://evidence/${string}`;
|
|
13
|
+
observationUri: `godot-mcp://evidence/${string}`;
|
|
14
|
+
sha256: string;
|
|
15
|
+
mimeType: "image/png";
|
|
16
|
+
byteLength: number;
|
|
17
|
+
path: string;
|
|
18
|
+
observationPath: string;
|
|
19
|
+
}
|
|
20
|
+
export interface JsonEvidenceReference {
|
|
21
|
+
uri: `godot-mcp://evidence/${string}`;
|
|
22
|
+
observationUri: `godot-mcp://evidence/${string}`;
|
|
23
|
+
sha256: string;
|
|
24
|
+
mimeType: "application/json";
|
|
25
|
+
byteLength: number;
|
|
26
|
+
path: string;
|
|
27
|
+
observationPath: string;
|
|
28
|
+
}
|
|
29
|
+
export interface PngObservation {
|
|
30
|
+
data: Uint8Array;
|
|
31
|
+
sha256: string;
|
|
32
|
+
mimeType: "image/png";
|
|
33
|
+
byteLength: number;
|
|
34
|
+
width: number;
|
|
35
|
+
height: number;
|
|
36
|
+
observationUri: `godot-mcp://evidence/${string}`;
|
|
37
|
+
}
|
|
38
|
+
export interface PngBaselineManifest {
|
|
39
|
+
schemaVersion: 1;
|
|
40
|
+
comparisonContractVersion: 1;
|
|
41
|
+
name: string;
|
|
42
|
+
sha256: string;
|
|
43
|
+
mimeType: "image/png";
|
|
44
|
+
byteLength: number;
|
|
45
|
+
width: number;
|
|
46
|
+
height: number;
|
|
47
|
+
sourceObservationSha256: string;
|
|
48
|
+
createdAtUnixMs: number;
|
|
49
|
+
}
|
|
50
|
+
export declare class EvidenceStore {
|
|
51
|
+
private readonly projectRoot;
|
|
52
|
+
constructor(projectRoot: string);
|
|
53
|
+
putPng(sessionId: string, png: Uint8Array, metadata: PngEvidenceMetadata): Promise<EvidenceReference>;
|
|
54
|
+
readSessionPngObservation(sessionId: string, observationUri: string): Promise<PngObservation>;
|
|
55
|
+
putJson(sessionId: string, value: unknown, metadata: Record<string, unknown>): Promise<JsonEvidenceReference>;
|
|
56
|
+
createPngBaseline(sessionId: string, name: string, observationUri: string, createdAtUnixMs?: number): Promise<PngBaselineManifest>;
|
|
57
|
+
readPngBaseline(name: string): Promise<PngBaselineManifest>;
|
|
58
|
+
readPngBaselineData(name: string): Promise<{
|
|
59
|
+
manifest: PngBaselineManifest;
|
|
60
|
+
data: Uint8Array;
|
|
61
|
+
}>;
|
|
62
|
+
}
|
|
63
|
+
//# sourceMappingURL=evidenceStore.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"evidenceStore.d.ts","sourceRoot":"","sources":["../../src/evidence/evidenceStore.ts"],"names":[],"mappings":"AAeA,MAAM,WAAW,mBAAmB;IAClC,QAAQ,EAAE,IAAI,GAAG,IAAI,GAAG,SAAS,CAAC;IAClC,KAAK,EAAE,MAAM,CAAC;IACd,MAAM,EAAE,MAAM,CAAC;IACf,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,MAAM,CAAC,EAAE,QAAQ,GAAG,SAAS,CAAC;IAC9B,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,UAAU,CAAC,EAAE,MAAM,CAAC;CACrB;AAED,MAAM,WAAW,iBAAiB;IAChC,GAAG,EAAE,wBAAwB,MAAM,EAAE,CAAC;IACtC,cAAc,EAAE,wBAAwB,MAAM,EAAE,CAAC;IACjD,MAAM,EAAE,MAAM,CAAC;IACf,QAAQ,EAAE,WAAW,CAAC;IACtB,UAAU,EAAE,MAAM,CAAC;IACnB,IAAI,EAAE,MAAM,CAAC;IACb,eAAe,EAAE,MAAM,CAAC;CACzB;AAED,MAAM,WAAW,qBAAqB;IACpC,GAAG,EAAE,wBAAwB,MAAM,EAAE,CAAC;IACtC,cAAc,EAAE,wBAAwB,MAAM,EAAE,CAAC;IACjD,MAAM,EAAE,MAAM,CAAC;IACf,QAAQ,EAAE,kBAAkB,CAAC;IAC7B,UAAU,EAAE,MAAM,CAAC;IACnB,IAAI,EAAE,MAAM,CAAC;IACb,eAAe,EAAE,MAAM,CAAC;CACzB;AAED,MAAM,WAAW,cAAc;IAC7B,IAAI,EAAE,UAAU,CAAC;IACjB,MAAM,EAAE,MAAM,CAAC;IACf,QAAQ,EAAE,WAAW,CAAC;IACtB,UAAU,EAAE,MAAM,CAAC;IACnB,KAAK,EAAE,MAAM,CAAC;IACd,MAAM,EAAE,MAAM,CAAC;IACf,cAAc,EAAE,wBAAwB,MAAM,EAAE,CAAC;CAClD;AAED,MAAM,WAAW,mBAAmB;IAClC,aAAa,EAAE,CAAC,CAAC;IACjB,yBAAyB,EAAE,CAAC,CAAC;IAC7B,IAAI,EAAE,MAAM,CAAC;IACb,MAAM,EAAE,MAAM,CAAC;IACf,QAAQ,EAAE,WAAW,CAAC;IACtB,UAAU,EAAE,MAAM,CAAC;IACnB,KAAK,EAAE,MAAM,CAAC;IACd,MAAM,EAAE,MAAM,CAAC;IACf,uBAAuB,EAAE,MAAM,CAAC;IAChC,eAAe,EAAE,MAAM,CAAC;CACzB;AAkID,qBAAa,aAAa;IACZ,OAAO,CAAC,QAAQ,CAAC,WAAW;gBAAX,WAAW,EAAE,MAAM;IAE1C,MAAM,CACV,SAAS,EAAE,MAAM,EACjB,GAAG,EAAE,UAAU,EACf,QAAQ,EAAE,mBAAmB,GAC5B,OAAO,CAAC,iBAAiB,CAAC;IAoDvB,yBAAyB,CAAC,SAAS,EAAE,MAAM,EAAE,cAAc,EAAE,MAAM,GAAG,OAAO,CAAC,cAAc,CAAC;IAqD7F,OAAO,CAAC,SAAS,EAAE,MAAM,EAAE,KAAK,EAAE,OAAO,EAAE,QAAQ,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,OAAO,CAAC,qBAAqB,CAAC;IA+B7G,iBAAiB,CACrB,SAAS,EAAE,MAAM,EACjB,IAAI,EAAE,MAAM,EACZ,cAAc,EAAE,MAAM,EACtB,eAAe,SAAa,GAC3B,OAAO,CAAC,mBAAmB,CAAC;IAwCzB,eAAe,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,mBAAmB,CAAC;IAI3D,mBAAmB,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC;QAAE,QAAQ,EAAE,mBAAmB,CAAC;QAAC,IAAI,EAAE,UAAU,CAAA;KAAE,CAAC;CAkBtG"}
|