@hybridlabor-api/aos 4.4.0 → 4.4.2-beta.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 (306) hide show
  1. package/.agents/skills/firecrawl/SKILL.md +149 -0
  2. package/.agents/skills/firecrawl/rules/install.md +82 -0
  3. package/.agents/skills/firecrawl/rules/security.md +26 -0
  4. package/.agents/skills/firecrawl-agent/SKILL.md +58 -0
  5. package/.agents/skills/firecrawl-build/SKILL.md +39 -0
  6. package/.agents/skills/firecrawl-build-interact/SKILL.md +68 -0
  7. package/.agents/skills/firecrawl-build-onboarding/SKILL.md +103 -0
  8. package/.agents/skills/firecrawl-build-onboarding/references/auth-flow.md +39 -0
  9. package/.agents/skills/firecrawl-build-onboarding/references/project-setup.md +20 -0
  10. package/.agents/skills/firecrawl-build-onboarding/references/sdk-installation.md +17 -0
  11. package/.agents/skills/firecrawl-build-scrape/SKILL.md +69 -0
  12. package/.agents/skills/firecrawl-build-search/SKILL.md +69 -0
  13. package/.agents/skills/firecrawl-crawl/SKILL.md +59 -0
  14. package/.agents/skills/firecrawl-download/SKILL.md +70 -0
  15. package/.agents/skills/firecrawl-interact/SKILL.md +84 -0
  16. package/.agents/skills/firecrawl-map/SKILL.md +51 -0
  17. package/.agents/skills/firecrawl-scrape/SKILL.md +69 -0
  18. package/.agents/skills/firecrawl-search/SKILL.md +60 -0
  19. package/.claude/hooks/memb-inject.mjs +6 -0
  20. package/CLAUDE.md +573 -0
  21. package/README.de.md +0 -8
  22. package/README.md +0 -8
  23. package/README.pt.md +0 -8
  24. package/assets/brand/ao-ant-mark.svg +91 -0
  25. package/assets/brand/bdb-core-mark.svg +34 -0
  26. package/assets/brand/heimdall-guardian-mark.svg +16 -0
  27. package/assets/brand/memb-crystal-mark.svg +18 -0
  28. package/bin/aos-config.mjs +89 -0
  29. package/bin/aos-dashboard.mjs +608 -0
  30. package/bin/aos-uninstall.mjs +227 -0
  31. package/docs/sessions/audit-2026-09-14-silent-failures.md +114 -0
  32. package/docs/skills_table.md +0 -3
  33. package/installer.js +428 -237
  34. package/mcps/RhinoMCP/cc-plugin/.claude/settings.json +10 -0
  35. package/mcps/after-effects-mcp/build/index.js +840 -0
  36. package/mcps/after-effects-mcp/build/scripts/applyEffect.jsx +153 -0
  37. package/mcps/after-effects-mcp/build/scripts/applyEffectTemplate.jsx +218 -0
  38. package/mcps/after-effects-mcp/build/scripts/createComposition.jsx +71 -0
  39. package/mcps/after-effects-mcp/build/scripts/createShapeLayer.jsx +147 -0
  40. package/mcps/after-effects-mcp/build/scripts/createSolidLayer.jsx +114 -0
  41. package/mcps/after-effects-mcp/build/scripts/createTextLayer.jsx +115 -0
  42. package/mcps/after-effects-mcp/build/scripts/getLayerInfo.jsx +192 -0
  43. package/mcps/after-effects-mcp/build/scripts/getProjectInfo.jsx +90 -0
  44. package/mcps/after-effects-mcp/build/scripts/listCompositions.jsx +50 -0
  45. package/mcps/after-effects-mcp/build/scripts/mcp-bridge-auto.jsx +1773 -0
  46. package/mcps/after-effects-mcp/build/scripts/setLayerProperties.jsx +160 -0
  47. package/mcps/computer-use-mcp/dist/client.d.ts +150 -0
  48. package/mcps/computer-use-mcp/dist/client.js +136 -0
  49. package/mcps/computer-use-mcp/dist/entrypoint.d.ts +16 -0
  50. package/mcps/computer-use-mcp/dist/entrypoint.js +26 -0
  51. package/mcps/computer-use-mcp/dist/native.d.ts +212 -0
  52. package/mcps/computer-use-mcp/dist/native.js +50 -0
  53. package/mcps/computer-use-mcp/dist/server.d.ts +32 -0
  54. package/mcps/computer-use-mcp/dist/server.js +342 -0
  55. package/mcps/computer-use-mcp/dist/session.d.ts +101 -0
  56. package/mcps/computer-use-mcp/dist/session.js +2372 -0
  57. package/package.json +13 -4
  58. package/skills/global_config/aos-project-init/SKILL.md +97 -130
  59. package/skills/global_config/aos-project-init/assets/openwikiignore.template +62 -0
  60. package/skills/global_config/aos-project-init/scripts/aos-project-doctor.mjs +38 -1
  61. package/skills/global_config/aos-setup/SKILL.md +110 -11
  62. package/skills/global_config/aos-setup/scripts/aos-doctor.mjs +48 -4
  63. package/skills/global_config/ask-tim/SKILL.md +2 -7
  64. package/skills/global_config/openwiki-skill/scripts/openwiki_daemon.py +65 -12
  65. package/bin/setup-saas.mjs +0 -792
  66. package/mcps/blender-mcp-server/.dockerignore +0 -19
  67. package/mcps/blender-mcp-server/.github/workflows/ci.yml +0 -67
  68. package/mcps/blender-mcp-server/.github/workflows/publish-pypi.yml +0 -54
  69. package/mcps/blender-mcp-server/CHANGELOG.md +0 -64
  70. package/mcps/blender-mcp-server/CONTRIBUTING.md +0 -107
  71. package/mcps/blender-mcp-server/Dockerfile +0 -19
  72. package/mcps/blender-mcp-server/LICENSE +0 -21
  73. package/mcps/blender-mcp-server/README.md +0 -409
  74. package/mcps/blender-mcp-server/addon/__init__.py +0 -1440
  75. package/mcps/blender-mcp-server/addon/models.py +0 -223
  76. package/mcps/blender-mcp-server/pyproject.toml +0 -120
  77. package/mcps/blender-mcp-server/scripts/blender_bridge_request.py +0 -71
  78. package/mcps/blender-mcp-server/scripts/blender_create_test_cube.py +0 -49
  79. package/mcps/blender-mcp-server/scripts/blender_scene_info.py +0 -38
  80. package/mcps/blender-mcp-server/scripts/build_addon_zip.sh +0 -29
  81. package/mcps/blender-mcp-server/scripts/demos/README.md +0 -186
  82. package/mcps/blender-mcp-server/scripts/demos/dam_break_scene.py +0 -276
  83. package/mcps/blender-mcp-server/scripts/demos/open_dam_break_gui.py +0 -33
  84. package/mcps/blender-mcp-server/scripts/demos/pipe_movement_study.py +0 -518
  85. package/mcps/blender-mcp-server/scripts/demos/pipe_pressure_failure_scene.py +0 -806
  86. package/mcps/blender-mcp-server/scripts/demos/procedural_dam_break_scene.py +0 -600
  87. package/mcps/blender-mcp-server/scripts/demos/run_dam_break.py +0 -510
  88. package/mcps/blender-mcp-server/scripts/launch_blender_gui.py +0 -41
  89. package/mcps/blender-mcp-server/scripts/library/README.md +0 -64
  90. package/mcps/blender-mcp-server/scripts/library/apply_transforms.py +0 -46
  91. package/mcps/blender-mcp-server/scripts/library/camera.py +0 -51
  92. package/mcps/blender-mcp-server/scripts/library/collections.py +0 -65
  93. package/mcps/blender-mcp-server/scripts/library/create_mesh.py +0 -41
  94. package/mcps/blender-mcp-server/scripts/library/effector.py +0 -48
  95. package/mcps/blender-mcp-server/scripts/library/fluid_domain.py +0 -80
  96. package/mcps/blender-mcp-server/scripts/library/fluid_inflow.py +0 -98
  97. package/mcps/blender-mcp-server/scripts/library/frame_range.py +0 -35
  98. package/mcps/blender-mcp-server/scripts/library/keyframes.py +0 -59
  99. package/mcps/blender-mcp-server/scripts/library/rigid_body.py +0 -52
  100. package/mcps/blender-mcp-server/scripts/library/save_blend.py +0 -40
  101. package/mcps/blender-mcp-server/scripts/server_start.sh +0 -26
  102. package/mcps/blender-mcp-server/src/blender_mcp_server/__init__.py +0 -3
  103. package/mcps/blender-mcp-server/src/blender_mcp_server/headless.py +0 -330
  104. package/mcps/blender-mcp-server/src/blender_mcp_server/server.py +0 -606
  105. package/mcps/davinci-mcp-professional/.bandit +0 -35
  106. package/mcps/davinci-mcp-professional/.claude/commands/security-review.md +0 -191
  107. package/mcps/davinci-mcp-professional/.claude/settings.json +0 -1
  108. package/mcps/davinci-mcp-professional/.editorconfig +0 -27
  109. package/mcps/davinci-mcp-professional/.gitattributes +0 -207
  110. package/mcps/davinci-mcp-professional/.github/CODEOWNERS +0 -2
  111. package/mcps/davinci-mcp-professional/.github/ISSUE_TEMPLATE/bug_report.md +0 -33
  112. package/mcps/davinci-mcp-professional/.github/ISSUE_TEMPLATE/feature_request.md +0 -19
  113. package/mcps/davinci-mcp-professional/.github/PULL_REQUEST_TEMPLATE.md +0 -20
  114. package/mcps/davinci-mcp-professional/.github/SECURITY.md +0 -97
  115. package/mcps/davinci-mcp-professional/.github/dependabot.yml +0 -27
  116. package/mcps/davinci-mcp-professional/.github/workflows/ci.yml +0 -39
  117. package/mcps/davinci-mcp-professional/ATTRIBUTION.md +0 -4
  118. package/mcps/davinci-mcp-professional/AUTHORS.md +0 -9
  119. package/mcps/davinci-mcp-professional/BUGS.md +0 -55
  120. package/mcps/davinci-mcp-professional/CLAUDE.md +0 -229
  121. package/mcps/davinci-mcp-professional/CONTRIBUTING.md +0 -51
  122. package/mcps/davinci-mcp-professional/COPYING.md +0 -228
  123. package/mcps/davinci-mcp-professional/Doxyfile +0 -379
  124. package/mcps/davinci-mcp-professional/README.md +0 -143
  125. package/mcps/davinci-mcp-professional/SECURITY.md +0 -40
  126. package/mcps/davinci-mcp-professional/USING.md +0 -301
  127. package/mcps/davinci-mcp-professional/VERSION.md +0 -13
  128. package/mcps/davinci-mcp-professional/build.py +0 -169
  129. package/mcps/davinci-mcp-professional/claude_desktop_config_template.json +0 -11
  130. package/mcps/davinci-mcp-professional/hooks/ci-check.sh +0 -29
  131. package/mcps/davinci-mcp-professional/hooks/pre-push +0 -46
  132. package/mcps/davinci-mcp-professional/main.py +0 -40
  133. package/mcps/davinci-mcp-professional/mcp_server.py +0 -30
  134. package/mcps/davinci-mcp-professional/pyproject.toml +0 -115
  135. package/mcps/davinci-mcp-professional/security_audit.py +0 -379
  136. package/mcps/davinci-mcp-professional/src/davinci_mcp/__init__.py +0 -19
  137. package/mcps/davinci-mcp-professional/src/davinci_mcp/cli.py +0 -138
  138. package/mcps/davinci-mcp-professional/src/davinci_mcp/resolve_client.py +0 -342
  139. package/mcps/davinci-mcp-professional/src/davinci_mcp/resources/__init__.py +0 -60
  140. package/mcps/davinci-mcp-professional/src/davinci_mcp/server.py +0 -185
  141. package/mcps/davinci-mcp-professional/src/davinci_mcp/tools/__init__.py +0 -146
  142. package/mcps/davinci-mcp-professional/src/davinci_mcp/types.py +0 -125
  143. package/mcps/davinci-mcp-professional/src/davinci_mcp/utils/__init__.py +0 -19
  144. package/mcps/davinci-mcp-professional/src/davinci_mcp/utils/platform.py +0 -239
  145. package/mcps/davinci-mcp-professional/test.py +0 -186
  146. package/mcps/davinci-mcp-professional/uv.lock +0 -2073
  147. package/mcps/davinci-resolve-mcp/.claude/skills/media-analysis.md +0 -44
  148. package/mcps/davinci-resolve-mcp/.clinerules +0 -17
  149. package/mcps/davinci-resolve-mcp/.cursorrules +0 -17
  150. package/mcps/davinci-resolve-mcp/.github/copilot-instructions.md +0 -17
  151. package/mcps/davinci-resolve-mcp/.github/workflows/npm-publish.yml +0 -109
  152. package/mcps/davinci-resolve-mcp/.windsurfrules +0 -17
  153. package/mcps/davinci-resolve-mcp/AGENTS.md +0 -114
  154. package/mcps/davinci-resolve-mcp/CHANGELOG.md +0 -2648
  155. package/mcps/davinci-resolve-mcp/CLAUDE.md +0 -15
  156. package/mcps/davinci-resolve-mcp/LICENSE +0 -21
  157. package/mcps/davinci-resolve-mcp/README.md +0 -173
  158. package/mcps/davinci-resolve-mcp/SECURITY.md +0 -53
  159. package/mcps/davinci-resolve-mcp/bin/davinci-resolve-mcp.mjs +0 -450
  160. package/mcps/davinci-resolve-mcp/examples/README.md +0 -53
  161. package/mcps/davinci-resolve-mcp/examples/markers/README.md +0 -81
  162. package/mcps/davinci-resolve-mcp/examples/media/README.md +0 -94
  163. package/mcps/davinci-resolve-mcp/examples/timeline/README.md +0 -98
  164. package/mcps/davinci-resolve-mcp/install.py +0 -1687
  165. package/mcps/davinci-resolve-mcp/package.json +0 -52
  166. package/mcps/davinci-resolve-mcp/release-notes/v2.22.0.md +0 -51
  167. package/mcps/davinci-resolve-mcp/release-notes/v2.23.0.md +0 -51
  168. package/mcps/davinci-resolve-mcp/release-notes/v2.23.1.md +0 -35
  169. package/mcps/davinci-resolve-mcp/release-notes/v2.24.1.md +0 -32
  170. package/mcps/davinci-resolve-mcp/scripts/audit_api_parity.py +0 -275
  171. package/mcps/davinci-resolve-mcp/scripts/audit_readwrite_symmetry.py +0 -80
  172. package/mcps/davinci-resolve-mcp/scripts/doctor.py +0 -227
  173. package/mcps/davinci-resolve-mcp/scripts/gen_api_limitations.py +0 -144
  174. package/mcps/davinci-resolve-mcp/scripts/live_media_analysis_polish_probe.py +0 -65
  175. package/mcps/davinci-resolve-mcp/scripts/measure_bridge_cost.py +0 -65
  176. package/mcps/davinci-resolve-mcp/scripts/regen_panel_screenshots.py +0 -76
  177. package/mcps/davinci-resolve-mcp/src/__init__.py +0 -3
  178. package/mcps/davinci-resolve-mcp/src/analysis_dashboard.py +0 -15505
  179. package/mcps/davinci-resolve-mcp/src/batch_cli.py +0 -540
  180. package/mcps/davinci-resolve-mcp/src/control_panel.py +0 -13
  181. package/mcps/davinci-resolve-mcp/src/granular/__init__.py +0 -17
  182. package/mcps/davinci-resolve-mcp/src/granular/common.py +0 -741
  183. package/mcps/davinci-resolve-mcp/src/granular/folder.py +0 -420
  184. package/mcps/davinci-resolve-mcp/src/granular/gallery.py +0 -306
  185. package/mcps/davinci-resolve-mcp/src/granular/graph.py +0 -309
  186. package/mcps/davinci-resolve-mcp/src/granular/media_pool.py +0 -679
  187. package/mcps/davinci-resolve-mcp/src/granular/media_pool_item.py +0 -1020
  188. package/mcps/davinci-resolve-mcp/src/granular/media_storage.py +0 -179
  189. package/mcps/davinci-resolve-mcp/src/granular/project.py +0 -1654
  190. package/mcps/davinci-resolve-mcp/src/granular/resolve_control.py +0 -538
  191. package/mcps/davinci-resolve-mcp/src/granular/timeline.py +0 -1075
  192. package/mcps/davinci-resolve-mcp/src/granular/timeline_item.py +0 -2251
  193. package/mcps/davinci-resolve-mcp/src/resolve_mcp_server.py +0 -43
  194. package/mcps/davinci-resolve-mcp/src/server.py +0 -24116
  195. package/mcps/davinci-resolve-mcp/src/utils/__init__.py +0 -3
  196. package/mcps/davinci-resolve-mcp/src/utils/actor_identity.py +0 -46
  197. package/mcps/davinci-resolve-mcp/src/utils/analysis_caps.py +0 -678
  198. package/mcps/davinci-resolve-mcp/src/utils/analysis_memory.py +0 -755
  199. package/mcps/davinci-resolve-mcp/src/utils/analysis_runs.py +0 -307
  200. package/mcps/davinci-resolve-mcp/src/utils/analysis_store.py +0 -945
  201. package/mcps/davinci-resolve-mcp/src/utils/api_truth.py +0 -525
  202. package/mcps/davinci-resolve-mcp/src/utils/app_control.py +0 -319
  203. package/mcps/davinci-resolve-mcp/src/utils/audio_fairlight_live_probe.py +0 -263
  204. package/mcps/davinci-resolve-mcp/src/utils/brain_edits.py +0 -387
  205. package/mcps/davinci-resolve-mcp/src/utils/bridge_metrics.py +0 -76
  206. package/mcps/davinci-resolve-mcp/src/utils/cdl.py +0 -20
  207. package/mcps/davinci-resolve-mcp/src/utils/clip_query.py +0 -85
  208. package/mcps/davinci-resolve-mcp/src/utils/cloud_operations.py +0 -192
  209. package/mcps/davinci-resolve-mcp/src/utils/color_grade_live_probe.py +0 -444
  210. package/mcps/davinci-resolve-mcp/src/utils/contracts.py +0 -102
  211. package/mcps/davinci-resolve-mcp/src/utils/cut_ir.py +0 -115
  212. package/mcps/davinci-resolve-mcp/src/utils/dctl_templates.py +0 -368
  213. package/mcps/davinci-resolve-mcp/src/utils/deep_vision.py +0 -643
  214. package/mcps/davinci-resolve-mcp/src/utils/destructive_hook.py +0 -606
  215. package/mcps/davinci-resolve-mcp/src/utils/edit_engine.py +0 -737
  216. package/mcps/davinci-resolve-mcp/src/utils/embeddings.py +0 -922
  217. package/mcps/davinci-resolve-mcp/src/utils/entities.py +0 -579
  218. package/mcps/davinci-resolve-mcp/src/utils/extension_authoring_live_probe.py +0 -292
  219. package/mcps/davinci-resolve-mcp/src/utils/failure_tracker.py +0 -119
  220. package/mcps/davinci-resolve-mcp/src/utils/fuse_templates.py +0 -1968
  221. package/mcps/davinci-resolve-mcp/src/utils/fusion_composition_live_probe.py +0 -284
  222. package/mcps/davinci-resolve-mcp/src/utils/fusion_group_settings.py +0 -334
  223. package/mcps/davinci-resolve-mcp/src/utils/layout_presets.py +0 -333
  224. package/mcps/davinci-resolve-mcp/src/utils/mcp_stdio.py +0 -32
  225. package/mcps/davinci-resolve-mcp/src/utils/mcp_transport.py +0 -128
  226. package/mcps/davinci-resolve-mcp/src/utils/media_analysis.py +0 -7690
  227. package/mcps/davinci-resolve-mcp/src/utils/media_analysis_jobs.py +0 -805
  228. package/mcps/davinci-resolve-mcp/src/utils/media_pool_changes.py +0 -121
  229. package/mcps/davinci-resolve-mcp/src/utils/media_pool_ingest_live_probe.py +0 -592
  230. package/mcps/davinci-resolve-mcp/src/utils/multicam.py +0 -393
  231. package/mcps/davinci-resolve-mcp/src/utils/object_inspection.py +0 -301
  232. package/mcps/davinci-resolve-mcp/src/utils/page_lock.py +0 -75
  233. package/mcps/davinci-resolve-mcp/src/utils/platform.py +0 -157
  234. package/mcps/davinci-resolve-mcp/src/utils/proc.py +0 -26
  235. package/mcps/davinci-resolve-mcp/src/utils/project_cleanup.py +0 -73
  236. package/mcps/davinci-resolve-mcp/src/utils/project_lifecycle_live_probe.py +0 -376
  237. package/mcps/davinci-resolve-mcp/src/utils/project_lint.py +0 -131
  238. package/mcps/davinci-resolve-mcp/src/utils/project_properties.py +0 -601
  239. package/mcps/davinci-resolve-mcp/src/utils/project_spec.py +0 -459
  240. package/mcps/davinci-resolve-mcp/src/utils/readback.py +0 -91
  241. package/mcps/davinci-resolve-mcp/src/utils/render_deliver_live_probe.py +0 -384
  242. package/mcps/davinci-resolve-mcp/src/utils/resolve_ai_governance.py +0 -214
  243. package/mcps/davinci-resolve-mcp/src/utils/resolve_ai_ledger.py +0 -244
  244. package/mcps/davinci-resolve-mcp/src/utils/resolve_busy.py +0 -171
  245. package/mcps/davinci-resolve-mcp/src/utils/resolve_connection.py +0 -77
  246. package/mcps/davinci-resolve-mcp/src/utils/review_annotation_live_probe.py +0 -352
  247. package/mcps/davinci-resolve-mcp/src/utils/script_templates.py +0 -1193
  248. package/mcps/davinci-resolve-mcp/src/utils/shot_relationships.py +0 -544
  249. package/mcps/davinci-resolve-mcp/src/utils/structural_diff.py +0 -175
  250. package/mcps/davinci-resolve-mcp/src/utils/sync_detection.py +0 -889
  251. package/mcps/davinci-resolve-mcp/src/utils/timeline_brain_db.py +0 -826
  252. package/mcps/davinci-resolve-mcp/src/utils/timeline_conform_live_probe.py +0 -280
  253. package/mcps/davinci-resolve-mcp/src/utils/timeline_kernel_live_probe.py +0 -1092
  254. package/mcps/davinci-resolve-mcp/src/utils/timeline_kernel_probe.py +0 -185
  255. package/mcps/davinci-resolve-mcp/src/utils/timeline_title_text.py +0 -87
  256. package/mcps/davinci-resolve-mcp/src/utils/timeline_versioning.py +0 -730
  257. package/mcps/davinci-resolve-mcp/src/utils/update_check.py +0 -685
  258. package/mcps/vectorworks-mcp/.dockerignore +0 -8
  259. package/mcps/vectorworks-mcp/Dockerfile +0 -28
  260. package/mcps/vectorworks-mcp/README.md +0 -156
  261. package/mcps/vectorworks-mcp/app/__init__.py +0 -2
  262. package/mcps/vectorworks-mcp/app/api.py +0 -52
  263. package/mcps/vectorworks-mcp/app/chunking.py +0 -56
  264. package/mcps/vectorworks-mcp/app/config.py +0 -29
  265. package/mcps/vectorworks-mcp/app/embeddings.py +0 -28
  266. package/mcps/vectorworks-mcp/app/indexer.py +0 -106
  267. package/mcps/vectorworks-mcp/app/main.py +0 -33
  268. package/mcps/vectorworks-mcp/app/mcp_server.py +0 -71
  269. package/mcps/vectorworks-mcp/app/search.py +0 -54
  270. package/mcps/vectorworks-mcp/app/utils.py +0 -14
  271. package/mcps/vectorworks-mcp/data/.gitkeep +0 -1
  272. package/mcps/vectorworks-mcp/data/vw-app-help/VW2022_PluginScript.htm +0 -95
  273. package/mcps/vectorworks-mcp/data/vw-app-help/VW2022_ScriptEditor.htm +0 -266
  274. package/mcps/vectorworks-mcp/data/vw-app-help/VW2022_Scripting.htm +0 -106
  275. package/mcps/vectorworks-mcp/data/vw-app-help/VW2023_CreatingScriptedPlugins.htm +0 -327
  276. package/mcps/vectorworks-mcp/data/vw-app-help/VW2024_RunningScripts.htm +0 -116
  277. package/mcps/vectorworks-mcp/data/vw-devwiki/VS_Function_Reference_category.html +0 -2129
  278. package/mcps/vectorworks-mcp/data/vw-jp-ref/ObjectsSymbols.html +0 -2035
  279. package/mcps/vectorworks-mcp/data/vw-jp-ref/ScriptFunctionReference.html +0 -29
  280. package/mcps/vectorworks-mcp/design.md +0 -57
  281. package/mcps/vectorworks-mcp/docker-compose.yml +0 -18
  282. package/mcps/vectorworks-mcp/index/.gitkeep +0 -1
  283. package/mcps/vectorworks-mcp/index/meta.jsonl +0 -3956
  284. package/mcps/vectorworks-mcp/index/vw.faiss +0 -0
  285. package/mcps/vectorworks-mcp/requirements.txt +0 -10
  286. package/mcps/vectorworks-mcp/scripts/fetch_docs_minimal.sh +0 -84
  287. package/mcps/vectorworks-mcp/scripts/fetch_github_vectorworks.sh +0 -85
  288. package/mcps/vectorworks-mcp/templates/index.html +0 -40
  289. package/scripts/ecosystem-health-audit.js +0 -257
  290. package/skills/bdb-dev-os-skill/SKILL.md +0 -49
  291. package/skills/bdb-dev-os-skill/package.json +0 -11
  292. package/skills/bdbsaastraining/SKILL.md +0 -316
  293. package/skills/bdbsaastraining/references/exam-pool.md +0 -313
  294. package/skills/bdbsaastraining/references/interaction-modes.md +0 -94
  295. package/skills/bdbsaastraining/references/track-a-ai-agent.md +0 -111
  296. package/skills/bdbsaastraining/references/track-b-wordpress.md +0 -111
  297. package/skills/bdbsaastraining/references/track-c-mailserver.md +0 -107
  298. package/skills/bdbsaastraining/references/track-d-debian.md +0 -109
  299. package/skills/bdbsaastraining/references/track-e-custom.md +0 -83
  300. package/skills/bdbsaastraining/scripts/build_profile.py +0 -529
  301. package/skills/bdbsaastraining/scripts/generate_certificate.py +0 -161
  302. package/skills/bdbsaastraining/scripts/preflight_check.sh +0 -150
  303. package/skills/bdbsaastraining/templates/certificate_template.html +0 -508
  304. package/skills/global_config/bdb-ecosystem-health/SKILL.md +0 -68
  305. package/skills/global_config/bdbsaas-ops/SKILL.md +0 -16
  306. package/skills/global_config/bdbsaashost/SKILL.md +0 -125
