creative-pipeline-mcp 0.2.14-alpha.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 (196) hide show
  1. package/LICENSE +18 -0
  2. package/NOTICE +9 -0
  3. package/README.md +205 -0
  4. package/SECURITY.md +19 -0
  5. package/docs/API_TOOLS.md +74 -0
  6. package/docs/ARCHITECTURE.md +28 -0
  7. package/docs/ARTIFACT_SCHEMA.md +43 -0
  8. package/docs/BLENDER_BRIDGE_STATUS_SCHEMA.md +42 -0
  9. package/docs/CEP_STATUS_SCHEMA.md +35 -0
  10. package/docs/COMPATIBILITY_MATRIX.md +36 -0
  11. package/docs/GPL_ADAPTERS.md +19 -0
  12. package/docs/INSTALL_BLENDER.md +39 -0
  13. package/docs/INSTALL_DASHBOARD.md +47 -0
  14. package/docs/INSTALL_PREMIERE.md +62 -0
  15. package/docs/LICENSING.md +19 -0
  16. package/docs/PREMIERE_E2E_TEST.md +55 -0
  17. package/docs/RELEASE_PROCESS.md +74 -0
  18. package/docs/ROADMAP.md +53 -0
  19. package/docs/SAFETY.md +21 -0
  20. package/docs/SECURITY.md +14 -0
  21. package/docs/TROUBLESHOOTING.md +46 -0
  22. package/docs/examples/adapter_check_report.sample.json +60 -0
  23. package/docs/examples/delivery_qc_report.sample.json +30 -0
  24. package/examples/blender-bridge-queue.mjs +42 -0
  25. package/examples/blender-e2e.mjs +53 -0
  26. package/examples/brief.txt +2 -0
  27. package/examples/minimal.gltf +23 -0
  28. package/examples/premiere-project-delivery.mjs +72 -0
  29. package/examples/premiere-qc-e2e.mjs +77 -0
  30. package/examples/sample-tool-call.json +2 -0
  31. package/package.json +77 -0
  32. package/packages/blender-gpl-adapters/LICENSE +6 -0
  33. package/packages/blender-gpl-adapters/dist/index.d.ts +10 -0
  34. package/packages/blender-gpl-adapters/dist/index.js +28 -0
  35. package/packages/blender-gpl-adapters/dist/index.js.map +1 -0
  36. package/packages/blender-gpl-adapters/package.json +15 -0
  37. package/packages/blender-gpl-adapters/src/index.ts +38 -0
  38. package/packages/blender-pro-mcp/dist/adapters/blenderBridge.d.ts +34 -0
  39. package/packages/blender-pro-mcp/dist/adapters/blenderBridge.js +79 -0
  40. package/packages/blender-pro-mcp/dist/adapters/blenderBridge.js.map +1 -0
  41. package/packages/blender-pro-mcp/dist/adapters/cli.d.ts +11 -0
  42. package/packages/blender-pro-mcp/dist/adapters/cli.js +121 -0
  43. package/packages/blender-pro-mcp/dist/adapters/cli.js.map +1 -0
  44. package/packages/blender-pro-mcp/dist/adapters/gltf.d.ts +21 -0
  45. package/packages/blender-pro-mcp/dist/adapters/gltf.js +99 -0
  46. package/packages/blender-pro-mcp/dist/adapters/gltf.js.map +1 -0
  47. package/packages/blender-pro-mcp/dist/adapters/preview.d.ts +1 -0
  48. package/packages/blender-pro-mcp/dist/adapters/preview.js +11 -0
  49. package/packages/blender-pro-mcp/dist/adapters/preview.js.map +1 -0
  50. package/packages/blender-pro-mcp/dist/index.d.ts +3 -0
  51. package/packages/blender-pro-mcp/dist/index.js +4 -0
  52. package/packages/blender-pro-mcp/dist/index.js.map +1 -0
  53. package/packages/blender-pro-mcp/dist/server.d.ts +1 -0
  54. package/packages/blender-pro-mcp/dist/server.js +4 -0
  55. package/packages/blender-pro-mcp/dist/server.js.map +1 -0
  56. package/packages/blender-pro-mcp/dist/tools/assetTools.d.ts +2 -0
  57. package/packages/blender-pro-mcp/dist/tools/assetTools.js +646 -0
  58. package/packages/blender-pro-mcp/dist/tools/assetTools.js.map +1 -0
  59. package/packages/blender-pro-mcp/dist/tools/shared.d.ts +3 -0
  60. package/packages/blender-pro-mcp/dist/tools/shared.js +94 -0
  61. package/packages/blender-pro-mcp/dist/tools/shared.js.map +1 -0
  62. package/packages/blender-pro-mcp/package.json +18 -0
  63. package/packages/blender-pro-mcp/src/adapters/blenderBridge.ts +106 -0
  64. package/packages/blender-pro-mcp/src/adapters/cli.ts +130 -0
  65. package/packages/blender-pro-mcp/src/adapters/gltf.ts +132 -0
  66. package/packages/blender-pro-mcp/src/adapters/preview.ts +11 -0
  67. package/packages/blender-pro-mcp/src/index.ts +3 -0
  68. package/packages/blender-pro-mcp/src/server.ts +4 -0
  69. package/packages/blender-pro-mcp/src/tools/assetTools.ts +663 -0
  70. package/packages/blender-pro-mcp/src/tools/shared.ts +99 -0
  71. package/packages/core/dist/approvalPolicy.d.ts +13 -0
  72. package/packages/core/dist/approvalPolicy.js +48 -0
  73. package/packages/core/dist/approvalPolicy.js.map +1 -0
  74. package/packages/core/dist/artifactStore.d.ts +14 -0
  75. package/packages/core/dist/artifactStore.js +77 -0
  76. package/packages/core/dist/artifactStore.js.map +1 -0
  77. package/packages/core/dist/coreTools.d.ts +2 -0
  78. package/packages/core/dist/coreTools.js +34 -0
  79. package/packages/core/dist/coreTools.js.map +1 -0
  80. package/packages/core/dist/index.d.ts +11 -0
  81. package/packages/core/dist/index.js +12 -0
  82. package/packages/core/dist/index.js.map +1 -0
  83. package/packages/core/dist/jobQueue.d.ts +11 -0
  84. package/packages/core/dist/jobQueue.js +14 -0
  85. package/packages/core/dist/jobQueue.js.map +1 -0
  86. package/packages/core/dist/licenseManifest.d.ts +7 -0
  87. package/packages/core/dist/licenseManifest.js +42 -0
  88. package/packages/core/dist/licenseManifest.js.map +1 -0
  89. package/packages/core/dist/mcpServer.d.ts +19 -0
  90. package/packages/core/dist/mcpServer.js +120 -0
  91. package/packages/core/dist/mcpServer.js.map +1 -0
  92. package/packages/core/dist/qcReport.d.ts +21 -0
  93. package/packages/core/dist/qcReport.js +25 -0
  94. package/packages/core/dist/qcReport.js.map +1 -0
  95. package/packages/core/dist/router.d.ts +7 -0
  96. package/packages/core/dist/router.js +55 -0
  97. package/packages/core/dist/router.js.map +1 -0
  98. package/packages/core/dist/schemaValidator.d.ts +8 -0
  99. package/packages/core/dist/schemaValidator.js +21 -0
  100. package/packages/core/dist/schemaValidator.js.map +1 -0
  101. package/packages/core/dist/server.d.ts +1 -0
  102. package/packages/core/dist/server.js +3 -0
  103. package/packages/core/dist/server.js.map +1 -0
  104. package/packages/core/dist/toolRegistry.d.ts +8 -0
  105. package/packages/core/dist/toolRegistry.js +25 -0
  106. package/packages/core/dist/toolRegistry.js.map +1 -0
  107. package/packages/core/dist/types.d.ts +58 -0
  108. package/packages/core/dist/types.js +2 -0
  109. package/packages/core/dist/types.js.map +1 -0
  110. package/packages/core/package.json +18 -0
  111. package/packages/core/src/approvalPolicy.ts +51 -0
  112. package/packages/core/src/artifactStore.ts +93 -0
  113. package/packages/core/src/coreTools.ts +36 -0
  114. package/packages/core/src/index.ts +11 -0
  115. package/packages/core/src/jobQueue.ts +22 -0
  116. package/packages/core/src/licenseManifest.ts +47 -0
  117. package/packages/core/src/mcpServer.ts +131 -0
  118. package/packages/core/src/qcReport.ts +53 -0
  119. package/packages/core/src/router.ts +61 -0
  120. package/packages/core/src/schemaValidator.ts +26 -0
  121. package/packages/core/src/server.ts +3 -0
  122. package/packages/core/src/toolRegistry.ts +31 -0
  123. package/packages/core/src/types.ts +78 -0
  124. package/packages/dashboard/dist/server.d.ts +1 -0
  125. package/packages/dashboard/dist/server.js +486 -0
  126. package/packages/dashboard/dist/server.js.map +1 -0
  127. package/packages/dashboard/package.json +18 -0
  128. package/packages/dashboard/src/server.ts +539 -0
  129. package/packages/director-agent/dist/index.d.ts +1 -0
  130. package/packages/director-agent/dist/index.js +2 -0
  131. package/packages/director-agent/dist/index.js.map +1 -0
  132. package/packages/director-agent/dist/server.d.ts +1 -0
  133. package/packages/director-agent/dist/server.js +4 -0
  134. package/packages/director-agent/dist/server.js.map +1 -0
  135. package/packages/director-agent/dist/tools.d.ts +2 -0
  136. package/packages/director-agent/dist/tools.js +115 -0
  137. package/packages/director-agent/dist/tools.js.map +1 -0
  138. package/packages/director-agent/package.json +18 -0
  139. package/packages/director-agent/src/index.ts +2 -0
  140. package/packages/director-agent/src/server.ts +4 -0
  141. package/packages/director-agent/src/tools.ts +116 -0
  142. package/packages/premiere-cep-panel/CSXS/manifest.xml +43 -0
  143. package/packages/premiere-cep-panel/README.md +21 -0
  144. package/packages/premiere-cep-panel/index.html +26 -0
  145. package/packages/premiere-cep-panel/js/main.js +107 -0
  146. package/packages/premiere-cep-panel/jsx/host.jsx +208 -0
  147. package/packages/premiere-cep-panel/package.json +8 -0
  148. package/packages/premiere-pro-mcp/dist/adapters/ffmpegQc.d.ts +21 -0
  149. package/packages/premiere-pro-mcp/dist/adapters/ffmpegQc.js +78 -0
  150. package/packages/premiere-pro-mcp/dist/adapters/ffmpegQc.js.map +1 -0
  151. package/packages/premiere-pro-mcp/dist/adapters/ffprobe.d.ts +25 -0
  152. package/packages/premiere-pro-mcp/dist/adapters/ffprobe.js +73 -0
  153. package/packages/premiere-pro-mcp/dist/adapters/ffprobe.js.map +1 -0
  154. package/packages/premiere-pro-mcp/dist/adapters/optionalTools.d.ts +11 -0
  155. package/packages/premiere-pro-mcp/dist/adapters/optionalTools.js +82 -0
  156. package/packages/premiere-pro-mcp/dist/adapters/optionalTools.js.map +1 -0
  157. package/packages/premiere-pro-mcp/dist/adapters/premiereCep.d.ts +34 -0
  158. package/packages/premiere-pro-mcp/dist/adapters/premiereCep.js +79 -0
  159. package/packages/premiere-pro-mcp/dist/adapters/premiereCep.js.map +1 -0
  160. package/packages/premiere-pro-mcp/dist/adapters/srt.d.ts +8 -0
  161. package/packages/premiere-pro-mcp/dist/adapters/srt.js +37 -0
  162. package/packages/premiere-pro-mcp/dist/adapters/srt.js.map +1 -0
  163. package/packages/premiere-pro-mcp/dist/index.d.ts +2 -0
  164. package/packages/premiere-pro-mcp/dist/index.js +3 -0
  165. package/packages/premiere-pro-mcp/dist/index.js.map +1 -0
  166. package/packages/premiere-pro-mcp/dist/server.d.ts +1 -0
  167. package/packages/premiere-pro-mcp/dist/server.js +4 -0
  168. package/packages/premiere-pro-mcp/dist/server.js.map +1 -0
  169. package/packages/premiere-pro-mcp/dist/tools/mediaTools.d.ts +2 -0
  170. package/packages/premiere-pro-mcp/dist/tools/mediaTools.js +935 -0
  171. package/packages/premiere-pro-mcp/dist/tools/mediaTools.js.map +1 -0
  172. package/packages/premiere-pro-mcp/dist/tools/shared.d.ts +3 -0
  173. package/packages/premiere-pro-mcp/dist/tools/shared.js +136 -0
  174. package/packages/premiere-pro-mcp/dist/tools/shared.js.map +1 -0
  175. package/packages/premiere-pro-mcp/package.json +18 -0
  176. package/packages/premiere-pro-mcp/src/adapters/ffmpegQc.ts +106 -0
  177. package/packages/premiere-pro-mcp/src/adapters/ffprobe.ts +105 -0
  178. package/packages/premiere-pro-mcp/src/adapters/optionalTools.ts +94 -0
  179. package/packages/premiere-pro-mcp/src/adapters/premiereCep.ts +106 -0
  180. package/packages/premiere-pro-mcp/src/adapters/srt.ts +46 -0
  181. package/packages/premiere-pro-mcp/src/index.ts +3 -0
  182. package/packages/premiere-pro-mcp/src/server.ts +4 -0
  183. package/packages/premiere-pro-mcp/src/tools/mediaTools.ts +961 -0
  184. package/packages/premiere-pro-mcp/src/tools/shared.ts +147 -0
  185. package/packages/premiere-windows-adapter/dist/index.d.ts +12 -0
  186. package/packages/premiere-windows-adapter/dist/index.js +17 -0
  187. package/packages/premiere-windows-adapter/dist/index.js.map +1 -0
  188. package/packages/premiere-windows-adapter/package.json +12 -0
  189. package/packages/premiere-windows-adapter/src/index.ts +25 -0
  190. package/scripts/blender-bridge-worker.mjs +311 -0
  191. package/scripts/check-adapters.mjs +57 -0
  192. package/scripts/install-premiere-cep.mjs +43 -0
  193. package/scripts/package-premiere-cep.mjs +236 -0
  194. package/scripts/release-assets.mjs +146 -0
  195. package/scripts/simulate-premiere-cep.mjs +194 -0
  196. package/third_party_licenses/README.md +19 -0
