@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,63 @@
1
+ import { randomUUID } from "node:crypto";
2
+ import { lstat, readFile, writeFile } from "node:fs/promises";
3
+ import { join } from "node:path";
4
+ import { PRODUCT_VERSION } from "@godot-mcp/protocol";
5
+ import { z } from "zod";
6
+ import { GodotMcpException } from "../errors.js";
7
+ import { discoverProject } from "./projectIdentity.js";
8
+ export const ProjectConfigSchema = z.object({
9
+ schemaVersion: z.literal(1),
10
+ projectId: z.uuid(),
11
+ addonVersion: z.literal(PRODUCT_VERSION),
12
+ allowedResourceRoots: z.array(z.string()).default(["res://"]),
13
+ });
14
+ function invalidConfig(message) {
15
+ return new GodotMcpException({
16
+ code: "INVALID_REQUEST",
17
+ message,
18
+ retryable: false,
19
+ correlationId: randomUUID(),
20
+ partialEffects: false,
21
+ rollback: "not_needed",
22
+ });
23
+ }
24
+ async function readExistingConfig(path) {
25
+ const metadata = await lstat(path);
26
+ if (!metadata.isFile() || metadata.isSymbolicLink()) {
27
+ throw invalidConfig(".godot-mcp.json must be a regular project-local file");
28
+ }
29
+ try {
30
+ return ProjectConfigSchema.parse(JSON.parse(await readFile(path, "utf8")));
31
+ }
32
+ catch (error) {
33
+ if (error instanceof GodotMcpException) {
34
+ throw error;
35
+ }
36
+ throw invalidConfig(".godot-mcp.json is not a valid Godot MCP project configuration");
37
+ }
38
+ }
39
+ export async function createProjectConfig(root) {
40
+ const project = await discoverProject(root);
41
+ const path = join(project.rootRealPath, ".godot-mcp.json");
42
+ const config = ProjectConfigSchema.parse({
43
+ schemaVersion: 1,
44
+ projectId: randomUUID(),
45
+ addonVersion: PRODUCT_VERSION,
46
+ allowedResourceRoots: ["res://"],
47
+ });
48
+ try {
49
+ await writeFile(path, `${JSON.stringify(config, null, 2)}\n`, {
50
+ encoding: "utf8",
51
+ flag: "wx",
52
+ mode: 0o600,
53
+ });
54
+ return config;
55
+ }
56
+ catch (error) {
57
+ if (error.code !== "EEXIST") {
58
+ throw error;
59
+ }
60
+ return readExistingConfig(path);
61
+ }
62
+ }
63
+ //# sourceMappingURL=projectConfig.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"projectConfig.js","sourceRoot":"","sources":["../../src/project/projectConfig.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,MAAM,aAAa,CAAC;AACzC,OAAO,EAAE,KAAK,EAAE,QAAQ,EAAE,SAAS,EAAE,MAAM,kBAAkB,CAAC;AAC9D,OAAO,EAAE,IAAI,EAAE,MAAM,WAAW,CAAC;AAEjC,OAAO,EAAE,eAAe,EAAE,MAAM,qBAAqB,CAAC;AACtD,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAExB,OAAO,EAAE,iBAAiB,EAAE,MAAM,cAAc,CAAC;AACjD,OAAO,EAAE,eAAe,EAAE,MAAM,sBAAsB,CAAC;AAEvD,MAAM,CAAC,MAAM,mBAAmB,GAAG,CAAC,CAAC,MAAM,CAAC;IAC1C,aAAa,EAAE,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC;IAC3B,SAAS,EAAE,CAAC,CAAC,IAAI,EAAE;IACnB,YAAY,EAAE,CAAC,CAAC,OAAO,CAAC,eAAe,CAAC;IACxC,oBAAoB,EAAE,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,MAAM,EAAE,CAAC,CAAC,OAAO,CAAC,CAAC,QAAQ,CAAC,CAAC;CAC9D,CAAC,CAAC;AAIH,SAAS,aAAa,CAAC,OAAe;IACpC,OAAO,IAAI,iBAAiB,CAAC;QAC3B,IAAI,EAAE,iBAAiB;QACvB,OAAO;QACP,SAAS,EAAE,KAAK;QAChB,aAAa,EAAE,UAAU,EAAE;QAC3B,cAAc,EAAE,KAAK;QACrB,QAAQ,EAAE,YAAY;KACvB,CAAC,CAAC;AACL,CAAC;AAED,KAAK,UAAU,kBAAkB,CAAC,IAAY;IAC5C,MAAM,QAAQ,GAAG,MAAM,KAAK,CAAC,IAAI,CAAC,CAAC;IACnC,IAAI,CAAC,QAAQ,CAAC,MAAM,EAAE,IAAI,QAAQ,CAAC,cAAc,EAAE,EAAE,CAAC;QACpD,MAAM,aAAa,CAAC,sDAAsD,CAAC,CAAC;IAC9E,CAAC;IAED,IAAI,CAAC;QACH,OAAO,mBAAmB,CAAC,KAAK,CAAC,IAAI,CAAC,KAAK,CAAC,MAAM,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC,CAAC,CAAC,CAAC;IAC7E,CAAC;IAAC,OAAO,KAAK,EAAE,CAAC;QACf,IAAI,KAAK,YAAY,iBAAiB,EAAE,CAAC;YACvC,MAAM,KAAK,CAAC;QACd,CAAC;QACD,MAAM,aAAa,CAAC,gEAAgE,CAAC,CAAC;IACxF,CAAC;AACH,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,mBAAmB,CAAC,IAAY;IACpD,MAAM,OAAO,GAAG,MAAM,eAAe,CAAC,IAAI,CAAC,CAAC;IAC5C,MAAM,IAAI,GAAG,IAAI,CAAC,OAAO,CAAC,YAAY,EAAE,iBAAiB,CAAC,CAAC;IAC3D,MAAM,MAAM,GAAG,mBAAmB,CAAC,KAAK,CAAC;QACvC,aAAa,EAAE,CAAC;QAChB,SAAS,EAAE,UAAU,EAAE;QACvB,YAAY,EAAE,eAAe;QAC7B,oBAAoB,EAAE,CAAC,QAAQ,CAAC;KACjC,CAAC,CAAC;IAEH,IAAI,CAAC;QACH,MAAM,SAAS,CAAC,IAAI,EAAE,GAAG,IAAI,CAAC,SAAS,CAAC,MAAM,EAAE,IAAI,EAAE,CAAC,CAAC,IAAI,EAAE;YAC5D,QAAQ,EAAE,MAAM;YAChB,IAAI,EAAE,IAAI;YACV,IAAI,EAAE,KAAK;SACZ,CAAC,CAAC;QACH,OAAO,MAAM,CAAC;IAChB,CAAC;IAAC,OAAO,KAAK,EAAE,CAAC;QACf,IAAK,KAA+B,CAAC,IAAI,KAAK,QAAQ,EAAE,CAAC;YACvD,MAAM,KAAK,CAAC;QACd,CAAC;QACD,OAAO,kBAAkB,CAAC,IAAI,CAAC,CAAC;IAClC,CAAC;AACH,CAAC"}
@@ -0,0 +1,8 @@
1
+ import type { ProjectIdentity } from "@godot-mcp/protocol";
2
+ export interface DiscoveredProject {
3
+ rootRealPath: string;
4
+ projectFileRealPath: string;
5
+ }
6
+ export declare function discoverProject(inputPath: string): Promise<DiscoveredProject>;
7
+ export declare function readProjectIdentity(root: string): Promise<ProjectIdentity>;
8
+ //# sourceMappingURL=projectIdentity.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"projectIdentity.d.ts","sourceRoot":"","sources":["../../src/project/projectIdentity.ts"],"names":[],"mappings":"AAIA,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,qBAAqB,CAAC;AAK3D,MAAM,WAAW,iBAAiB;IAChC,YAAY,EAAE,MAAM,CAAC;IACrB,mBAAmB,EAAE,MAAM,CAAC;CAC7B;AAaD,wBAAsB,eAAe,CAAC,SAAS,EAAE,MAAM,GAAG,OAAO,CAAC,iBAAiB,CAAC,CA8BnF;AAED,wBAAsB,mBAAmB,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,eAAe,CAAC,CAUhF"}
@@ -0,0 +1,58 @@
1
+ import { createHash, randomUUID } from "node:crypto";
2
+ import { realpath, readFile, stat } from "node:fs/promises";
3
+ import { basename, dirname, join } from "node:path";
4
+ import { GodotMcpException } from "../errors.js";
5
+ import { createProjectConfig } from "./projectConfig.js";
6
+ function invalidProject(message) {
7
+ return new GodotMcpException({
8
+ code: "INVALID_REQUEST",
9
+ message,
10
+ retryable: false,
11
+ correlationId: randomUUID(),
12
+ partialEffects: false,
13
+ rollback: "not_needed",
14
+ });
15
+ }
16
+ export async function discoverProject(inputPath) {
17
+ let inputMetadata;
18
+ try {
19
+ inputMetadata = await stat(inputPath);
20
+ }
21
+ catch {
22
+ throw invalidProject("The supplied Godot project path does not exist");
23
+ }
24
+ let rootInput;
25
+ if (inputMetadata.isDirectory()) {
26
+ rootInput = inputPath;
27
+ }
28
+ else if (inputMetadata.isFile() && basename(inputPath) === "project.godot") {
29
+ rootInput = dirname(inputPath);
30
+ }
31
+ else {
32
+ throw invalidProject("Supply a Godot project directory or its project.godot file");
33
+ }
34
+ const rootRealPath = await realpath(rootInput);
35
+ const projectFile = join(rootRealPath, "project.godot");
36
+ let projectMetadata;
37
+ try {
38
+ projectMetadata = await stat(projectFile);
39
+ }
40
+ catch {
41
+ throw invalidProject("The supplied directory does not contain project.godot");
42
+ }
43
+ if (!projectMetadata.isFile()) {
44
+ throw invalidProject("project.godot must be a regular file");
45
+ }
46
+ return { rootRealPath, projectFileRealPath: await realpath(projectFile) };
47
+ }
48
+ export async function readProjectIdentity(root) {
49
+ const project = await discoverProject(root);
50
+ const config = await createProjectConfig(project.rootRealPath);
51
+ const projectContents = await readFile(project.projectFileRealPath);
52
+ return {
53
+ projectId: config.projectId,
54
+ rootRealPath: project.rootRealPath,
55
+ projectConfigSha256: createHash("sha256").update(projectContents).digest("hex"),
56
+ };
57
+ }
58
+ //# sourceMappingURL=projectIdentity.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"projectIdentity.js","sourceRoot":"","sources":["../../src/project/projectIdentity.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,UAAU,EAAE,MAAM,aAAa,CAAC;AACrD,OAAO,EAAE,QAAQ,EAAE,QAAQ,EAAE,IAAI,EAAE,MAAM,kBAAkB,CAAC;AAC5D,OAAO,EAAE,QAAQ,EAAE,OAAO,EAAE,IAAI,EAAE,MAAM,WAAW,CAAC;AAIpD,OAAO,EAAE,iBAAiB,EAAE,MAAM,cAAc,CAAC;AACjD,OAAO,EAAE,mBAAmB,EAAE,MAAM,oBAAoB,CAAC;AAOzD,SAAS,cAAc,CAAC,OAAe;IACrC,OAAO,IAAI,iBAAiB,CAAC;QAC3B,IAAI,EAAE,iBAAiB;QACvB,OAAO;QACP,SAAS,EAAE,KAAK;QAChB,aAAa,EAAE,UAAU,EAAE;QAC3B,cAAc,EAAE,KAAK;QACrB,QAAQ,EAAE,YAAY;KACvB,CAAC,CAAC;AACL,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,eAAe,CAAC,SAAiB;IACrD,IAAI,aAAa,CAAC;IAClB,IAAI,CAAC;QACH,aAAa,GAAG,MAAM,IAAI,CAAC,SAAS,CAAC,CAAC;IACxC,CAAC;IAAC,MAAM,CAAC;QACP,MAAM,cAAc,CAAC,gDAAgD,CAAC,CAAC;IACzE,CAAC;IAED,IAAI,SAAiB,CAAC;IACtB,IAAI,aAAa,CAAC,WAAW,EAAE,EAAE,CAAC;QAChC,SAAS,GAAG,SAAS,CAAC;IACxB,CAAC;SAAM,IAAI,aAAa,CAAC,MAAM,EAAE,IAAI,QAAQ,CAAC,SAAS,CAAC,KAAK,eAAe,EAAE,CAAC;QAC7E,SAAS,GAAG,OAAO,CAAC,SAAS,CAAC,CAAC;IACjC,CAAC;SAAM,CAAC;QACN,MAAM,cAAc,CAAC,4DAA4D,CAAC,CAAC;IACrF,CAAC;IAED,MAAM,YAAY,GAAG,MAAM,QAAQ,CAAC,SAAS,CAAC,CAAC;IAC/C,MAAM,WAAW,GAAG,IAAI,CAAC,YAAY,EAAE,eAAe,CAAC,CAAC;IACxD,IAAI,eAAe,CAAC;IACpB,IAAI,CAAC;QACH,eAAe,GAAG,MAAM,IAAI,CAAC,WAAW,CAAC,CAAC;IAC5C,CAAC;IAAC,MAAM,CAAC;QACP,MAAM,cAAc,CAAC,uDAAuD,CAAC,CAAC;IAChF,CAAC;IACD,IAAI,CAAC,eAAe,CAAC,MAAM,EAAE,EAAE,CAAC;QAC9B,MAAM,cAAc,CAAC,sCAAsC,CAAC,CAAC;IAC/D,CAAC;IAED,OAAO,EAAE,YAAY,EAAE,mBAAmB,EAAE,MAAM,QAAQ,CAAC,WAAW,CAAC,EAAE,CAAC;AAC5E,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,mBAAmB,CAAC,IAAY;IACpD,MAAM,OAAO,GAAG,MAAM,eAAe,CAAC,IAAI,CAAC,CAAC;IAC5C,MAAM,MAAM,GAAG,MAAM,mBAAmB,CAAC,OAAO,CAAC,YAAY,CAAC,CAAC;IAC/D,MAAM,eAAe,GAAG,MAAM,QAAQ,CAAC,OAAO,CAAC,mBAAmB,CAAC,CAAC;IAEpE,OAAO;QACL,SAAS,EAAE,MAAM,CAAC,SAAS;QAC3B,YAAY,EAAE,OAAO,CAAC,YAAY;QAClC,mBAAmB,EAAE,UAAU,CAAC,QAAQ,CAAC,CAAC,MAAM,CAAC,eAAe,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC;KAChF,CAAC;AACJ,CAAC"}
@@ -0,0 +1,49 @@
1
+ import { z } from "zod";
2
+ declare const SnapshotSchema: z.ZodObject<{
3
+ schemaVersion: z.ZodLiteral<1>;
4
+ projectId: z.ZodUUID;
5
+ jobToken: z.ZodString;
6
+ sessionId: z.ZodString;
7
+ operation: z.ZodEnum<{
8
+ run: "run";
9
+ reimport: "reimport";
10
+ import: "import";
11
+ build: "build";
12
+ export: "export";
13
+ }>;
14
+ state: z.ZodEnum<{
15
+ queued: "queued";
16
+ running: "running";
17
+ completed: "completed";
18
+ failed: "failed";
19
+ cancelled: "cancelled";
20
+ }>;
21
+ pid: z.ZodOptional<z.ZodNumber>;
22
+ fingerprint: z.ZodOptional<z.ZodString>;
23
+ artifactName: z.ZodOptional<z.ZodString>;
24
+ recovery: z.ZodOptional<z.ZodEnum<{
25
+ stopped: "stopped";
26
+ missing: "missing";
27
+ ambiguous: "ambiguous";
28
+ }>>;
29
+ artifactRecovery: z.ZodOptional<z.ZodEnum<{
30
+ rejected: "rejected";
31
+ not_applicable: "not_applicable";
32
+ clean: "clean";
33
+ absent: "absent";
34
+ }>>;
35
+ recordedAt: z.ZodString;
36
+ }, z.core.$strict>;
37
+ export type ProjectJobJournalSnapshot = z.infer<typeof SnapshotSchema>;
38
+ export declare class ProjectJobJournal {
39
+ private readonly path;
40
+ private readonly latest;
41
+ private tail;
42
+ static open(path: string): Promise<ProjectJobJournal>;
43
+ private constructor();
44
+ nonterminal(projectId: string): ProjectJobJournalSnapshot[];
45
+ append(input: Omit<ProjectJobJournalSnapshot, "schemaVersion" | "recordedAt">): Promise<void>;
46
+ private remember;
47
+ }
48
+ export {};
49
+ //# sourceMappingURL=projectJobJournal.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"projectJobJournal.d.ts","sourceRoot":"","sources":["../../src/project/projectJobJournal.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAKxB,QAAA,MAAM,cAAc;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;kBAasH,CAAC;AAE3I,MAAM,MAAM,yBAAyB,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,cAAc,CAAC,CAAC;AAEvE,qBAAa,iBAAiB;IAoBR,OAAO,CAAC,QAAQ,CAAC,IAAI;IAnBzC,OAAO,CAAC,QAAQ,CAAC,MAAM,CAAgD;IACvE,OAAO,CAAC,IAAI,CAAuC;WAEtC,IAAI,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,iBAAiB,CAAC;IAgB3D,OAAO;IAEP,WAAW,CAAC,SAAS,EAAE,MAAM,GAAG,yBAAyB,EAAE;IAIrD,MAAM,CAAC,KAAK,EAAE,IAAI,CAAC,yBAAyB,EAAE,eAAe,GAAG,YAAY,CAAC,GAAG,OAAO,CAAC,IAAI,CAAC;IAUnG,OAAO,CAAC,QAAQ;CAKjB"}
@@ -0,0 +1,67 @@
1
+ import { z } from "zod";
2
+ import { appendSecureJournal, readSecureJournal } from "./secureJournalFile.js";
3
+ const MAX_BYTES = 4 * 1024 * 1024;
4
+ const SnapshotSchema = z.object({
5
+ schemaVersion: z.literal(1),
6
+ projectId: z.uuid(),
7
+ jobToken: z.string().regex(/^pjob_[A-Za-z0-9_-]{43}$/),
8
+ sessionId: z.string().min(8).max(256),
9
+ operation: z.enum(["import", "reimport", "run", "build", "export"]),
10
+ state: z.enum(["queued", "running", "completed", "failed", "cancelled"]),
11
+ pid: z.number().int().positive().optional(),
12
+ fingerprint: z.string().min(3).max(256).optional(),
13
+ artifactName: z.string().regex(/^[A-Za-z0-9][A-Za-z0-9_-]{0,63}$/).optional(),
14
+ recovery: z.enum(["stopped", "missing", "ambiguous"]).optional(),
15
+ artifactRecovery: z.enum(["not_applicable", "clean", "rejected", "absent"]).optional(),
16
+ recordedAt: z.string().datetime(),
17
+ }).strict().refine((value) => (value.pid === undefined) === (value.fingerprint === undefined), "PID and fingerprint must appear together");
18
+ export class ProjectJobJournal {
19
+ path;
20
+ latest = new Map();
21
+ tail = Promise.resolve();
22
+ static async open(path) {
23
+ const journal = new ProjectJobJournal(path);
24
+ try {
25
+ const text = await readSecureJournal(path, MAX_BYTES);
26
+ if (text === null)
27
+ return journal;
28
+ for (const [index, line] of text.split("\n").entries()) {
29
+ if (!line)
30
+ continue;
31
+ try {
32
+ journal.remember(SnapshotSchema.parse(JSON.parse(line)));
33
+ }
34
+ catch {
35
+ throw new Error(`Project job journal record ${index + 1} is malformed`);
36
+ }
37
+ }
38
+ }
39
+ catch (error) {
40
+ if (error.code !== "ENOENT")
41
+ throw error;
42
+ }
43
+ return journal;
44
+ }
45
+ constructor(path) {
46
+ this.path = path;
47
+ }
48
+ nonterminal(projectId) {
49
+ return [...this.latest.values()].filter((record) => record.projectId === projectId && ["queued", "running"].includes(record.state));
50
+ }
51
+ async append(input) {
52
+ const record = SnapshotSchema.parse({ ...input, schemaVersion: 1, recordedAt: new Date().toISOString() });
53
+ const write = this.tail.then(async () => {
54
+ await appendSecureJournal(this.path, `${JSON.stringify(record)}\n`);
55
+ this.remember(record);
56
+ });
57
+ this.tail = write.catch(() => undefined);
58
+ await write;
59
+ }
60
+ remember(record) {
61
+ this.latest.delete(record.jobToken);
62
+ this.latest.set(record.jobToken, record);
63
+ while (this.latest.size > 256)
64
+ this.latest.delete(this.latest.keys().next().value);
65
+ }
66
+ }
67
+ //# sourceMappingURL=projectJobJournal.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"projectJobJournal.js","sourceRoot":"","sources":["../../src/project/projectJobJournal.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAExB,OAAO,EAAE,mBAAmB,EAAE,iBAAiB,EAAE,MAAM,wBAAwB,CAAC;AAEhF,MAAM,SAAS,GAAG,CAAC,GAAG,IAAI,GAAG,IAAI,CAAC;AAClC,MAAM,cAAc,GAAG,CAAC,CAAC,MAAM,CAAC;IAC9B,aAAa,EAAE,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC;IAC3B,SAAS,EAAE,CAAC,CAAC,IAAI,EAAE;IACnB,QAAQ,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,KAAK,CAAC,0BAA0B,CAAC;IACtD,SAAS,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,GAAG,CAAC;IACrC,SAAS,EAAE,CAAC,CAAC,IAAI,CAAC,CAAC,QAAQ,EAAE,UAAU,EAAE,KAAK,EAAE,OAAO,EAAE,QAAQ,CAAC,CAAC;IACnE,KAAK,EAAE,CAAC,CAAC,IAAI,CAAC,CAAC,QAAQ,EAAE,SAAS,EAAE,WAAW,EAAE,QAAQ,EAAE,WAAW,CAAC,CAAC;IACxE,GAAG,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,GAAG,EAAE,CAAC,QAAQ,EAAE,CAAC,QAAQ,EAAE;IAC3C,WAAW,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC,QAAQ,EAAE;IAClD,YAAY,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,KAAK,CAAC,kCAAkC,CAAC,CAAC,QAAQ,EAAE;IAC7E,QAAQ,EAAE,CAAC,CAAC,IAAI,CAAC,CAAC,SAAS,EAAE,SAAS,EAAE,WAAW,CAAC,CAAC,CAAC,QAAQ,EAAE;IAChE,gBAAgB,EAAE,CAAC,CAAC,IAAI,CAAC,CAAC,gBAAgB,EAAE,OAAO,EAAE,UAAU,EAAE,QAAQ,CAAC,CAAC,CAAC,QAAQ,EAAE;IACtF,UAAU,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,EAAE;CAClC,CAAC,CAAC,MAAM,EAAE,CAAC,MAAM,CAAC,CAAC,KAAK,EAAE,EAAE,CAAC,CAAC,KAAK,CAAC,GAAG,KAAK,SAAS,CAAC,KAAK,CAAC,KAAK,CAAC,WAAW,KAAK,SAAS,CAAC,EAAE,0CAA0C,CAAC,CAAC;AAI3I,MAAM,OAAO,iBAAiB;IAoBS;IAnBpB,MAAM,GAAG,IAAI,GAAG,EAAqC,CAAC;IAC/D,IAAI,GAAqB,OAAO,CAAC,OAAO,EAAE,CAAC;IAEnD,MAAM,CAAC,KAAK,CAAC,IAAI,CAAC,IAAY;QAC5B,MAAM,OAAO,GAAG,IAAI,iBAAiB,CAAC,IAAI,CAAC,CAAC;QAC5C,IAAI,CAAC;YACH,MAAM,IAAI,GAAG,MAAM,iBAAiB,CAAC,IAAI,EAAE,SAAS,CAAC,CAAC;YACtD,IAAI,IAAI,KAAK,IAAI;gBAAE,OAAO,OAAO,CAAC;YAClC,KAAK,MAAM,CAAC,KAAK,EAAE,IAAI,CAAC,IAAI,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC,OAAO,EAAE,EAAE,CAAC;gBACvD,IAAI,CAAC,IAAI;oBAAE,SAAS;gBACpB,IAAI,CAAC;oBAAC,OAAO,CAAC,QAAQ,CAAC,cAAc,CAAC,KAAK,CAAC,IAAI,CAAC,KAAK,CAAC,IAAI,CAAY,CAAC,CAAC,CAAC;gBAAC,CAAC;gBAC5E,MAAM,CAAC;oBAAC,MAAM,IAAI,KAAK,CAAC,8BAA8B,KAAK,GAAG,CAAC,eAAe,CAAC,CAAC;gBAAC,CAAC;YACpF,CAAC;QACH,CAAC;QAAC,OAAO,KAAK,EAAE,CAAC;YACf,IAAK,KAA+B,CAAC,IAAI,KAAK,QAAQ;gBAAE,MAAM,KAAK,CAAC;QACtE,CAAC;QACD,OAAO,OAAO,CAAC;IACjB,CAAC;IAED,YAAqC,IAAY;QAAZ,SAAI,GAAJ,IAAI,CAAQ;IAAG,CAAC;IAErD,WAAW,CAAC,SAAiB;QAC3B,OAAO,CAAC,GAAG,IAAI,CAAC,MAAM,CAAC,MAAM,EAAE,CAAC,CAAC,MAAM,CAAC,CAAC,MAAM,EAAE,EAAE,CAAC,MAAM,CAAC,SAAS,KAAK,SAAS,IAAI,CAAC,QAAQ,EAAE,SAAS,CAAC,CAAC,QAAQ,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC,CAAC;IACtI,CAAC;IAED,KAAK,CAAC,MAAM,CAAC,KAAsE;QACjF,MAAM,MAAM,GAAG,cAAc,CAAC,KAAK,CAAC,EAAE,GAAG,KAAK,EAAE,aAAa,EAAE,CAAC,EAAE,UAAU,EAAE,IAAI,IAAI,EAAE,CAAC,WAAW,EAAE,EAAE,CAAC,CAAC;QAC1G,MAAM,KAAK,GAAG,IAAI,CAAC,IAAI,CAAC,IAAI,CAAC,KAAK,IAAI,EAAE;YACtC,MAAM,mBAAmB,CAAC,IAAI,CAAC,IAAI,EAAE,GAAG,IAAI,CAAC,SAAS,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC;YACpE,IAAI,CAAC,QAAQ,CAAC,MAAM,CAAC,CAAC;QACxB,CAAC,CAAC,CAAC;QACH,IAAI,CAAC,IAAI,GAAG,KAAK,CAAC,KAAK,CAAC,GAAG,EAAE,CAAC,SAAS,CAAC,CAAC;QACzC,MAAM,KAAK,CAAC;IACd,CAAC;IAEO,QAAQ,CAAC,MAAiC;QAChD,IAAI,CAAC,MAAM,CAAC,MAAM,CAAC,MAAM,CAAC,QAAQ,CAAC,CAAC;QACpC,IAAI,CAAC,MAAM,CAAC,GAAG,CAAC,MAAM,CAAC,QAAQ,EAAE,MAAM,CAAC,CAAC;QACzC,OAAO,IAAI,CAAC,MAAM,CAAC,IAAI,GAAG,GAAG;YAAE,IAAI,CAAC,MAAM,CAAC,MAAM,CAAC,IAAI,CAAC,MAAM,CAAC,IAAI,EAAE,CAAC,IAAI,EAAE,CAAC,KAAe,CAAC,CAAC;IAC/F,CAAC;CACF"}
@@ -0,0 +1,52 @@
1
+ import { type ProjectJobReceipt, type ProjectOperationInput, type ProjectOperationResult } from "@godot-mcp/protocol";
2
+ import { EvidenceStore } from "../evidence/evidenceStore.js";
3
+ import type { ArtifactStore } from "./artifactStore.js";
4
+ import type { ProjectJobJournal } from "./projectJobJournal.js";
5
+ import type { ProjectProcessInput } from "./projectProcess.js";
6
+ type ProjectJobStartInput = Extract<ProjectOperationInput, {
7
+ operation: "import_start" | "run_start" | "build_start" | "export_start";
8
+ }>;
9
+ export interface ProjectJobProcess {
10
+ readonly pid: number;
11
+ readonly fingerprint: string;
12
+ wait(): Promise<number>;
13
+ stop(graceMs?: number): Promise<void>;
14
+ diagnostics?(): string;
15
+ }
16
+ export interface ProjectJobServiceDependencies {
17
+ projectId: string;
18
+ projectRoot: string;
19
+ sessionId(): string | null;
20
+ artifacts: ArtifactStore;
21
+ launch(input: ProjectProcessInput): Promise<ProjectJobProcess>;
22
+ reimport?(resourcePaths: string[]): Promise<void>;
23
+ evidence?: EvidenceStore;
24
+ now?: () => number;
25
+ journal?: ProjectJobJournal;
26
+ recoverProcess?(pid: number, fingerprint: string): Promise<"stopped" | "missing" | "ambiguous">;
27
+ preflight?(input: ProjectJobStartInput): Promise<void>;
28
+ conflictReason?(input: ProjectJobStartInput): string | null;
29
+ }
30
+ export declare class ProjectJobService {
31
+ private readonly dependencies;
32
+ private job;
33
+ private runPromise;
34
+ private readonly evidence;
35
+ private readonly now;
36
+ constructor(dependencies: ProjectJobServiceDependencies);
37
+ recover(): Promise<void>;
38
+ start(rawInput: ProjectJobStartInput): ProjectJobReceipt;
39
+ status(jobToken: string): ProjectJobReceipt;
40
+ cancel(jobToken: string): ProjectJobReceipt;
41
+ result(jobToken: string): ProjectOperationResult;
42
+ close(): Promise<void>;
43
+ private requireJob;
44
+ private receipt;
45
+ private assertActive;
46
+ private boundary;
47
+ private nonInterruptibleBoundary;
48
+ private run;
49
+ private record;
50
+ }
51
+ export {};
52
+ //# sourceMappingURL=projectJobService.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"projectJobService.d.ts","sourceRoot":"","sources":["../../src/project/projectJobService.ts"],"names":[],"mappings":"AAGA,OAAO,EAIL,KAAK,iBAAiB,EACtB,KAAK,qBAAqB,EAC1B,KAAK,sBAAsB,EAC5B,MAAM,qBAAqB,CAAC;AAG7B,OAAO,EAAE,aAAa,EAAE,MAAM,8BAA8B,CAAC;AAC7D,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,oBAAoB,CAAC;AACxD,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,wBAAwB,CAAC;AAChE,OAAO,KAAK,EAAE,mBAAmB,EAAE,MAAM,qBAAqB,CAAC;AAE/D,KAAK,oBAAoB,GAAG,OAAO,CAAC,qBAAqB,EAAE;IACzD,SAAS,EAAE,cAAc,GAAG,WAAW,GAAG,aAAa,GAAG,cAAc,CAAC;CAC1E,CAAC,CAAC;AAIH,MAAM,WAAW,iBAAiB;IAChC,QAAQ,CAAC,GAAG,EAAE,MAAM,CAAC;IACrB,QAAQ,CAAC,WAAW,EAAE,MAAM,CAAC;IAC7B,IAAI,IAAI,OAAO,CAAC,MAAM,CAAC,CAAC;IACxB,IAAI,CAAC,OAAO,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;IACtC,WAAW,CAAC,IAAI,MAAM,CAAC;CACxB;AAED,MAAM,WAAW,6BAA6B;IAC5C,SAAS,EAAE,MAAM,CAAC;IAClB,WAAW,EAAE,MAAM,CAAC;IACpB,SAAS,IAAI,MAAM,GAAG,IAAI,CAAC;IAC3B,SAAS,EAAE,aAAa,CAAC;IACzB,MAAM,CAAC,KAAK,EAAE,mBAAmB,GAAG,OAAO,CAAC,iBAAiB,CAAC,CAAC;IAC/D,QAAQ,CAAC,CAAC,aAAa,EAAE,MAAM,EAAE,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;IAClD,QAAQ,CAAC,EAAE,aAAa,CAAC;IACzB,GAAG,CAAC,EAAE,MAAM,MAAM,CAAC;IACnB,OAAO,CAAC,EAAE,iBAAiB,CAAC;IAC5B,cAAc,CAAC,CAAC,GAAG,EAAE,MAAM,EAAE,WAAW,EAAE,MAAM,GAAG,OAAO,CAAC,SAAS,GAAG,SAAS,GAAG,WAAW,CAAC,CAAC;IAChG,SAAS,CAAC,CAAC,KAAK,EAAE,oBAAoB,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;IACvD,cAAc,CAAC,CAAC,KAAK,EAAE,oBAAoB,GAAG,MAAM,GAAG,IAAI,CAAC;CAC7D;AAyCD,qBAAa,iBAAiB;IAMhB,OAAO,CAAC,QAAQ,CAAC,YAAY;IALzC,OAAO,CAAC,GAAG,CAAyB;IACpC,OAAO,CAAC,UAAU,CAA4B;IAC9C,OAAO,CAAC,QAAQ,CAAC,QAAQ,CAAgB;IACzC,OAAO,CAAC,QAAQ,CAAC,GAAG,CAAe;gBAEN,YAAY,EAAE,6BAA6B;IAKlE,OAAO,IAAI,OAAO,CAAC,IAAI,CAAC;IA8B9B,KAAK,CAAC,QAAQ,EAAE,oBAAoB,GAAG,iBAAiB;IA2BxD,MAAM,CAAC,QAAQ,EAAE,MAAM,GAAG,iBAAiB;IAI3C,MAAM,CAAC,QAAQ,EAAE,MAAM,GAAG,iBAAiB;IAM3C,MAAM,CAAC,QAAQ,EAAE,MAAM,GAAG,sBAAsB;IAM1C,KAAK,IAAI,OAAO,CAAC,IAAI,CAAC;IAU5B,OAAO,CAAC,UAAU;IAMlB,OAAO,CAAC,OAAO;IAWf,OAAO,CAAC,YAAY;YAKN,QAAQ;YAoBR,wBAAwB;YAOxB,GAAG;YAwFH,MAAM;CAYrB"}
@@ -0,0 +1,289 @@
1
+ import { randomBytes, randomUUID } from "node:crypto";
2
+ import { join } from "node:path";
3
+ import { ProjectJobReceiptSchema, ProjectOperationInputSchema, ProjectOperationResultSchema, } from "@godot-mcp/protocol";
4
+ import { GodotMcpException } from "../errors.js";
5
+ import { EvidenceStore } from "../evidence/evidenceStore.js";
6
+ function jobError(code, message) {
7
+ return new GodotMcpException({
8
+ code,
9
+ message,
10
+ retryable: false,
11
+ correlationId: randomUUID(),
12
+ partialEffects: false,
13
+ rollback: "not_needed",
14
+ });
15
+ }
16
+ function errorCode(error) {
17
+ return typeof error === "object" && error !== null && "code" in error && typeof error.code === "string"
18
+ ? error.code
19
+ : "GODOT_RUNTIME_ERROR";
20
+ }
21
+ function operationFor(input) {
22
+ if (input.operation === "import_start")
23
+ return input.kind === "full" ? "import" : "reimport";
24
+ if (input.operation === "run_start")
25
+ return "run";
26
+ if (input.operation === "build_start")
27
+ return "build";
28
+ return "export";
29
+ }
30
+ export class ProjectJobService {
31
+ dependencies;
32
+ job;
33
+ runPromise;
34
+ evidence;
35
+ now;
36
+ constructor(dependencies) {
37
+ this.dependencies = dependencies;
38
+ this.evidence = dependencies.evidence ?? new EvidenceStore(dependencies.projectRoot);
39
+ this.now = dependencies.now ?? (() => Date.now());
40
+ }
41
+ async recover() {
42
+ if (!this.dependencies.journal)
43
+ return;
44
+ for (const record of this.dependencies.journal.nonterminal(this.dependencies.projectId)) {
45
+ const recovery = record.pid !== undefined && record.fingerprint !== undefined && this.dependencies.recoverProcess
46
+ ? await this.dependencies.recoverProcess(record.pid, record.fingerprint)
47
+ : "ambiguous";
48
+ let artifactRecovery = "not_applicable";
49
+ if (record.operation === "export" && record.artifactName) {
50
+ try {
51
+ await this.dependencies.artifacts.finalize(record.jobToken, record.artifactName);
52
+ artifactRecovery = "clean";
53
+ }
54
+ catch (error) {
55
+ artifactRecovery = errorCode(error) === "PRECONDITION_FAILED" ? "absent" : "rejected";
56
+ }
57
+ }
58
+ await this.evidence.putJson(record.sessionId, { operation: record.operation, recovery, artifactRecovery }, { kind: "project_job_recovery" }).catch(() => undefined);
59
+ await this.dependencies.journal.append({
60
+ projectId: record.projectId,
61
+ jobToken: record.jobToken,
62
+ sessionId: record.sessionId,
63
+ operation: record.operation,
64
+ state: "failed",
65
+ ...(record.pid === undefined ? {} : { pid: record.pid, fingerprint: record.fingerprint }),
66
+ ...(record.artifactName === undefined ? {} : { artifactName: record.artifactName }),
67
+ recovery,
68
+ artifactRecovery,
69
+ });
70
+ }
71
+ }
72
+ start(rawInput) {
73
+ if (this.job && (this.job.state === "queued" || this.job.state === "running"))
74
+ throw jobError("CONFLICT", "A project operation job is already active");
75
+ const sessionId = this.dependencies.sessionId();
76
+ if (!sessionId)
77
+ throw jobError("NOT_ATTACHED", "Godot editor addon is not attached");
78
+ const parsed = ProjectOperationInputSchema.parse(rawInput);
79
+ if (!["import_start", "run_start", "build_start", "export_start"].includes(parsed.operation))
80
+ throw jobError("CONFLICT", "Operation does not start a project job");
81
+ const input = parsed;
82
+ const conflict = this.dependencies.conflictReason?.(input);
83
+ if (conflict)
84
+ throw jobError("CONFLICT", conflict);
85
+ const job = {
86
+ token: `pjob_${randomBytes(32).toString("base64url")}`,
87
+ sessionId,
88
+ input,
89
+ operation: operationFor(input),
90
+ state: "queued",
91
+ phase: "validating",
92
+ progressMillionths: 0,
93
+ cancellationSafe: true,
94
+ deadlineAtMs: Math.floor(this.now()) + input.deadlineMs,
95
+ controller: new AbortController(),
96
+ };
97
+ this.job = job;
98
+ this.runPromise = Promise.resolve().then(() => this.run(job));
99
+ void this.runPromise.catch(() => undefined);
100
+ return this.receipt(job);
101
+ }
102
+ status(jobToken) {
103
+ return this.receipt(this.requireJob(jobToken));
104
+ }
105
+ cancel(jobToken) {
106
+ const job = this.requireJob(jobToken);
107
+ if (job.state === "queued" || job.state === "running")
108
+ job.controller.abort(jobError("CANCELLED", "Project operation was cancelled"));
109
+ return this.receipt(job);
110
+ }
111
+ result(jobToken) {
112
+ const job = this.requireJob(jobToken);
113
+ if (!job.result)
114
+ throw jobError("CONFLICT", "Project operation result is not terminal");
115
+ return ProjectOperationResultSchema.parse(job.result);
116
+ }
117
+ async close() {
118
+ const job = this.job;
119
+ if (!job)
120
+ return;
121
+ if (["queued", "running"].includes(job.state)) {
122
+ job.controller.abort(jobError("CANCELLED", "Project job service closed"));
123
+ await job.process?.stop().catch(() => undefined);
124
+ }
125
+ await this.runPromise;
126
+ }
127
+ requireJob(jobToken) {
128
+ const job = this.job;
129
+ if (!job || job.token !== jobToken || this.dependencies.sessionId() !== job.sessionId)
130
+ throw jobError("STALE_HANDLE", "Project job token is stale or belongs to another session");
131
+ return job;
132
+ }
133
+ receipt(job) {
134
+ return ProjectJobReceiptSchema.parse({
135
+ jobToken: job.token,
136
+ operation: job.operation,
137
+ state: job.state,
138
+ phase: job.phase,
139
+ progressMillionths: job.progressMillionths,
140
+ cancellationSafe: job.cancellationSafe,
141
+ });
142
+ }
143
+ assertActive(job) {
144
+ if (job.controller.signal.aborted)
145
+ throw job.controller.signal.reason ?? jobError("CANCELLED", "Project operation was cancelled");
146
+ if (Math.floor(this.now()) >= job.deadlineAtMs)
147
+ throw jobError("TIMEOUT", "Project operation deadline expired");
148
+ }
149
+ async boundary(job, promiseFactory) {
150
+ this.assertActive(job);
151
+ const remaining = job.deadlineAtMs - Math.floor(this.now());
152
+ let timeout;
153
+ let abortListener;
154
+ const operation = promiseFactory();
155
+ operation.catch(() => undefined);
156
+ const interruption = new Promise((_resolve, reject) => {
157
+ timeout = setTimeout(() => reject(jobError("TIMEOUT", "Project operation deadline expired")), remaining);
158
+ abortListener = () => reject(job.controller.signal.reason ?? jobError("CANCELLED", "Project operation was cancelled"));
159
+ job.controller.signal.addEventListener("abort", abortListener, { once: true });
160
+ });
161
+ try {
162
+ return await Promise.race([operation, interruption]);
163
+ }
164
+ finally {
165
+ if (timeout)
166
+ clearTimeout(timeout);
167
+ if (abortListener)
168
+ job.controller.signal.removeEventListener("abort", abortListener);
169
+ }
170
+ }
171
+ async nonInterruptibleBoundary(job, promiseFactory) {
172
+ this.assertActive(job);
173
+ const result = await promiseFactory();
174
+ this.assertActive(job);
175
+ return result;
176
+ }
177
+ async run(job) {
178
+ if (this.job !== job)
179
+ return;
180
+ job.state = "running";
181
+ job.phase = "preparing";
182
+ let exitCode = null;
183
+ let terminalState = "failed";
184
+ let artifact;
185
+ try {
186
+ await this.record(job);
187
+ await this.dependencies.preflight?.(job.input);
188
+ this.assertActive(job);
189
+ if (job.operation === "reimport") {
190
+ if (!this.dependencies.reimport)
191
+ throw jobError("GODOT_RUNTIME_ERROR", "Selective reimport transport is unavailable");
192
+ job.phase = "executing";
193
+ job.progressMillionths = 250_000;
194
+ job.cancellationSafe = false;
195
+ await this.nonInterruptibleBoundary(job, () => this.dependencies.reimport(job.input.resourcePaths));
196
+ job.cancellationSafe = true;
197
+ job.progressMillionths = 900_000;
198
+ }
199
+ else {
200
+ let processInput;
201
+ if (job.input.operation === "import_start")
202
+ processInput = { operation: "import", projectRoot: this.dependencies.projectRoot };
203
+ else if (job.input.operation === "run_start")
204
+ processInput = {
205
+ operation: "run",
206
+ projectRoot: this.dependencies.projectRoot,
207
+ headless: job.input.headless,
208
+ ...(job.input.scenePath ? { scenePath: job.input.scenePath } : {}),
209
+ };
210
+ else if (job.input.operation === "build_start")
211
+ processInput = { operation: "build", projectRoot: this.dependencies.projectRoot };
212
+ else {
213
+ const allocated = await this.dependencies.artifacts.allocate(job.token, job.input.artifactName);
214
+ const extension = job.input.mode === "pack" ? "pck" : "zip";
215
+ processInput = {
216
+ operation: "export",
217
+ projectRoot: this.dependencies.projectRoot,
218
+ artifactRoot: allocated.path,
219
+ mode: job.input.mode,
220
+ preset: job.input.preset,
221
+ outputPath: join(allocated.path, `${job.input.artifactName}.${extension}`),
222
+ };
223
+ }
224
+ this.assertActive(job);
225
+ job.process = await this.dependencies.launch(processInput);
226
+ await this.record(job);
227
+ job.phase = "executing";
228
+ job.progressMillionths = 250_000;
229
+ exitCode = await this.boundary(job, () => job.process.wait());
230
+ if (exitCode !== 0)
231
+ throw jobError("GODOT_RUNTIME_ERROR", `Godot project operation exited with code ${exitCode}`);
232
+ job.progressMillionths = 800_000;
233
+ if (job.input.operation === "export_start") {
234
+ job.phase = "scanning";
235
+ artifact = await this.dependencies.artifacts.finalize(job.token, job.input.artifactName);
236
+ }
237
+ }
238
+ terminalState = "completed";
239
+ }
240
+ catch (error) {
241
+ if (job.process && (errorCode(error) === "CANCELLED" || errorCode(error) === "TIMEOUT"))
242
+ await job.process.stop().catch(() => undefined);
243
+ terminalState = errorCode(error) === "CANCELLED" ? "cancelled" : "failed";
244
+ }
245
+ finally {
246
+ job.cancellationSafe = true;
247
+ job.phase = "finalizing";
248
+ const evidence = [];
249
+ try {
250
+ const stored = await this.evidence.putJson(job.sessionId, {
251
+ operation: job.operation,
252
+ exitCode,
253
+ output: job.process?.diagnostics?.() ?? "",
254
+ state: terminalState,
255
+ }, { kind: "project_job_output" });
256
+ evidence.push(stored.observationUri);
257
+ }
258
+ catch { }
259
+ job.progressMillionths = 1_000_000;
260
+ job.phase = "terminal";
261
+ job.state = terminalState;
262
+ job.result = ProjectOperationResultSchema.parse({
263
+ ...this.receipt(job),
264
+ state: terminalState,
265
+ phase: "terminal",
266
+ exitCode,
267
+ partialEffects: false,
268
+ rollback: "not_needed",
269
+ evidence,
270
+ ...(artifact ? { artifact } : {}),
271
+ });
272
+ await this.record(job);
273
+ }
274
+ }
275
+ async record(job) {
276
+ if (!this.dependencies.journal)
277
+ return;
278
+ await this.dependencies.journal.append({
279
+ projectId: this.dependencies.projectId,
280
+ jobToken: job.token,
281
+ sessionId: job.sessionId,
282
+ operation: job.operation,
283
+ state: job.state,
284
+ ...(job.process ? { pid: job.process.pid, fingerprint: job.process.fingerprint } : {}),
285
+ ...(job.input.operation === "export_start" ? { artifactName: job.input.artifactName } : {}),
286
+ });
287
+ }
288
+ }
289
+ //# sourceMappingURL=projectJobService.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"projectJobService.js","sourceRoot":"","sources":["../../src/project/projectJobService.ts"],"names":[],"mappings":"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"}