@@ -1,679 +0,0 @@
1
- """Media pool operations and MediaPool API tools."""
2
-
3
- from src.granular.common import * # noqa: F401,F403
4
- from src.utils.multicam import build_multicam_setup_plan
5
-
6
- resolve = ResolveProxy()
7
-
8
-
9
- def _ensure_timeline_tracks_for_multicam(timeline, track_type: str, needed: int, audio_type: str = "stereo"):
10
- needed = max(0, int(needed or 0))
11
- added = 0
12
- try:
13
- current = int(timeline.GetTrackCount(track_type) or 0)
14
- except Exception as exc:
15
- return {"success": False, "error": f"GetTrackCount({track_type}) failed: {exc}"}
16
- while current < needed:
17
- try:
18
- if track_type == "audio":
19
- ok = timeline.AddTrack(track_type, {"audioType": audio_type})
20
- else:
21
- ok = timeline.AddTrack(track_type)
22
- except TypeError:
23
- ok = timeline.AddTrack(track_type)
24
- except Exception as exc:
25
- return {"success": False, "error": f"AddTrack({track_type}) failed: {exc}"}
26
- if not ok:
27
- return {"success": False, "error": f"AddTrack({track_type}) returned false at track {current + 1}"}
28
- current += 1
29
- added += 1
30
- return {"success": True, "existing": current - added, "added": added, "count": current}
31
-
32
-
33
- def _set_multicam_track_names(timeline, plan):
34
- results = []
35
- for angle in plan.get("angles") or []:
36
- angle_name = angle.get("angle_name") or f"Angle {angle.get('angle_index')}"
37
- video_track = angle.get("video_track_index")
38
- if video_track:
39
- try:
40
- results.append({
41
- "track_type": "video",
42
- "track_index": video_track,
43
- "name": angle_name,
44
- "success": bool(timeline.SetTrackName("video", int(video_track), str(angle_name))),
45
- })
46
- except Exception as exc:
47
- results.append({"track_type": "video", "track_index": video_track, "success": False, "error": str(exc)})
48
- audio_track = angle.get("audio_track_index")
49
- if audio_track:
50
- try:
51
- results.append({
52
- "track_type": "audio",
53
- "track_index": audio_track,
54
- "name": angle_name,
55
- "success": bool(timeline.SetTrackName("audio", int(audio_track), str(angle_name))),
56
- })
57
- except Exception as exc:
58
- results.append({"track_type": "audio", "track_index": audio_track, "success": False, "error": str(exc)})
59
- return results
60
-
61
-
62
- def _appended_item_summary(item):
63
- try:
64
- item_id = item.GetUniqueId()
65
- except Exception:
66
- item_id = None
67
- try:
68
- name = item.GetName()
69
- except Exception:
70
- name = None
71
- return {"timeline_item_id": item_id, "name": name}
72
-
73
- @mcp.resource("resolve://media-pool-clips")
74
- def list_media_pool_clips() -> List[Dict[str, Any]]:
75
- """List all clips in the root folder of the media pool."""
76
- pm, current_project = get_current_project()
77
- if not current_project:
78
- return [{"error": "No project currently open"}]
79
-
80
- media_pool = current_project.GetMediaPool()
81
- if not media_pool:
82
- return [{"error": "Failed to get Media Pool"}]
83
-
84
- root_folder = media_pool.GetRootFolder()
85
- if not root_folder:
86
- return [{"error": "Failed to get root folder"}]
87
-
88
- clips = root_folder.GetClipList()
89
- if not clips:
90
- return [{"info": "No clips found in the root folder"}]
91
-
92
- # Return a simplified list with basic clip info
93
- result = []
94
- for clip in clips:
95
- result.append({
96
- "name": clip.GetName(),
97
- "duration": clip.GetDuration(),
98
- "fps": clip.GetClipProperty("FPS")
99
- })
100
-
101
- return result
102
-
103
-
104
- @mcp.tool(annotations=EXTERNAL_WRITE_TOOL)
105
- def import_media(
106
- paths: Optional[List[str]] = None,
107
- clip_infos: Optional[List[Dict[str, Any]]] = None,
108
- file_path: Optional[str] = None,
109
- ) -> Dict[str, Any]:
110
- """Import media into the current project's media pool.
111
-
112
- Args:
113
- paths: Simple form — list of file or folder paths to import.
114
- clip_infos: Image-sequence form — list of dicts with keys FilePath
115
- (required), StartIndex, EndIndex. Mirrors
116
- MediaPool.ImportMedia([{clipInfo}, ...]). Each entry imports as
117
- one MediaPoolItem unless 'Show Individual Frames' is enabled.
118
- Example: [{"FilePath": "frame_%03d.dpx", "StartIndex": 1, "EndIndex": 100}]
119
- file_path: Single-path convenience for backward compatibility.
120
- """
121
- project, mp, err = _get_mp()
122
- if err:
123
- return err
124
- if clip_infos is not None:
125
- if not isinstance(clip_infos, list) or not clip_infos:
126
- return {"error": "clip_infos must be a non-empty list"}
127
- for i, ci in enumerate(clip_infos):
128
- if not isinstance(ci, dict):
129
- return {"error": f"clip_infos[{i}] must be an object"}
130
- if not ci.get("FilePath"):
131
- return {"error": f"clip_infos[{i}] requires FilePath"}
132
- result = mp.ImportMedia(clip_infos)
133
- else:
134
- path_list = paths if paths is not None else ([file_path] if file_path else None)
135
- if not path_list:
136
- return {"error": "Provide paths (list), clip_infos (image sequences), or file_path"}
137
- result = mp.ImportMedia(path_list)
138
- if not result:
139
- return {"success": False, "error": "Failed to import media"}
140
- return {
141
- "success": True,
142
- "imported": len(result),
143
- "clips": [{"name": c.GetName(), "id": c.GetUniqueId()} for c in result],
144
- }
145
-
146
-
147
- @mcp.tool()
148
- def append_to_timeline(
149
- clip_ids: Optional[List[str]] = None,
150
- clip_infos: Optional[List[Dict[str, Any]]] = None,
151
- ) -> Dict[str, Any]:
152
- """Append clips to the current timeline.
153
-
154
- Mirrors MediaPool.AppendToTimeline per docs lines 219-221. Two forms:
155
-
156
- Args:
157
- clip_ids: Simple form — list of MediaPoolItem unique IDs to append in order.
158
- clip_infos: Positioned form — list of dicts with keys clip_id (or
159
- media_pool_item_id), start_frame, end_frame, record_frame, track_index,
160
- and optional media_type (1=video only, 2=audio only). record_frame is
161
- relative to the current timeline start frame by default; pass
162
- record_frame_mode="absolute" for raw Resolve recordFrame values.
163
- Returns timeline_item_id per appended item.
164
- """
165
- project, mp, err = _get_mp()
166
- if err:
167
- return err
168
- if clip_infos is not None:
169
- if not isinstance(clip_infos, list) or not clip_infos:
170
- return {"error": "clip_infos must be a non-empty list"}
171
- root = mp.GetRootFolder()
172
- current_timeline = project.GetCurrentTimeline() if project else None
173
- timeline_start = _timeline_start_frame(current_timeline)
174
- built = []
175
- for i, ci in enumerate(clip_infos):
176
- row, row_err = _build_append_clip_info_dict(root, ci, i, timeline_start)
177
- if row_err:
178
- return row_err
179
- built.append(row)
180
- result = mp.AppendToTimeline(built)
181
- if not result:
182
- return {"success": False, "error": "Failed to append clip_infos to timeline"}
183
- items_out = []
184
- for i, item in enumerate(result):
185
- if not item:
186
- return {"success": False, "error": f"Missing timeline item at index {i}"}
187
- try:
188
- item_id = item.GetUniqueId()
189
- name = item.GetName()
190
- except Exception as exc:
191
- return {"success": False, "error": f"Invalid timeline item at index {i}: {exc}"}
192
- if not item_id:
193
- return {"success": False, "error": f"Missing timeline item id at index {i}"}
194
- items_out.append({"timeline_item_id": item_id, "name": name})
195
- return {"success": True, "count": len(items_out), "items": items_out}
196
- if not clip_ids:
197
- return {"error": "Provide clip_ids (simple) or clip_infos (positioned)"}
198
- root = mp.GetRootFolder()
199
- clips = [_find_clip_by_id(root, cid) for cid in clip_ids]
200
- clips = [c for c in clips if c]
201
- if not clips:
202
- return {"error": "No valid clips found"}
203
- result = mp.AppendToTimeline(clips)
204
- return {"success": True, "count": len(result) if result else 0}
205
-
206
-
207
- @mcp.tool()
208
- def setup_multicam_timeline(
209
- name: str = "Multicam Setup",
210
- clip_ids: Optional[List[str]] = None,
211
- angles: Optional[List[Dict[str, Any]]] = None,
212
- sync_mode: str = "stack_start",
213
- include_audio: bool = False,
214
- audio_track_mode: str = "matching",
215
- start_timecode: Optional[str] = None,
216
- timeline_start_timecode: Optional[str] = None,
217
- record_frame_start: int = 0,
218
- frame_rate: Optional[Any] = None,
219
- audio_type: str = "stereo",
220
- dry_run: bool = False,
221
- ) -> Dict[str, Any]:
222
- """Create a stacked multicam prep timeline from Media Pool clips.
223
-
224
- This does not create a native Resolve multicam clip because the public
225
- scripting API does not expose native multicam creation. It creates a prep
226
- timeline with one angle per video track and optional matching audio tracks.
227
-
228
- Args:
229
- name: Name for the setup timeline.
230
- clip_ids: Simple list of MediaPoolItem unique IDs, one per angle.
231
- angles: Detailed angle rows with clip_id, optional angle_name,
232
- start_frame/end_frame, record_frame, source_timecode, track_index.
233
- sync_mode: 'stack_start', 'record_frame', or 'source_timecode'.
234
- include_audio: Also append audio-only rows.
235
- audio_track_mode: 'matching' for per-angle audio tracks, or 'first'.
236
- start_timecode: Optional timeline start timecode to set after creation.
237
- timeline_start_timecode: Base timecode for source_timecode sync math.
238
- record_frame_start: Timeline-relative start frame for stack_start mode.
239
- frame_rate: Fallback frame rate for duration/timecode parsing.
240
- audio_type: Resolve audio track type when tracks must be added.
241
- dry_run: Return the plan without creating a timeline.
242
- """
243
- project, mp, err = _get_mp()
244
- if err:
245
- return err
246
- root = mp.GetRootFolder()
247
- params = {
248
- "name": name,
249
- "clip_ids": clip_ids,
250
- "angles": angles,
251
- "sync_mode": sync_mode,
252
- "include_audio": include_audio,
253
- "audio_track_mode": audio_track_mode,
254
- "start_timecode": start_timecode,
255
- "timeline_start_timecode": timeline_start_timecode,
256
- "record_frame_start": record_frame_start,
257
- "frame_rate": frame_rate,
258
- "audio_type": audio_type,
259
- "dry_run": dry_run,
260
- }
261
- plan, plan_err = build_multicam_setup_plan(root, params, _find_clip_by_id)
262
- if plan_err:
263
- return plan_err
264
- if dry_run:
265
- return {
266
- **plan,
267
- "dry_run": True,
268
- "would_create_timeline": True,
269
- "would_append": len(plan.get("append_rows") or []),
270
- }
271
-
272
- timeline = mp.CreateEmptyTimeline(plan["name"])
273
- if not timeline:
274
- return {"error": f"Failed to create multicam setup timeline: {plan['name']}"}
275
- try:
276
- project.SetCurrentTimeline(timeline)
277
- except Exception:
278
- pass
279
- if plan.get("start_timecode"):
280
- try:
281
- timeline.SetStartTimecode(plan["start_timecode"])
282
- except Exception:
283
- pass
284
-
285
- video_tracks = _ensure_timeline_tracks_for_multicam(timeline, "video", plan.get("max_video_track", 0))
286
- if not video_tracks.get("success"):
287
- return video_tracks
288
- audio_tracks = _ensure_timeline_tracks_for_multicam(
289
- timeline,
290
- "audio",
291
- plan.get("max_audio_track", 0),
292
- audio_type=audio_type,
293
- )
294
- if not audio_tracks.get("success"):
295
- return audio_tracks
296
- track_names = _set_multicam_track_names(timeline, plan)
297
-
298
- timeline_start = _timeline_start_frame(timeline)
299
- append_rows = plan.get("append_rows") or []
300
- append_infos = []
301
- for index, row in enumerate(append_rows):
302
- clip_info, clip_err = _build_append_clip_info_dict(root, row, index, timeline_start)
303
- if clip_err:
304
- return clip_err
305
- append_infos.append(clip_info)
306
- appended = mp.AppendToTimeline(append_infos)
307
- if not appended:
308
- return {"error": "AppendToTimeline returned no items for multicam setup"}
309
-
310
- items = []
311
- for index, item in enumerate(appended):
312
- summary = _appended_item_summary(item)
313
- summary["setup_row"] = append_rows[index]
314
- items.append(summary)
315
- return {
316
- **plan,
317
- "dry_run": False,
318
- "timeline_name": timeline.GetName(),
319
- "timeline_id": timeline.GetUniqueId(),
320
- "items": items,
321
- "track_setup": {"video": video_tracks, "audio": audio_tracks, "names": track_names},
322
- }
323
-
324
-
325
- @mcp.tool()
326
- def auto_sync_audio(
327
- clip_ids: List[str],
328
- sync_mode: Optional[str] = None,
329
- channel_number: Optional[Any] = None,
330
- retain_embedded_audio: Optional[bool] = None,
331
- retain_video_metadata: Optional[bool] = None,
332
- ) -> Dict[str, Any]:
333
- """Sync audio across multiple clips.
334
-
335
- Mirrors MediaPool.AutoSyncAudio([items], {audioSyncSettings}) per docs lines 600-614.
336
-
337
- Args:
338
- clip_ids: List of MediaPoolItem unique IDs to sync.
339
- sync_mode: 'waveform' or 'timecode' (default on Resolve side: 'timecode').
340
- channel_number: int >= 1 for channel offset, or 'automatic' (-1) / 'mix' (-2).
341
- Only used in waveform mode.
342
- retain_embedded_audio: keep clip's embedded audio after sync.
343
- retain_video_metadata: keep video clip's metadata after sync.
344
- """
345
- r = get_resolve()
346
- if r is None:
347
- return {"error": "Not connected to DaVinci Resolve"}
348
- _, mp, err = _get_mp()
349
- if err:
350
- return err
351
- if not clip_ids:
352
- return {"error": "clip_ids must be a non-empty list"}
353
- root = mp.GetRootFolder()
354
- clips = [_find_clip_by_id(root, cid) for cid in clip_ids]
355
- clips = [c for c in clips if c]
356
- if not clips:
357
- return {"error": "No valid clips found"}
358
- settings, settings_err = _build_audio_sync_settings(
359
- r, sync_mode=sync_mode, channel_number=channel_number,
360
- retain_embedded_audio=retain_embedded_audio,
361
- retain_video_metadata=retain_video_metadata,
362
- )
363
- if settings_err:
364
- return settings_err
365
- return {"success": bool(mp.AutoSyncAudio(clips, settings))}
366
-
367
-
368
- @mcp.tool()
369
- def add_subfolder(folder_name: str) -> Dict[str, Any]:
370
- """Create a new subfolder in the current Media Pool folder.
371
-
372
- Args:
373
- folder_name: Name of the subfolder to create.
374
- """
375
- _, mp, err = _get_mp()
376
- if err:
377
- return err
378
- folder = mp.AddSubFolder(mp.GetCurrentFolder(), folder_name)
379
- if folder:
380
- return {"success": True, "folder_name": folder.GetName(), "unique_id": folder.GetUniqueId()}
381
- return {"success": False, "error": f"Failed to create subfolder '{folder_name}'"}
382
-
383
-
384
- @mcp.tool()
385
- def refresh_media_pool_folders() -> Dict[str, Any]:
386
- """Refresh all folders in the Media Pool."""
387
- _, mp, err = _get_mp()
388
- if err:
389
- return err
390
- result = mp.RefreshFolders()
391
- return {"success": bool(result)}
392
-
393
-
394
- @mcp.tool()
395
- def import_timeline_from_file(file_path: str, import_options: Optional[Dict[str, Any]] = None) -> Dict[str, Any]:
396
- """Import a timeline from a file (AAF, EDL, XML, FCPXML, DRT, ADL, OTIO).
397
-
398
- Args:
399
- file_path: Absolute path to the timeline file.
400
- import_options: Optional dict of import options.
401
- """
402
- _, mp, err = _get_mp()
403
- if err:
404
- return err
405
- if import_options:
406
- tl = mp.ImportTimelineFromFile(file_path, import_options)
407
- else:
408
- tl = mp.ImportTimelineFromFile(file_path)
409
- if tl:
410
- return {"success": True, "timeline_name": tl.GetName(), "unique_id": tl.GetUniqueId()}
411
- return {"success": False, "error": f"Failed to import timeline from '{file_path}'"}
412
-
413
-
414
- @mcp.tool()
415
- def delete_timelines_by_id(timeline_ids: List[str]) -> Dict[str, Any]:
416
- """Delete timelines by their unique IDs.
417
-
418
- Args:
419
- timeline_ids: List of timeline unique IDs to delete.
420
- """
421
- project, mp, err = _get_mp()
422
- if err:
423
- return err
424
- timelines = []
425
- for i in range(1, project.GetTimelineCount() + 1):
426
- tl = project.GetTimelineByIndex(i)
427
- if tl and tl.GetUniqueId() in timeline_ids:
428
- timelines.append(tl)
429
- if not timelines:
430
- return {"error": "No matching timelines found"}
431
- result = mp.DeleteTimelines(timelines)
432
- return {"success": bool(result), "deleted_count": len(timelines)}
433
-
434
-
435
- @mcp.tool()
436
- def set_current_media_pool_folder(folder_path: str) -> Dict[str, Any]:
437
- """Navigate to a specific folder in the Media Pool.
438
-
439
- Args:
440
- folder_path: Folder path using '/' separators from root (e.g. 'Master/Footage').
441
- """
442
- _, mp, err = _get_mp()
443
- if err:
444
- return err
445
- target = _navigate_to_folder(mp, folder_path)
446
- if not target:
447
- return {"error": f"Folder '{folder_path}' not found"}
448
- result = mp.SetCurrentFolder(target)
449
- return {"success": bool(result), "folder": target.GetName()}
450
-
451
-
452
- @mcp.tool()
453
- def delete_media_pool_clips(clip_ids: List[str]) -> Dict[str, Any]:
454
- """Delete clips from the Media Pool by their unique IDs.
455
-
456
- Args:
457
- clip_ids: List of clip unique IDs to delete.
458
- """
459
- _, mp, err = _get_mp()
460
- if err:
461
- return err
462
- clips = _find_clips_by_ids(mp.GetRootFolder(), set(clip_ids))
463
- if not clips:
464
- return {"error": "No matching clips found"}
465
- result = mp.DeleteClips(clips)
466
- return {"success": bool(result), "deleted_count": len(clips)}
467
-
468
-
469
- @mcp.tool()
470
- def import_folder_from_file(file_path: str) -> Dict[str, Any]:
471
- """Import a Media Pool folder structure from a file.
472
-
473
- Args:
474
- file_path: Absolute path to the file.
475
- """
476
- _, mp, err = _get_mp()
477
- if err:
478
- return err
479
- result = mp.ImportFolderFromFile(file_path)
480
- return {"success": bool(result), "file_path": file_path}
481
-
482
-
483
- @mcp.tool()
484
- def delete_media_pool_folders(folder_names: List[str]) -> Dict[str, Any]:
485
- """Delete folders from the current Media Pool location.
486
-
487
- Args:
488
- folder_names: List of folder names to delete.
489
- """
490
- _, mp, err = _get_mp()
491
- if err:
492
- return err
493
- current = mp.GetCurrentFolder()
494
- folders = [sub for sub in (current.GetSubFolderList() or []) if sub.GetName() in folder_names]
495
- if not folders:
496
- return {"error": "No matching folders found"}
497
- result = mp.DeleteFolders(folders)
498
- return {"success": bool(result), "deleted_count": len(folders)}
499
-
500
-
501
- @mcp.tool()
502
- def move_clips_to_folder(clip_ids: List[str], target_folder_path: str) -> Dict[str, Any]:
503
- """Move clips to a different Media Pool folder.
504
-
505
- Args:
506
- clip_ids: List of clip unique IDs to move.
507
- target_folder_path: Path to target folder (e.g. 'Master/Footage').
508
- """
509
- _, mp, err = _get_mp()
510
- if err:
511
- return err
512
- clips = _find_clips_by_ids(mp.GetRootFolder(), set(clip_ids))
513
- if not clips:
514
- return {"error": "No matching clips found"}
515
- target = _navigate_to_folder(mp, target_folder_path)
516
- if not target:
517
- return {"error": f"Target folder '{target_folder_path}' not found"}
518
- result = mp.MoveClips(clips, target)
519
- return {"success": bool(result), "moved_count": len(clips)}
520
-
521
-
522
- @mcp.tool()
523
- def move_media_pool_folders(folder_names: List[str], target_folder_path: str) -> Dict[str, Any]:
524
- """Move folders to a different Media Pool location.
525
-
526
- Args:
527
- folder_names: List of folder names to move.
528
- target_folder_path: Path to target folder.
529
- """
530
- _, mp, err = _get_mp()
531
- if err:
532
- return err
533
- current = mp.GetCurrentFolder()
534
- folders = [sub for sub in (current.GetSubFolderList() or []) if sub.GetName() in folder_names]
535
- if not folders:
536
- return {"error": "No matching folders found"}
537
- target = _navigate_to_folder(mp, target_folder_path)
538
- if not target:
539
- return {"error": f"Target folder '{target_folder_path}' not found"}
540
- result = mp.MoveFolders(folders, target)
541
- return {"success": bool(result), "moved_count": len(folders)}
542
-
543
-
544
- @mcp.tool()
545
- def get_clip_matte_list(clip_id: str) -> Dict[str, Any]:
546
- """Get list of clip mattes for a MediaPoolItem.
547
-
548
- Args:
549
- clip_id: Unique ID of the clip.
550
- """
551
- _, mp, err = _get_mp()
552
- if err:
553
- return err
554
- clip = _find_clip_by_id(mp.GetRootFolder(), clip_id)
555
- if not clip:
556
- return {"error": f"Clip with ID {clip_id} not found"}
557
- mattes = mp.GetClipMatteList(clip)
558
- return {"clip_id": clip_id, "mattes": mattes if mattes else []}
559
-
560
-
561
- @mcp.tool()
562
- def get_timeline_matte_list(item_index: int = 0, track_type: str = "video", track_index: int = 1) -> Dict[str, Any]:
563
- """Get list of timeline mattes for a timeline item.
564
-
565
- Args:
566
- item_index: 0-based index of the item in the track. Default: 0.
567
- track_type: 'video' or 'audio'. Default: 'video'.
568
- track_index: 1-based track index. Default: 1.
569
- """
570
- project, mp, err = _get_mp()
571
- if err:
572
- return err
573
- tl = project.GetCurrentTimeline()
574
- if not tl:
575
- return {"error": "No current timeline"}
576
- items = tl.GetItemListInTrack(track_type, track_index)
577
- if not items or item_index < 0 or item_index >= len(items): # reject negatives (EX5)
578
- return {"error": f"No item at index {item_index}"}
579
- mattes = mp.GetTimelineMatteList(items[item_index])
580
- return {"mattes": mattes if mattes else []}
581
-
582
-
583
- @mcp.tool()
584
- def delete_clip_mattes(clip_id: str, matte_paths: List[str]) -> Dict[str, Any]:
585
- """Delete clip mattes from a MediaPoolItem.
586
-
587
- Args:
588
- clip_id: Unique ID of the clip.
589
- matte_paths: List of matte file paths to delete.
590
- """
591
- _, mp, err = _get_mp()
592
- if err:
593
- return err
594
- clip = _find_clip_by_id(mp.GetRootFolder(), clip_id)
595
- if not clip:
596
- return {"error": f"Clip with ID {clip_id} not found"}
597
- result = mp.DeleteClipMattes(clip, matte_paths)
598
- return {"success": bool(result)}
599
-
600
-
601
- @mcp.tool()
602
- def export_media_pool_metadata(file_path: str) -> Dict[str, Any]:
603
- """Export metadata of clips in the current Media Pool folder to a CSV file.
604
-
605
- Args:
606
- file_path: Absolute path for the exported CSV file.
607
- """
608
- _, mp, err = _get_mp()
609
- if err:
610
- return err
611
- result = mp.ExportMetadata(file_path)
612
- return {"success": bool(result), "file_path": file_path}
613
-
614
-
615
- @mcp.tool()
616
- def get_media_pool_unique_id() -> Dict[str, Any]:
617
- """Get the unique ID of the Media Pool."""
618
- _, mp, err = _get_mp()
619
- if err:
620
- return err
621
- return {"unique_id": mp.GetUniqueId()}
622
-
623
-
624
- @mcp.tool()
625
- def create_stereo_clip(left_clip_id: str, right_clip_id: str) -> Dict[str, Any]:
626
- """Create a stereo clip from left and right eye clips.
627
-
628
- Args:
629
- left_clip_id: Unique ID of the left eye clip.
630
- right_clip_id: Unique ID of the right eye clip.
631
- """
632
- _, mp, err = _get_mp()
633
- if err:
634
- return err
635
- root = mp.GetRootFolder()
636
- left = _find_clip_by_id(root, left_clip_id)
637
- right = _find_clip_by_id(root, right_clip_id)
638
- if not left:
639
- return {"error": f"Left clip {left_clip_id} not found"}
640
- if not right:
641
- return {"error": f"Right clip {right_clip_id} not found"}
642
- result = mp.CreateStereoClip(left, right)
643
- return {"success": bool(result)}
644
-
645
-
646
- @mcp.tool()
647
- def get_selected_clips() -> Dict[str, Any]:
648
- """Get currently selected clips in the Media Pool."""
649
- _, mp, err = _get_mp()
650
- if err:
651
- return err
652
- clips = mp.GetSelectedClips()
653
- if clips:
654
- result = []
655
- for clip in clips:
656
- try:
657
- result.append({"name": clip.GetName(), "unique_id": clip.GetUniqueId()})
658
- except Exception:
659
- logger.debug("Could not read selected clip identity", exc_info=True)
660
- result.append({"name": "Unknown"})
661
- return {"selected_clips": result}
662
- return {"selected_clips": []}
663
-
664
-
665
- @mcp.tool()
666
- def set_selected_clip(clip_id: str) -> Dict[str, Any]:
667
- """Set a clip as selected in the Media Pool.
668
-
669
- Args:
670
- clip_id: Unique ID of the clip to select.
671
- """
672
- _, mp, err = _get_mp()
673
- if err:
674
- return err
675
- clip = _find_clip_by_id(mp.GetRootFolder(), clip_id)
676
- if not clip:
677
- return {"error": f"Clip {clip_id} not found"}
678
- result = mp.SetSelectedClip(clip)
679
- return {"success": bool(result)}