@@ -0,0 +1,77 @@
1
+ import { spawnSync } from "node:child_process";
2
+ import { mkdirSync } from "node:fs";
3
+ import { resolve } from "node:path";
4
+
5
+ const root = process.cwd();
6
+ const artifacts = resolve(root, "artifacts", "examples", "premiere-e2e");
7
+ mkdirSync(artifacts, { recursive: true });
8
+
9
+ const source = resolve(artifacts, "source.mp4");
10
+ run("ffmpeg", [
11
+ "-hide_banner",
12
+ "-y",
13
+ "-f",
14
+ "lavfi",
15
+ "-i",
16
+ "testsrc=duration=1:size=320x240:rate=30",
17
+ "-f",
18
+ "lavfi",
19
+ "-i",
20
+ "sine=frequency=880:duration=1",
21
+ "-shortest",
22
+ source
23
+ ]);
24
+
25
+ const roughCut = callTool("premiere.make_rough_cut", {
26
+ path: source,
27
+ brief: "One-second generated QC sample",
28
+ targetDuration: 1
29
+ });
30
+ callTool("premiere.run_delivery_qc", {
31
+ path: source,
32
+ targetWidth: 320,
33
+ targetHeight: 240,
34
+ maxDuration: 2,
35
+ referencePath: source,
36
+ targetMinVmaf: 99
37
+ });
38
+ callTool("premiere.generate_thumbnail_plan", { path: source, count: 1 });
39
+
40
+ const otioPath = roughCut.structuredContent.artifacts[0];
41
+ callTool(
42
+ "premiere.build_timeline_from_otio",
43
+ { otioPath, sequenceName: "Creative Pipeline E2E" },
44
+ { CREATIVE_MCP_PERMISSION: "project_write" }
45
+ );
46
+ callTool("premiere.read_cep_status", {});
47
+
48
+ function callTool(name, args, extraEnv = {}) {
49
+ const request = JSON.stringify({
50
+ jsonrpc: "2.0",
51
+ id: 1,
52
+ method: "tools/call",
53
+ params: { name, arguments: args }
54
+ });
55
+ const result = spawnSync("node", ["packages/premiere-pro-mcp/dist/server.js"], {
56
+ cwd: root,
57
+ input: `${request}\n`,
58
+ encoding: "utf8",
59
+ env: { ...process.env, ...extraEnv }
60
+ });
61
+ if (result.status !== 0) {
62
+ throw new Error(result.stderr || `Tool failed: ${name}`);
63
+ }
64
+ process.stdout.write(result.stdout);
65
+ const response = JSON.parse(result.stdout);
66
+ if (!response.result?.structuredContent?.ok && name !== "premiere.read_cep_status") {
67
+ throw new Error(`Tool returned not ok: ${name}`);
68
+ }
69
+ return response.result;
70
+ }
71
+
72
+ function run(command, args) {
73
+ const result = spawnSync(command, args, { cwd: root, encoding: "utf8" });
74
+ if (result.status !== 0) {
75
+ throw new Error(result.stderr || `${command} failed`);
76
+ }
77
+ }
@@ -0,0 +1,2 @@
1
+ {"jsonrpc":"2.0","id":1,"method":"tools/list","params":{}}
2
+
package/package.json ADDED
@@ -0,0 +1,77 @@
1
+ {
2
+ "name": "creative-pipeline-mcp",
3
+ "version": "0.2.14-alpha.0",
4
+ "private": false,
5
+ "description": "QC-first MCP pipeline for Blender assets and Premiere media workflows.",
6
+ "license": "Apache-2.0",
7
+ "repository": {
8
+ "type": "git",
9
+ "url": "git+https://github.com/taiyuhiga/creative-pipeline-mcp.git"
10
+ },
11
+ "type": "module",
12
+ "workspaces": [
13
+ "packages/*"
14
+ ],
15
+ "files": [
16
+ "packages/*/dist/**",
17
+ "packages/*/src/**",
18
+ "packages/*/package.json",
19
+ "packages/premiere-cep-panel/CSXS",
20
+ "packages/premiere-cep-panel/index.html",
21
+ "packages/premiere-cep-panel/js",
22
+ "packages/premiere-cep-panel/jsx",
23
+ "packages/premiere-cep-panel/README.md",
24
+ "docs",
25
+ "examples",
26
+ "scripts",
27
+ "third_party_licenses",
28
+ "README.md",
29
+ "LICENSE",
30
+ "NOTICE",
31
+ "SECURITY.md"
32
+ ],
33
+ "bin": {
34
+ "creative-mcp-core": "packages/core/dist/server.js",
35
+ "blender-pro-mcp": "packages/blender-pro-mcp/dist/server.js",
36
+ "premiere-pro-mcp": "packages/premiere-pro-mcp/dist/server.js",
37
+ "creative-pipeline-director": "packages/director-agent/dist/server.js",
38
+ "creative-mcp-dashboard": "packages/dashboard/dist/server.js"
39
+ },
40
+ "exports": {
41
+ "./core": "./packages/core/dist/index.js",
42
+ "./blender": "./packages/blender-pro-mcp/dist/index.js",
43
+ "./premiere": "./packages/premiere-pro-mcp/dist/index.js",
44
+ "./director": "./packages/director-agent/dist/index.js",
45
+ "./blender-gpl-adapters": "./packages/blender-gpl-adapters/dist/index.js",
46
+ "./premiere-windows-adapter": "./packages/premiere-windows-adapter/dist/index.js"
47
+ },
48
+ "scripts": {
49
+ "build": "tsc -b packages/core packages/blender-pro-mcp packages/premiere-pro-mcp packages/director-agent packages/blender-gpl-adapters packages/premiere-windows-adapter packages/dashboard",
50
+ "clean": "tsc -b --clean packages/core packages/blender-pro-mcp packages/premiere-pro-mcp packages/director-agent packages/blender-gpl-adapters packages/premiere-windows-adapter packages/dashboard && rm -rf artifacts",
51
+ "test": "npm run build && node --test tests/*.mjs",
52
+ "prepack": "npm run build",
53
+ "check:adapters": "node scripts/check-adapters.mjs",
54
+ "release:assets": "node scripts/release-assets.mjs",
55
+ "blender:bridge-worker": "node scripts/blender-bridge-worker.mjs",
56
+ "simulate:premiere-cep": "node scripts/simulate-premiere-cep.mjs",
57
+ "package:premiere-cep": "node scripts/package-premiere-cep.mjs",
58
+ "install:premiere-cep": "node scripts/install-premiere-cep.mjs",
59
+ "uninstall:premiere-cep": "node scripts/install-premiere-cep.mjs --uninstall",
60
+ "start:core": "node packages/core/dist/server.js",
61
+ "start:blender": "node packages/blender-pro-mcp/dist/server.js",
62
+ "start:premiere": "node packages/premiere-pro-mcp/dist/server.js",
63
+ "start:director": "node packages/director-agent/dist/server.js",
64
+ "start:dashboard": "node packages/dashboard/dist/server.js"
65
+ },
66
+ "dependencies": {
67
+ "@gltf-transform/cli": "4.3.0",
68
+ "ajv": "^8.20.0"
69
+ },
70
+ "devDependencies": {
71
+ "@types/node": "^24.10.1",
72
+ "typescript": "^5.9.3"
73
+ },
74
+ "engines": {
75
+ "node": ">=20"
76
+ }
77
+ }
@@ -0,0 +1,6 @@
1
+ GPL-3.0-or-later adapter package.
2
+
3
+ This package intentionally contains only adapter manifests and process-boundary wrappers.
4
+ Install and run GPL tools such as BlenderProc, BlenderGIS, and Sverchok separately, then
5
+ connect them through command-line, socket, or Blender addon boundaries.
6
+
@@ -0,0 +1,10 @@
1
+ export interface ExternalGplAdapterJob {
2
+ adapter: "blenderproc" | "blendergis" | "sverchok";
3
+ command: string;
4
+ args: string[];
5
+ inputJson: Record<string, unknown>;
6
+ license: "GPL-3.0-or-later";
7
+ }
8
+ export declare function createBlenderProcJob(inputJson: Record<string, unknown>): ExternalGplAdapterJob;
9
+ export declare function createBlenderGisJob(inputJson: Record<string, unknown>): ExternalGplAdapterJob;
10
+ export declare function createSverchokJob(inputJson: Record<string, unknown>): ExternalGplAdapterJob;
@@ -0,0 +1,28 @@
1
+ export function createBlenderProcJob(inputJson) {
2
+ return {
3
+ adapter: "blenderproc",
4
+ command: "blenderproc",
5
+ args: ["run", "--custom-blender-path", "${BLENDER_PATH}", "${SCRIPT_PATH}"],
6
+ inputJson,
7
+ license: "GPL-3.0-or-later"
8
+ };
9
+ }
10
+ export function createBlenderGisJob(inputJson) {
11
+ return {
12
+ adapter: "blendergis",
13
+ command: "blender",
14
+ args: ["--background", "--python", "${BLENDERGIS_BRIDGE_SCRIPT}"],
15
+ inputJson,
16
+ license: "GPL-3.0-or-later"
17
+ };
18
+ }
19
+ export function createSverchokJob(inputJson) {
20
+ return {
21
+ adapter: "sverchok",
22
+ command: "blender",
23
+ args: ["--background", "--python", "${SVERCHOK_BRIDGE_SCRIPT}"],
24
+ inputJson,
25
+ license: "GPL-3.0-or-later"
26
+ };
27
+ }
28
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAQA,MAAM,UAAU,oBAAoB,CAAC,SAAkC;IACrE,OAAO;QACL,OAAO,EAAE,aAAa;QACtB,OAAO,EAAE,aAAa;QACtB,IAAI,EAAE,CAAC,KAAK,EAAE,uBAAuB,EAAE,iBAAiB,EAAE,gBAAgB,CAAC;QAC3E,SAAS;QACT,OAAO,EAAE,kBAAkB;KAC5B,CAAC;AACJ,CAAC;AAED,MAAM,UAAU,mBAAmB,CAAC,SAAkC;IACpE,OAAO;QACL,OAAO,EAAE,YAAY;QACrB,OAAO,EAAE,SAAS;QAClB,IAAI,EAAE,CAAC,cAAc,EAAE,UAAU,EAAE,6BAA6B,CAAC;QACjE,SAAS;QACT,OAAO,EAAE,kBAAkB;KAC5B,CAAC;AACJ,CAAC;AAED,MAAM,UAAU,iBAAiB,CAAC,SAAkC;IAClE,OAAO;QACL,OAAO,EAAE,UAAU;QACnB,OAAO,EAAE,SAAS;QAClB,IAAI,EAAE,CAAC,cAAc,EAAE,UAAU,EAAE,2BAA2B,CAAC;QAC/D,SAAS;QACT,OAAO,EAAE,kBAAkB;KAC5B,CAAC;AACJ,CAAC"}
@@ -0,0 +1,15 @@
1
+ {
2
+ "name": "@creative-pipeline-mcp/blender-gpl-adapters",
3
+ "version": "0.2.14-alpha.0",
4
+ "type": "module",
5
+ "license": "GPL-3.0-or-later",
6
+ "main": "dist/index.js",
7
+ "types": "dist/index.d.ts",
8
+ "exports": {
9
+ ".": "./dist/index.js"
10
+ },
11
+ "files": ["dist", "src", "LICENSE"],
12
+ "dependencies": {
13
+ "@creative-pipeline-mcp/core": "0.2.14-alpha.0"
14
+ }
15
+ }
@@ -0,0 +1,38 @@
1
+ export interface ExternalGplAdapterJob {
2
+ adapter: "blenderproc" | "blendergis" | "sverchok";
3
+ command: string;
4
+ args: string[];
5
+ inputJson: Record<string, unknown>;
6
+ license: "GPL-3.0-or-later";
7
+ }
8
+
9
+ export function createBlenderProcJob(inputJson: Record<string, unknown>): ExternalGplAdapterJob {
10
+ return {
11
+ adapter: "blenderproc",
12
+ command: "blenderproc",
13
+ args: ["run", "--custom-blender-path", "${BLENDER_PATH}", "${SCRIPT_PATH}"],
14
+ inputJson,
15
+ license: "GPL-3.0-or-later"
16
+ };
17
+ }
18
+
19
+ export function createBlenderGisJob(inputJson: Record<string, unknown>): ExternalGplAdapterJob {
20
+ return {
21
+ adapter: "blendergis",
22
+ command: "blender",
23
+ args: ["--background", "--python", "${BLENDERGIS_BRIDGE_SCRIPT}"],
24
+ inputJson,
25
+ license: "GPL-3.0-or-later"
26
+ };
27
+ }
28
+
29
+ export function createSverchokJob(inputJson: Record<string, unknown>): ExternalGplAdapterJob {
30
+ return {
31
+ adapter: "sverchok",
32
+ command: "blender",
33
+ args: ["--background", "--python", "${SVERCHOK_BRIDGE_SCRIPT}"],
34
+ inputJson,
35
+ license: "GPL-3.0-or-later"
36
+ };
37
+ }
38
+
@@ -0,0 +1,34 @@
1
+ export interface BlenderBridgeCommand {
2
+ id: string;
3
+ type: "create_scene" | "create_asset" | "modify_asset" | "apply_material" | "run_safe_script";
4
+ payload: Record<string, unknown>;
5
+ createdAt: string;
6
+ }
7
+ export interface BlenderBridgeStatus {
8
+ schema: "creative.pipeline.blender.status.v1";
9
+ commandId?: string | null;
10
+ commandType: BlenderBridgeCommand["type"] | "unknown";
11
+ status: "success" | "accepted" | "error" | string;
12
+ message: string;
13
+ details: Record<string, unknown>;
14
+ command?: BlenderBridgeCommand;
15
+ processedAt?: string;
16
+ finishedAt?: string;
17
+ }
18
+ export declare function enqueueBlenderBridgeCommand(type: BlenderBridgeCommand["type"], payload: Record<string, unknown>): Promise<{
19
+ command: BlenderBridgeCommand;
20
+ path: string;
21
+ }>;
22
+ export declare function listBlenderBridgeStatuses(): Promise<Array<{
23
+ id: string;
24
+ path: string;
25
+ status: BlenderBridgeStatus;
26
+ }>>;
27
+ export declare function findBlenderBridgeStatus(criteria: {
28
+ commandId?: string;
29
+ commandType?: BlenderBridgeCommand["type"];
30
+ }): Promise<{
31
+ id: string;
32
+ path: string;
33
+ status: BlenderBridgeStatus;
34
+ } | undefined>;
@@ -0,0 +1,79 @@
1
+ import { mkdir, readFile, readdir, writeFile } from "node:fs/promises";
2
+ import { join, resolve } from "node:path";
3
+ export async function enqueueBlenderBridgeCommand(type, payload) {
4
+ const queueDir = resolve(process.env.CREATIVE_MCP_BLENDER_IPC_DIR ?? "artifacts/blender/bridge_queue");
5
+ await mkdir(queueDir, { recursive: true });
6
+ const command = {
7
+ id: `${Date.now()}-${Math.random().toString(16).slice(2)}`,
8
+ type,
9
+ payload,
10
+ createdAt: new Date().toISOString()
11
+ };
12
+ const path = join(queueDir, `${command.id}.json`);
13
+ await writeFile(path, `${JSON.stringify(command, null, 2)}\n`, "utf8");
14
+ return { command, path };
15
+ }
16
+ export async function listBlenderBridgeStatuses() {
17
+ const statusDir = resolve(process.env.CREATIVE_MCP_BLENDER_STATUS_DIR ?? "artifacts/blender/bridge_status");
18
+ let entries;
19
+ try {
20
+ entries = await readdir(statusDir);
21
+ }
22
+ catch {
23
+ return [];
24
+ }
25
+ const statuses = [];
26
+ for (const entry of entries.filter((file) => file.endsWith(".json"))) {
27
+ const path = join(statusDir, entry);
28
+ try {
29
+ statuses.push({ id: entry, path, status: normalizeStatus(JSON.parse(await readFile(path, "utf8"))) });
30
+ }
31
+ catch {
32
+ statuses.push({
33
+ id: entry,
34
+ path,
35
+ status: {
36
+ schema: "creative.pipeline.blender.status.v1",
37
+ commandType: "unknown",
38
+ status: "error",
39
+ message: "unreadable status file",
40
+ details: { unreadable: true }
41
+ }
42
+ });
43
+ }
44
+ }
45
+ return statuses;
46
+ }
47
+ export async function findBlenderBridgeStatus(criteria) {
48
+ const statuses = await listBlenderBridgeStatuses();
49
+ return statuses.find((entry) => {
50
+ const commandId = entry.status.commandId ?? entry.status.command?.id;
51
+ return (!criteria.commandId || commandId === criteria.commandId)
52
+ && (!criteria.commandType || entry.status.commandType === criteria.commandType);
53
+ });
54
+ }
55
+ function normalizeStatus(value) {
56
+ if (isStatus(value)) {
57
+ return value;
58
+ }
59
+ const legacy = value && typeof value === "object" ? value : {};
60
+ return {
61
+ schema: "creative.pipeline.blender.status.v1",
62
+ commandType: "unknown",
63
+ status: typeof legacy.status === "string" ? legacy.status : "accepted",
64
+ message: typeof legacy.message === "string" ? legacy.message : "legacy Blender bridge status",
65
+ details: legacy
66
+ };
67
+ }
68
+ function isStatus(value) {
69
+ if (!value || typeof value !== "object") {
70
+ return false;
71
+ }
72
+ const candidate = value;
73
+ return candidate.schema === "creative.pipeline.blender.status.v1"
74
+ && typeof candidate.commandType === "string"
75
+ && typeof candidate.status === "string"
76
+ && typeof candidate.message === "string"
77
+ && typeof candidate.details === "object";
78
+ }
79
+ //# sourceMappingURL=blenderBridge.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"blenderBridge.js","sourceRoot":"","sources":["../../src/adapters/blenderBridge.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,11 @@
1
+ export interface CliResult {
2
+ available: boolean;
3
+ command: string;
4
+ stdout?: string;
5
+ stderr?: string;
6
+ error?: string;
7
+ }
8
+ export declare function commandExists(command: string): Promise<boolean>;
9
+ export declare function optimizeWithCli(source: string, target: string): Promise<CliResult>;
10
+ export declare function renderWithHeadlessBlender(source: string, outputPng: string): Promise<CliResult>;
11
+ export declare function runHeadlessBlenderScript(script: string): Promise<CliResult>;
@@ -0,0 +1,121 @@
1
+ import { access, mkdtemp, writeFile } from "node:fs/promises";
2
+ import { constants, existsSync } from "node:fs";
3
+ import { execFile } from "node:child_process";
4
+ import { tmpdir } from "node:os";
5
+ import { join, resolve } from "node:path";
6
+ import { promisify } from "node:util";
7
+ const execFileAsync = promisify(execFile);
8
+ export async function commandExists(command) {
9
+ const resolved = resolveCommand(command);
10
+ if (command.includes("/") || command.includes("\\")) {
11
+ try {
12
+ await access(command, constants.X_OK);
13
+ return true;
14
+ }
15
+ catch {
16
+ return false;
17
+ }
18
+ }
19
+ try {
20
+ await execFileAsync(process.platform === "win32" ? "where" : "command", process.platform === "win32" ? [resolved] : ["-v", resolved], {
21
+ shell: process.platform !== "win32"
22
+ });
23
+ return true;
24
+ }
25
+ catch {
26
+ return false;
27
+ }
28
+ }
29
+ export async function optimizeWithCli(source, target) {
30
+ const gltfTransform = process.env.GLTF_TRANSFORM_BIN ?? "gltf-transform";
31
+ const gltfTransformCommand = resolveCommand(gltfTransform);
32
+ if (await commandExists(gltfTransform)) {
33
+ try {
34
+ const { stdout, stderr } = await execFileAsync(gltfTransformCommand, ["optimize", source, target]);
35
+ return { available: true, command: gltfTransformCommand, stdout, stderr };
36
+ }
37
+ catch (error) {
38
+ return { available: true, command: gltfTransformCommand, error: error instanceof Error ? error.message : String(error) };
39
+ }
40
+ }
41
+ const gltfpack = process.env.GLTFPACK_BIN ?? "gltfpack";
42
+ const gltfpackCommand = resolveCommand(gltfpack);
43
+ if (await commandExists(gltfpack)) {
44
+ try {
45
+ const { stdout, stderr } = await execFileAsync(gltfpackCommand, ["-i", source, "-o", target]);
46
+ return { available: true, command: gltfpackCommand, stdout, stderr };
47
+ }
48
+ catch (error) {
49
+ return { available: true, command: gltfpackCommand, error: error instanceof Error ? error.message : String(error) };
50
+ }
51
+ }
52
+ return { available: false, command: "gltf-transform|gltfpack", error: "No glTF optimizer CLI found" };
53
+ }
54
+ export async function renderWithHeadlessBlender(source, outputPng) {
55
+ const blender = process.env.BLENDER_BIN ?? "blender";
56
+ const blenderCommand = resolveCommand(blender);
57
+ if (!(await commandExists(blender))) {
58
+ return { available: false, command: blenderCommand, error: "Blender executable not found" };
59
+ }
60
+ const tempDir = await mkdtemp(join(tmpdir(), "creative-mcp-blender-"));
61
+ const scriptPath = join(tempDir, "render_preview.py");
62
+ const script = `
63
+ import bpy
64
+ import os
65
+
66
+ source = ${JSON.stringify(source)}
67
+ output = ${JSON.stringify(outputPng)}
68
+
69
+ bpy.ops.object.delete()
70
+ if source.lower().endswith((".glb", ".gltf")):
71
+ bpy.ops.import_scene.gltf(filepath=source)
72
+ elif source.lower().endswith(".blend"):
73
+ pass
74
+ else:
75
+ raise RuntimeError("Unsupported preview source: " + source)
76
+
77
+ if not bpy.context.scene.camera:
78
+ bpy.ops.object.light_add(type="AREA", location=(2, -3, 4))
79
+ bpy.context.object.data.energy = 400
80
+ bpy.ops.object.camera_add(location=(3, -5, 3), rotation=(1.1, 0, 0.55))
81
+ bpy.context.scene.camera = bpy.context.object
82
+
83
+ bpy.context.scene.render.resolution_x = 1024
84
+ bpy.context.scene.render.resolution_y = 1024
85
+ bpy.context.scene.render.filepath = output
86
+ bpy.ops.render.render(write_still=True)
87
+ `;
88
+ await writeFile(scriptPath, script, "utf8");
89
+ try {
90
+ const { stdout, stderr } = await execFileAsync(blenderCommand, ["--background", source.endsWith(".blend") ? source : "--factory-startup", "--python", scriptPath]);
91
+ return { available: true, command: blenderCommand, stdout, stderr };
92
+ }
93
+ catch (error) {
94
+ return { available: true, command: blenderCommand, error: error instanceof Error ? error.message : String(error) };
95
+ }
96
+ }
97
+ export async function runHeadlessBlenderScript(script) {
98
+ const blender = process.env.BLENDER_BIN ?? "blender";
99
+ const blenderCommand = resolveCommand(blender);
100
+ if (!(await commandExists(blender))) {
101
+ return { available: false, command: blenderCommand, error: "Blender executable not found" };
102
+ }
103
+ const tempDir = await mkdtemp(join(tmpdir(), "creative-mcp-blender-"));
104
+ const scriptPath = join(tempDir, "script.py");
105
+ await writeFile(scriptPath, script, "utf8");
106
+ try {
107
+ const { stdout, stderr } = await execFileAsync(blenderCommand, ["--background", "--factory-startup", "--python", scriptPath]);
108
+ return { available: true, command: blenderCommand, stdout, stderr };
109
+ }
110
+ catch (error) {
111
+ return { available: true, command: blenderCommand, error: error instanceof Error ? error.message : String(error) };
112
+ }
113
+ }
114
+ function resolveCommand(command) {
115
+ if (command.includes("/") || command.includes("\\")) {
116
+ return command;
117
+ }
118
+ const local = resolve("node_modules", ".bin", process.platform === "win32" ? `${command}.cmd` : command);
119
+ return existsSync(local) ? local : command;
120
+ }
121
+ //# sourceMappingURL=cli.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"cli.js","sourceRoot":"","sources":["../../src/adapters/cli.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,21 @@
1
+ export interface GltfInspection {
2
+ format: "glb" | "gltf";
3
+ version?: string;
4
+ nodeCount: number;
5
+ meshCount: number;
6
+ materialCount: number;
7
+ textureCount: number;
8
+ imageCount: number;
9
+ primitiveCount: number;
10
+ vertexCount: number;
11
+ triangleCount: number;
12
+ primitivesMissingNormals: number;
13
+ primitivesMissingUvs: number;
14
+ missingTextureRefs: number;
15
+ materialTextureSlots: number;
16
+ boundingBox?: {
17
+ min: number[];
18
+ max: number[];
19
+ };
20
+ }
21
+ export declare function inspectGltf(path: string): Promise<GltfInspection>;
@@ -0,0 +1,99 @@
1
+ import { readFile } from "node:fs/promises";
2
+ export async function inspectGltf(path) {
3
+ const bytes = await readFile(path);
4
+ const json = path.toLowerCase().endsWith(".glb") ? readGlbJson(bytes) : JSON.parse(bytes.toString("utf8"));
5
+ return summarize(json, path.toLowerCase().endsWith(".glb") ? "glb" : "gltf");
6
+ }
7
+ function readGlbJson(bytes) {
8
+ if (bytes.length < 20 || bytes.readUInt32LE(0) !== 0x46546c67) {
9
+ throw new Error("Invalid GLB header");
10
+ }
11
+ let offset = 12;
12
+ while (offset + 8 <= bytes.length) {
13
+ const chunkLength = bytes.readUInt32LE(offset);
14
+ const chunkType = bytes.readUInt32LE(offset + 4);
15
+ offset += 8;
16
+ if (chunkType === 0x4e4f534a) {
17
+ return JSON.parse(bytes.subarray(offset, offset + chunkLength).toString("utf8").trim());
18
+ }
19
+ offset += chunkLength;
20
+ }
21
+ throw new Error("GLB JSON chunk not found");
22
+ }
23
+ function summarize(json, format) {
24
+ const accessors = json.accessors ?? [];
25
+ let primitiveCount = 0;
26
+ let vertexCount = 0;
27
+ let triangleCount = 0;
28
+ let primitivesMissingNormals = 0;
29
+ let primitivesMissingUvs = 0;
30
+ const bbox = { min: [Infinity, Infinity, Infinity], max: [-Infinity, -Infinity, -Infinity] };
31
+ for (const mesh of json.meshes ?? []) {
32
+ for (const primitive of mesh.primitives ?? []) {
33
+ primitiveCount += 1;
34
+ const attributes = primitive.attributes;
35
+ if (typeof attributes?.NORMAL !== "number") {
36
+ primitivesMissingNormals += 1;
37
+ }
38
+ if (typeof attributes?.TEXCOORD_0 !== "number") {
39
+ primitivesMissingUvs += 1;
40
+ }
41
+ const positionAccessor = attributes ? accessors[attributes.POSITION] : undefined;
42
+ if (positionAccessor?.count) {
43
+ vertexCount += positionAccessor.count;
44
+ }
45
+ if (positionAccessor?.min && positionAccessor.max) {
46
+ for (let index = 0; index < 3; index += 1) {
47
+ bbox.min[index] = Math.min(bbox.min[index], positionAccessor.min[index] ?? bbox.min[index]);
48
+ bbox.max[index] = Math.max(bbox.max[index], positionAccessor.max[index] ?? bbox.max[index]);
49
+ }
50
+ }
51
+ const indicesIndex = primitive.indices;
52
+ const indexAccessor = typeof indicesIndex === "number" ? accessors[indicesIndex] : undefined;
53
+ if (indexAccessor?.count) {
54
+ triangleCount += Math.floor(indexAccessor.count / 3);
55
+ }
56
+ else if (positionAccessor?.count) {
57
+ triangleCount += Math.floor(positionAccessor.count / 3);
58
+ }
59
+ }
60
+ }
61
+ const images = json.images ?? [];
62
+ const missingTextureRefs = (json.textures ?? []).filter((texture) => {
63
+ return typeof texture.source !== "number" || !images[texture.source];
64
+ }).length;
65
+ const materialTextureSlots = (json.materials ?? []).reduce((count, material) => {
66
+ return count + countTextureSlots(material);
67
+ }, 0);
68
+ return {
69
+ format,
70
+ version: json.asset?.version,
71
+ nodeCount: json.nodes?.length ?? 0,
72
+ meshCount: json.meshes?.length ?? 0,
73
+ materialCount: json.materials?.length ?? 0,
74
+ textureCount: json.textures?.length ?? 0,
75
+ imageCount: images.length,
76
+ primitiveCount,
77
+ vertexCount,
78
+ triangleCount,
79
+ primitivesMissingNormals,
80
+ primitivesMissingUvs,
81
+ missingTextureRefs,
82
+ materialTextureSlots,
83
+ boundingBox: Number.isFinite(bbox.min[0]) ? bbox : undefined
84
+ };
85
+ }
86
+ function countTextureSlots(value) {
87
+ if (!value || typeof value !== "object") {
88
+ return 0;
89
+ }
90
+ let count = 0;
91
+ for (const [key, nested] of Object.entries(value)) {
92
+ if (key.endsWith("Texture") && nested && typeof nested === "object") {
93
+ count += 1;
94
+ }
95
+ count += countTextureSlots(nested);
96
+ }
97
+ return count;
98
+ }
99
+ //# sourceMappingURL=gltf.js.map