@hybridlabor-api/aos 4.4.1 → 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 (305) 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.md +573 -0
  20. package/README.de.md +0 -8
  21. package/README.md +0 -8
  22. package/README.pt.md +0 -8
  23. package/assets/brand/ao-ant-mark.svg +91 -0
  24. package/assets/brand/bdb-core-mark.svg +34 -0
  25. package/assets/brand/heimdall-guardian-mark.svg +16 -0
  26. package/assets/brand/memb-crystal-mark.svg +18 -0
  27. package/bin/aos-config.mjs +89 -0
  28. package/bin/aos-dashboard.mjs +608 -0
  29. package/bin/aos-uninstall.mjs +227 -0
  30. package/docs/sessions/audit-2026-09-14-silent-failures.md +114 -0
  31. package/docs/skills_table.md +0 -3
  32. package/installer.js +387 -237
  33. package/mcps/RhinoMCP/cc-plugin/.claude/settings.json +10 -0
  34. package/mcps/after-effects-mcp/build/index.js +840 -0
  35. package/mcps/after-effects-mcp/build/scripts/applyEffect.jsx +153 -0
  36. package/mcps/after-effects-mcp/build/scripts/applyEffectTemplate.jsx +218 -0
  37. package/mcps/after-effects-mcp/build/scripts/createComposition.jsx +71 -0
  38. package/mcps/after-effects-mcp/build/scripts/createShapeLayer.jsx +147 -0
  39. package/mcps/after-effects-mcp/build/scripts/createSolidLayer.jsx +114 -0
  40. package/mcps/after-effects-mcp/build/scripts/createTextLayer.jsx +115 -0
  41. package/mcps/after-effects-mcp/build/scripts/getLayerInfo.jsx +192 -0
  42. package/mcps/after-effects-mcp/build/scripts/getProjectInfo.jsx +90 -0
  43. package/mcps/after-effects-mcp/build/scripts/listCompositions.jsx +50 -0
  44. package/mcps/after-effects-mcp/build/scripts/mcp-bridge-auto.jsx +1773 -0
  45. package/mcps/after-effects-mcp/build/scripts/setLayerProperties.jsx +160 -0
  46. package/mcps/computer-use-mcp/dist/client.d.ts +150 -0
  47. package/mcps/computer-use-mcp/dist/client.js +136 -0
  48. package/mcps/computer-use-mcp/dist/entrypoint.d.ts +16 -0
  49. package/mcps/computer-use-mcp/dist/entrypoint.js +26 -0
  50. package/mcps/computer-use-mcp/dist/native.d.ts +212 -0
  51. package/mcps/computer-use-mcp/dist/native.js +50 -0
  52. package/mcps/computer-use-mcp/dist/server.d.ts +32 -0
  53. package/mcps/computer-use-mcp/dist/server.js +342 -0
  54. package/mcps/computer-use-mcp/dist/session.d.ts +101 -0
  55. package/mcps/computer-use-mcp/dist/session.js +2372 -0
  56. package/package.json +13 -4
  57. package/skills/global_config/aos-project-init/SKILL.md +97 -130
  58. package/skills/global_config/aos-project-init/assets/openwikiignore.template +62 -0
  59. package/skills/global_config/aos-project-init/scripts/aos-project-doctor.mjs +38 -1
  60. package/skills/global_config/aos-setup/SKILL.md +98 -8
  61. package/skills/global_config/aos-setup/scripts/aos-doctor.mjs +21 -2
  62. package/skills/global_config/ask-tim/SKILL.md +2 -7
  63. package/skills/global_config/openwiki-skill/scripts/openwiki_daemon.py +65 -12
  64. package/bin/setup-saas.mjs +0 -792
  65. package/mcps/blender-mcp-server/.dockerignore +0 -19
  66. package/mcps/blender-mcp-server/.github/workflows/ci.yml +0 -67
  67. package/mcps/blender-mcp-server/.github/workflows/publish-pypi.yml +0 -54
  68. package/mcps/blender-mcp-server/CHANGELOG.md +0 -64
  69. package/mcps/blender-mcp-server/CONTRIBUTING.md +0 -107
  70. package/mcps/blender-mcp-server/Dockerfile +0 -19
  71. package/mcps/blender-mcp-server/LICENSE +0 -21
  72. package/mcps/blender-mcp-server/README.md +0 -409
  73. package/mcps/blender-mcp-server/addon/__init__.py +0 -1440
  74. package/mcps/blender-mcp-server/addon/models.py +0 -223
  75. package/mcps/blender-mcp-server/pyproject.toml +0 -120
  76. package/mcps/blender-mcp-server/scripts/blender_bridge_request.py +0 -71
  77. package/mcps/blender-mcp-server/scripts/blender_create_test_cube.py +0 -49
  78. package/mcps/blender-mcp-server/scripts/blender_scene_info.py +0 -38
  79. package/mcps/blender-mcp-server/scripts/build_addon_zip.sh +0 -29
  80. package/mcps/blender-mcp-server/scripts/demos/README.md +0 -186
  81. package/mcps/blender-mcp-server/scripts/demos/dam_break_scene.py +0 -276
  82. package/mcps/blender-mcp-server/scripts/demos/open_dam_break_gui.py +0 -33
  83. package/mcps/blender-mcp-server/scripts/demos/pipe_movement_study.py +0 -518
  84. package/mcps/blender-mcp-server/scripts/demos/pipe_pressure_failure_scene.py +0 -806
  85. package/mcps/blender-mcp-server/scripts/demos/procedural_dam_break_scene.py +0 -600
  86. package/mcps/blender-mcp-server/scripts/demos/run_dam_break.py +0 -510
  87. package/mcps/blender-mcp-server/scripts/launch_blender_gui.py +0 -41
  88. package/mcps/blender-mcp-server/scripts/library/README.md +0 -64
  89. package/mcps/blender-mcp-server/scripts/library/apply_transforms.py +0 -46
  90. package/mcps/blender-mcp-server/scripts/library/camera.py +0 -51
  91. package/mcps/blender-mcp-server/scripts/library/collections.py +0 -65
  92. package/mcps/blender-mcp-server/scripts/library/create_mesh.py +0 -41
  93. package/mcps/blender-mcp-server/scripts/library/effector.py +0 -48
  94. package/mcps/blender-mcp-server/scripts/library/fluid_domain.py +0 -80
  95. package/mcps/blender-mcp-server/scripts/library/fluid_inflow.py +0 -98
  96. package/mcps/blender-mcp-server/scripts/library/frame_range.py +0 -35
  97. package/mcps/blender-mcp-server/scripts/library/keyframes.py +0 -59
  98. package/mcps/blender-mcp-server/scripts/library/rigid_body.py +0 -52
  99. package/mcps/blender-mcp-server/scripts/library/save_blend.py +0 -40
  100. package/mcps/blender-mcp-server/scripts/server_start.sh +0 -26
  101. package/mcps/blender-mcp-server/src/blender_mcp_server/__init__.py +0 -3
  102. package/mcps/blender-mcp-server/src/blender_mcp_server/headless.py +0 -330
  103. package/mcps/blender-mcp-server/src/blender_mcp_server/server.py +0 -606
  104. package/mcps/davinci-mcp-professional/.bandit +0 -35
  105. package/mcps/davinci-mcp-professional/.claude/commands/security-review.md +0 -191
  106. package/mcps/davinci-mcp-professional/.claude/settings.json +0 -1
  107. package/mcps/davinci-mcp-professional/.editorconfig +0 -27
  108. package/mcps/davinci-mcp-professional/.gitattributes +0 -207
  109. package/mcps/davinci-mcp-professional/.github/CODEOWNERS +0 -2
  110. package/mcps/davinci-mcp-professional/.github/ISSUE_TEMPLATE/bug_report.md +0 -33
  111. package/mcps/davinci-mcp-professional/.github/ISSUE_TEMPLATE/feature_request.md +0 -19
  112. package/mcps/davinci-mcp-professional/.github/PULL_REQUEST_TEMPLATE.md +0 -20
  113. package/mcps/davinci-mcp-professional/.github/SECURITY.md +0 -97
  114. package/mcps/davinci-mcp-professional/.github/dependabot.yml +0 -27
  115. package/mcps/davinci-mcp-professional/.github/workflows/ci.yml +0 -39
  116. package/mcps/davinci-mcp-professional/ATTRIBUTION.md +0 -4
  117. package/mcps/davinci-mcp-professional/AUTHORS.md +0 -9
  118. package/mcps/davinci-mcp-professional/BUGS.md +0 -55
  119. package/mcps/davinci-mcp-professional/CLAUDE.md +0 -229
  120. package/mcps/davinci-mcp-professional/CONTRIBUTING.md +0 -51
  121. package/mcps/davinci-mcp-professional/COPYING.md +0 -228
  122. package/mcps/davinci-mcp-professional/Doxyfile +0 -379
  123. package/mcps/davinci-mcp-professional/README.md +0 -143
  124. package/mcps/davinci-mcp-professional/SECURITY.md +0 -40
  125. package/mcps/davinci-mcp-professional/USING.md +0 -301
  126. package/mcps/davinci-mcp-professional/VERSION.md +0 -13
  127. package/mcps/davinci-mcp-professional/build.py +0 -169
  128. package/mcps/davinci-mcp-professional/claude_desktop_config_template.json +0 -11
  129. package/mcps/davinci-mcp-professional/hooks/ci-check.sh +0 -29
  130. package/mcps/davinci-mcp-professional/hooks/pre-push +0 -46
  131. package/mcps/davinci-mcp-professional/main.py +0 -40
  132. package/mcps/davinci-mcp-professional/mcp_server.py +0 -30
  133. package/mcps/davinci-mcp-professional/pyproject.toml +0 -115
  134. package/mcps/davinci-mcp-professional/security_audit.py +0 -379
  135. package/mcps/davinci-mcp-professional/src/davinci_mcp/__init__.py +0 -19
  136. package/mcps/davinci-mcp-professional/src/davinci_mcp/cli.py +0 -138
  137. package/mcps/davinci-mcp-professional/src/davinci_mcp/resolve_client.py +0 -342
  138. package/mcps/davinci-mcp-professional/src/davinci_mcp/resources/__init__.py +0 -60
  139. package/mcps/davinci-mcp-professional/src/davinci_mcp/server.py +0 -185
  140. package/mcps/davinci-mcp-professional/src/davinci_mcp/tools/__init__.py +0 -146
  141. package/mcps/davinci-mcp-professional/src/davinci_mcp/types.py +0 -125
  142. package/mcps/davinci-mcp-professional/src/davinci_mcp/utils/__init__.py +0 -19
  143. package/mcps/davinci-mcp-professional/src/davinci_mcp/utils/platform.py +0 -239
  144. package/mcps/davinci-mcp-professional/test.py +0 -186
  145. package/mcps/davinci-mcp-professional/uv.lock +0 -2073
  146. package/mcps/davinci-resolve-mcp/.claude/skills/media-analysis.md +0 -44
  147. package/mcps/davinci-resolve-mcp/.clinerules +0 -17
  148. package/mcps/davinci-resolve-mcp/.cursorrules +0 -17
  149. package/mcps/davinci-resolve-mcp/.github/copilot-instructions.md +0 -17
  150. package/mcps/davinci-resolve-mcp/.github/workflows/npm-publish.yml +0 -109
  151. package/mcps/davinci-resolve-mcp/.windsurfrules +0 -17
  152. package/mcps/davinci-resolve-mcp/AGENTS.md +0 -114
  153. package/mcps/davinci-resolve-mcp/CHANGELOG.md +0 -2648
  154. package/mcps/davinci-resolve-mcp/CLAUDE.md +0 -15
  155. package/mcps/davinci-resolve-mcp/LICENSE +0 -21
  156. package/mcps/davinci-resolve-mcp/README.md +0 -173
  157. package/mcps/davinci-resolve-mcp/SECURITY.md +0 -53
  158. package/mcps/davinci-resolve-mcp/bin/davinci-resolve-mcp.mjs +0 -450
  159. package/mcps/davinci-resolve-mcp/examples/README.md +0 -53
  160. package/mcps/davinci-resolve-mcp/examples/markers/README.md +0 -81
  161. package/mcps/davinci-resolve-mcp/examples/media/README.md +0 -94
  162. package/mcps/davinci-resolve-mcp/examples/timeline/README.md +0 -98
  163. package/mcps/davinci-resolve-mcp/install.py +0 -1687
  164. package/mcps/davinci-resolve-mcp/package.json +0 -52
  165. package/mcps/davinci-resolve-mcp/release-notes/v2.22.0.md +0 -51
  166. package/mcps/davinci-resolve-mcp/release-notes/v2.23.0.md +0 -51
  167. package/mcps/davinci-resolve-mcp/release-notes/v2.23.1.md +0 -35
  168. package/mcps/davinci-resolve-mcp/release-notes/v2.24.1.md +0 -32
  169. package/mcps/davinci-resolve-mcp/scripts/audit_api_parity.py +0 -275
  170. package/mcps/davinci-resolve-mcp/scripts/audit_readwrite_symmetry.py +0 -80
  171. package/mcps/davinci-resolve-mcp/scripts/doctor.py +0 -227
  172. package/mcps/davinci-resolve-mcp/scripts/gen_api_limitations.py +0 -144
  173. package/mcps/davinci-resolve-mcp/scripts/live_media_analysis_polish_probe.py +0 -65
  174. package/mcps/davinci-resolve-mcp/scripts/measure_bridge_cost.py +0 -65
  175. package/mcps/davinci-resolve-mcp/scripts/regen_panel_screenshots.py +0 -76
  176. package/mcps/davinci-resolve-mcp/src/__init__.py +0 -3
  177. package/mcps/davinci-resolve-mcp/src/analysis_dashboard.py +0 -15505
  178. package/mcps/davinci-resolve-mcp/src/batch_cli.py +0 -540
  179. package/mcps/davinci-resolve-mcp/src/control_panel.py +0 -13
  180. package/mcps/davinci-resolve-mcp/src/granular/__init__.py +0 -17
  181. package/mcps/davinci-resolve-mcp/src/granular/common.py +0 -741
  182. package/mcps/davinci-resolve-mcp/src/granular/folder.py +0 -420
  183. package/mcps/davinci-resolve-mcp/src/granular/gallery.py +0 -306
  184. package/mcps/davinci-resolve-mcp/src/granular/graph.py +0 -309
  185. package/mcps/davinci-resolve-mcp/src/granular/media_pool.py +0 -679
  186. package/mcps/davinci-resolve-mcp/src/granular/media_pool_item.py +0 -1020
  187. package/mcps/davinci-resolve-mcp/src/granular/media_storage.py +0 -179
  188. package/mcps/davinci-resolve-mcp/src/granular/project.py +0 -1654
  189. package/mcps/davinci-resolve-mcp/src/granular/resolve_control.py +0 -538
  190. package/mcps/davinci-resolve-mcp/src/granular/timeline.py +0 -1075
  191. package/mcps/davinci-resolve-mcp/src/granular/timeline_item.py +0 -2251
  192. package/mcps/davinci-resolve-mcp/src/resolve_mcp_server.py +0 -43
  193. package/mcps/davinci-resolve-mcp/src/server.py +0 -24116
  194. package/mcps/davinci-resolve-mcp/src/utils/__init__.py +0 -3
  195. package/mcps/davinci-resolve-mcp/src/utils/actor_identity.py +0 -46
  196. package/mcps/davinci-resolve-mcp/src/utils/analysis_caps.py +0 -678
  197. package/mcps/davinci-resolve-mcp/src/utils/analysis_memory.py +0 -755
  198. package/mcps/davinci-resolve-mcp/src/utils/analysis_runs.py +0 -307
  199. package/mcps/davinci-resolve-mcp/src/utils/analysis_store.py +0 -945
  200. package/mcps/davinci-resolve-mcp/src/utils/api_truth.py +0 -525
  201. package/mcps/davinci-resolve-mcp/src/utils/app_control.py +0 -319
  202. package/mcps/davinci-resolve-mcp/src/utils/audio_fairlight_live_probe.py +0 -263
  203. package/mcps/davinci-resolve-mcp/src/utils/brain_edits.py +0 -387
  204. package/mcps/davinci-resolve-mcp/src/utils/bridge_metrics.py +0 -76
  205. package/mcps/davinci-resolve-mcp/src/utils/cdl.py +0 -20
  206. package/mcps/davinci-resolve-mcp/src/utils/clip_query.py +0 -85
  207. package/mcps/davinci-resolve-mcp/src/utils/cloud_operations.py +0 -192
  208. package/mcps/davinci-resolve-mcp/src/utils/color_grade_live_probe.py +0 -444
  209. package/mcps/davinci-resolve-mcp/src/utils/contracts.py +0 -102
  210. package/mcps/davinci-resolve-mcp/src/utils/cut_ir.py +0 -115
  211. package/mcps/davinci-resolve-mcp/src/utils/dctl_templates.py +0 -368
  212. package/mcps/davinci-resolve-mcp/src/utils/deep_vision.py +0 -643
  213. package/mcps/davinci-resolve-mcp/src/utils/destructive_hook.py +0 -606
  214. package/mcps/davinci-resolve-mcp/src/utils/edit_engine.py +0 -737
  215. package/mcps/davinci-resolve-mcp/src/utils/embeddings.py +0 -922
  216. package/mcps/davinci-resolve-mcp/src/utils/entities.py +0 -579
  217. package/mcps/davinci-resolve-mcp/src/utils/extension_authoring_live_probe.py +0 -292
  218. package/mcps/davinci-resolve-mcp/src/utils/failure_tracker.py +0 -119
  219. package/mcps/davinci-resolve-mcp/src/utils/fuse_templates.py +0 -1968
  220. package/mcps/davinci-resolve-mcp/src/utils/fusion_composition_live_probe.py +0 -284
  221. package/mcps/davinci-resolve-mcp/src/utils/fusion_group_settings.py +0 -334
  222. package/mcps/davinci-resolve-mcp/src/utils/layout_presets.py +0 -333
  223. package/mcps/davinci-resolve-mcp/src/utils/mcp_stdio.py +0 -32
  224. package/mcps/davinci-resolve-mcp/src/utils/mcp_transport.py +0 -128
  225. package/mcps/davinci-resolve-mcp/src/utils/media_analysis.py +0 -7690
  226. package/mcps/davinci-resolve-mcp/src/utils/media_analysis_jobs.py +0 -805
  227. package/mcps/davinci-resolve-mcp/src/utils/media_pool_changes.py +0 -121
  228. package/mcps/davinci-resolve-mcp/src/utils/media_pool_ingest_live_probe.py +0 -592
  229. package/mcps/davinci-resolve-mcp/src/utils/multicam.py +0 -393
  230. package/mcps/davinci-resolve-mcp/src/utils/object_inspection.py +0 -301
  231. package/mcps/davinci-resolve-mcp/src/utils/page_lock.py +0 -75
  232. package/mcps/davinci-resolve-mcp/src/utils/platform.py +0 -157
  233. package/mcps/davinci-resolve-mcp/src/utils/proc.py +0 -26
  234. package/mcps/davinci-resolve-mcp/src/utils/project_cleanup.py +0 -73
  235. package/mcps/davinci-resolve-mcp/src/utils/project_lifecycle_live_probe.py +0 -376
  236. package/mcps/davinci-resolve-mcp/src/utils/project_lint.py +0 -131
  237. package/mcps/davinci-resolve-mcp/src/utils/project_properties.py +0 -601
  238. package/mcps/davinci-resolve-mcp/src/utils/project_spec.py +0 -459
  239. package/mcps/davinci-resolve-mcp/src/utils/readback.py +0 -91
  240. package/mcps/davinci-resolve-mcp/src/utils/render_deliver_live_probe.py +0 -384
  241. package/mcps/davinci-resolve-mcp/src/utils/resolve_ai_governance.py +0 -214
  242. package/mcps/davinci-resolve-mcp/src/utils/resolve_ai_ledger.py +0 -244
  243. package/mcps/davinci-resolve-mcp/src/utils/resolve_busy.py +0 -171
  244. package/mcps/davinci-resolve-mcp/src/utils/resolve_connection.py +0 -77
  245. package/mcps/davinci-resolve-mcp/src/utils/review_annotation_live_probe.py +0 -352
  246. package/mcps/davinci-resolve-mcp/src/utils/script_templates.py +0 -1193
  247. package/mcps/davinci-resolve-mcp/src/utils/shot_relationships.py +0 -544
  248. package/mcps/davinci-resolve-mcp/src/utils/structural_diff.py +0 -175
  249. package/mcps/davinci-resolve-mcp/src/utils/sync_detection.py +0 -889
  250. package/mcps/davinci-resolve-mcp/src/utils/timeline_brain_db.py +0 -826
  251. package/mcps/davinci-resolve-mcp/src/utils/timeline_conform_live_probe.py +0 -280
  252. package/mcps/davinci-resolve-mcp/src/utils/timeline_kernel_live_probe.py +0 -1092
  253. package/mcps/davinci-resolve-mcp/src/utils/timeline_kernel_probe.py +0 -185
  254. package/mcps/davinci-resolve-mcp/src/utils/timeline_title_text.py +0 -87
  255. package/mcps/davinci-resolve-mcp/src/utils/timeline_versioning.py +0 -730
  256. package/mcps/davinci-resolve-mcp/src/utils/update_check.py +0 -685
  257. package/mcps/vectorworks-mcp/.dockerignore +0 -8
  258. package/mcps/vectorworks-mcp/Dockerfile +0 -28
  259. package/mcps/vectorworks-mcp/README.md +0 -156
  260. package/mcps/vectorworks-mcp/app/__init__.py +0 -2
  261. package/mcps/vectorworks-mcp/app/api.py +0 -52
  262. package/mcps/vectorworks-mcp/app/chunking.py +0 -56
  263. package/mcps/vectorworks-mcp/app/config.py +0 -29
  264. package/mcps/vectorworks-mcp/app/embeddings.py +0 -28
  265. package/mcps/vectorworks-mcp/app/indexer.py +0 -106
  266. package/mcps/vectorworks-mcp/app/main.py +0 -33
  267. package/mcps/vectorworks-mcp/app/mcp_server.py +0 -71
  268. package/mcps/vectorworks-mcp/app/search.py +0 -54
  269. package/mcps/vectorworks-mcp/app/utils.py +0 -14
  270. package/mcps/vectorworks-mcp/data/.gitkeep +0 -1
  271. package/mcps/vectorworks-mcp/data/vw-app-help/VW2022_PluginScript.htm +0 -95
  272. package/mcps/vectorworks-mcp/data/vw-app-help/VW2022_ScriptEditor.htm +0 -266
  273. package/mcps/vectorworks-mcp/data/vw-app-help/VW2022_Scripting.htm +0 -106
  274. package/mcps/vectorworks-mcp/data/vw-app-help/VW2023_CreatingScriptedPlugins.htm +0 -327
  275. package/mcps/vectorworks-mcp/data/vw-app-help/VW2024_RunningScripts.htm +0 -116
  276. package/mcps/vectorworks-mcp/data/vw-devwiki/VS_Function_Reference_category.html +0 -2129
  277. package/mcps/vectorworks-mcp/data/vw-jp-ref/ObjectsSymbols.html +0 -2035
  278. package/mcps/vectorworks-mcp/data/vw-jp-ref/ScriptFunctionReference.html +0 -29
  279. package/mcps/vectorworks-mcp/design.md +0 -57
  280. package/mcps/vectorworks-mcp/docker-compose.yml +0 -18
  281. package/mcps/vectorworks-mcp/index/.gitkeep +0 -1
  282. package/mcps/vectorworks-mcp/index/meta.jsonl +0 -3956
  283. package/mcps/vectorworks-mcp/index/vw.faiss +0 -0
  284. package/mcps/vectorworks-mcp/requirements.txt +0 -10
  285. package/mcps/vectorworks-mcp/scripts/fetch_docs_minimal.sh +0 -84
  286. package/mcps/vectorworks-mcp/scripts/fetch_github_vectorworks.sh +0 -85
  287. package/mcps/vectorworks-mcp/templates/index.html +0 -40
  288. package/scripts/ecosystem-health-audit.js +0 -257
  289. package/skills/bdb-dev-os-skill/SKILL.md +0 -49
  290. package/skills/bdb-dev-os-skill/package.json +0 -11
  291. package/skills/bdbsaastraining/SKILL.md +0 -316
  292. package/skills/bdbsaastraining/references/exam-pool.md +0 -313
  293. package/skills/bdbsaastraining/references/interaction-modes.md +0 -94
  294. package/skills/bdbsaastraining/references/track-a-ai-agent.md +0 -111
  295. package/skills/bdbsaastraining/references/track-b-wordpress.md +0 -111
  296. package/skills/bdbsaastraining/references/track-c-mailserver.md +0 -107
  297. package/skills/bdbsaastraining/references/track-d-debian.md +0 -109
  298. package/skills/bdbsaastraining/references/track-e-custom.md +0 -83
  299. package/skills/bdbsaastraining/scripts/build_profile.py +0 -529
  300. package/skills/bdbsaastraining/scripts/generate_certificate.py +0 -161
  301. package/skills/bdbsaastraining/scripts/preflight_check.sh +0 -150
  302. package/skills/bdbsaastraining/templates/certificate_template.html +0 -508
  303. package/skills/global_config/bdb-ecosystem-health/SKILL.md +0 -68
  304. package/skills/global_config/bdbsaas-ops/SKILL.md +0 -16
  305. package/skills/global_config/bdbsaashost/SKILL.md +0 -125
@@ -1,1075 +0,0 @@
1
- """Timeline resources and operations."""
2
-
3
- from src.granular.common import * # noqa: F401,F403
4
-
5
- resolve = ResolveProxy()
6
-
7
- @mcp.resource("resolve://timelines")
8
- def list_timelines() -> List[str]:
9
- """List all timelines in the current project."""
10
- logger.info("Received request to list timelines")
11
-
12
- if resolve is None:
13
- logger.error("Not connected to DaVinci Resolve")
14
- return ["Error: Not connected to DaVinci Resolve"]
15
-
16
- project_manager = resolve.GetProjectManager()
17
- if not project_manager:
18
- logger.error("Failed to get Project Manager")
19
- return ["Error: Failed to get Project Manager"]
20
-
21
- current_project = project_manager.GetCurrentProject()
22
- if not current_project:
23
- logger.error("No project currently open")
24
- return ["Error: No project currently open"]
25
-
26
- timeline_count = current_project.GetTimelineCount()
27
- logger.info(f"Timeline count: {timeline_count}")
28
-
29
- timelines = []
30
-
31
- for i in range(1, timeline_count + 1):
32
- timeline = current_project.GetTimelineByIndex(i)
33
- if timeline:
34
- timeline_name = timeline.GetName()
35
- timelines.append(timeline_name)
36
- logger.info(f"Found timeline {i}: {timeline_name}")
37
-
38
- if not timelines:
39
- logger.info("No timelines found in the current project")
40
- return ["No timelines found in the current project"]
41
-
42
- logger.info(f"Returning {len(timelines)} timelines: {', '.join(timelines)}")
43
- return timelines
44
-
45
-
46
- @mcp.resource("resolve://current-timeline")
47
- def get_current_timeline() -> Dict[str, Any]:
48
- """Get information about the current timeline."""
49
- pm, current_project = get_current_project()
50
- if not current_project:
51
- return {"error": "No project currently open"}
52
-
53
- current_timeline = current_project.GetCurrentTimeline()
54
- if not current_timeline:
55
- return {"error": "No timeline currently active"}
56
-
57
- # Get basic timeline information
58
- result = {
59
- "name": current_timeline.GetName(),
60
- "fps": current_timeline.GetSetting("timelineFrameRate"),
61
- "resolution": {
62
- "width": current_timeline.GetSetting("timelineResolutionWidth"),
63
- "height": current_timeline.GetSetting("timelineResolutionHeight")
64
- },
65
- "duration": current_timeline.GetEndFrame() - current_timeline.GetStartFrame() + 1
66
- }
67
-
68
- return result
69
-
70
-
71
- @mcp.tool()
72
- def create_timeline(name: str) -> str:
73
- """Create a new timeline with the given name.
74
-
75
- Args:
76
- name: The name for the new timeline
77
- """
78
- resolve = get_resolve()
79
- if resolve is None:
80
- return "Error: Not connected to DaVinci Resolve"
81
-
82
- if not name:
83
- return "Error: Timeline name cannot be empty"
84
-
85
- project_manager = resolve.GetProjectManager()
86
- if not project_manager:
87
- return "Error: Failed to get Project Manager"
88
-
89
- current_project = project_manager.GetCurrentProject()
90
- if not current_project:
91
- return "Error: No project currently open"
92
-
93
- media_pool = current_project.GetMediaPool()
94
- if not media_pool:
95
- return "Error: Failed to get Media Pool"
96
-
97
- timeline = media_pool.CreateEmptyTimeline(name)
98
- if timeline:
99
- return f"Successfully created timeline '{name}'"
100
- else:
101
- return f"Failed to create timeline '{name}'"
102
-
103
-
104
- @mcp.tool()
105
- def set_current_timeline(name: str) -> str:
106
- """Switch to a timeline by name.
107
-
108
- Args:
109
- name: The name of the timeline to set as current
110
- """
111
- resolve = get_resolve()
112
- if resolve is None:
113
- return "Error: Not connected to DaVinci Resolve"
114
-
115
- if not name:
116
- return "Error: Timeline name cannot be empty"
117
-
118
- project_manager = resolve.GetProjectManager()
119
- if not project_manager:
120
- return "Error: Failed to get Project Manager"
121
-
122
- current_project = project_manager.GetCurrentProject()
123
- if not current_project:
124
- return "Error: No project currently open"
125
-
126
- # Find the timeline by name
127
- timeline_count = current_project.GetTimelineCount()
128
- for i in range(1, timeline_count + 1):
129
- timeline = current_project.GetTimelineByIndex(i)
130
- if timeline and timeline.GetName() == name:
131
- result = current_project.SetCurrentTimeline(timeline)
132
- if result:
133
- return f"Successfully switched to timeline '{name}'"
134
- else:
135
- return f"Failed to switch to timeline '{name}'"
136
-
137
- return f"Error: Timeline '{name}' not found"
138
-
139
-
140
- @mcp.resource("resolve://timeline-clips")
141
- def list_timeline_clips() -> List[Dict[str, Any]]:
142
- """List all clips in the current timeline."""
143
- pm, current_project = get_current_project()
144
- if not current_project:
145
- return [{"error": "No project currently open"}]
146
-
147
- current_timeline = current_project.GetCurrentTimeline()
148
- if not current_timeline:
149
- return [{"error": "No timeline currently active"}]
150
-
151
- try:
152
- # Get all tracks in the timeline
153
- # Video tracks are 1-based index (1 is first track)
154
- video_track_count = current_timeline.GetTrackCount("video")
155
- audio_track_count = current_timeline.GetTrackCount("audio")
156
-
157
- clips = []
158
-
159
- # Process video tracks
160
- for track_index in range(1, video_track_count + 1):
161
- track_items = current_timeline.GetItemListInTrack("video", track_index)
162
- if track_items:
163
- for item in track_items:
164
- clips.append({
165
- "name": item.GetName(),
166
- "type": "video",
167
- "track": track_index,
168
- "start_frame": item.GetStart(),
169
- "end_frame": item.GetEnd(),
170
- "duration": item.GetDuration()
171
- })
172
-
173
- # Process audio tracks
174
- for track_index in range(1, audio_track_count + 1):
175
- track_items = current_timeline.GetItemListInTrack("audio", track_index)
176
- if track_items:
177
- for item in track_items:
178
- clips.append({
179
- "name": item.GetName(),
180
- "type": "audio",
181
- "track": track_index,
182
- "start_frame": item.GetStart(),
183
- "end_frame": item.GetEnd(),
184
- "duration": item.GetDuration()
185
- })
186
-
187
- if not clips:
188
- return [{"info": "No clips found in the current timeline"}]
189
-
190
- return clips
191
- except Exception as e:
192
- return [{"error": f"Error listing timeline clips: {str(e)}"}]
193
-
194
-
195
- @mcp.tool()
196
- def list_timelines_tool() -> List[str]:
197
- """List all timelines in the current project as a tool."""
198
- logger.info("Received request to list timelines via tool")
199
- return list_timelines()
200
-
201
-
202
- @mcp.tool()
203
- def timeline_set_name(name: str) -> Dict[str, Any]:
204
- """Rename the current timeline.
205
-
206
- Args:
207
- name: New name for the timeline.
208
- """
209
- _, tl, err = _get_timeline()
210
- if err:
211
- return err
212
- result = tl.SetName(name)
213
- return {"success": bool(result), "name": name}
214
-
215
-
216
- @mcp.tool()
217
- def timeline_set_start_timecode(timecode: str) -> Dict[str, Any]:
218
- """Set the start timecode of the current timeline.
219
-
220
- Args:
221
- timecode: Timecode string (e.g. '01:00:00:00').
222
- """
223
- _, tl, err = _get_timeline()
224
- if err:
225
- return err
226
- result = tl.SetStartTimecode(timecode)
227
- return {"success": bool(result), "timecode": timecode}
228
-
229
-
230
- @mcp.tool()
231
- def timeline_get_current_timecode() -> Dict[str, Any]:
232
- """Get the current playhead timecode."""
233
- _, tl, err = _get_timeline()
234
- if err:
235
- return err
236
- return {"timecode": tl.GetCurrentTimecode()}
237
-
238
-
239
- @mcp.tool()
240
- def timeline_set_current_timecode(timecode: str) -> Dict[str, Any]:
241
- """Set the playhead to a specific timecode.
242
-
243
- Args:
244
- timecode: Timecode string (e.g. '01:00:05:00').
245
- """
246
- _, tl, err = _get_timeline()
247
- if err:
248
- return err
249
- result = tl.SetCurrentTimecode(timecode)
250
- return {"success": bool(result), "timecode": timecode}
251
-
252
-
253
- @mcp.tool()
254
- def timeline_add_track(
255
- track_type: str,
256
- audio_type: Optional[str] = None,
257
- index: Optional[int] = None,
258
- ) -> Dict[str, Any]:
259
- """Add a new track to the timeline.
260
-
261
- Mirrors Timeline.AddTrack(trackType, {newTrackOptions}) per docs line 327.
262
-
263
- Args:
264
- track_type: 'video', 'audio', or 'subtitle'.
265
- audio_type: For audio tracks: 'mono', 'stereo', 'lrc', 'lcr', 'lrcs', 'lcrs',
266
- 'quad', '5.0', '5.0film', '5.1', '5.1film', '7.0', '7.0film', '7.1',
267
- '7.1film', 'adaptive1' through 'adaptive36'. Defaults to 'mono' for audio
268
- tracks if omitted.
269
- index: 1-based track index where 1 <= index <= GetTrackCount(track_type) + 1.
270
- If omitted or out of bounds, the track is appended.
271
- """
272
- _, tl, err = _get_timeline()
273
- if err:
274
- return err
275
- options: Dict[str, Any] = {}
276
- if audio_type is not None:
277
- options["audioType"] = audio_type
278
- if index is not None:
279
- options["index"] = index
280
- if options:
281
- result = tl.AddTrack(track_type, options)
282
- else:
283
- result = tl.AddTrack(track_type)
284
- return {"success": bool(result), "track_type": track_type}
285
-
286
-
287
- @mcp.tool()
288
- def timeline_delete_track(track_type: str, track_index: int) -> Dict[str, Any]:
289
- """Delete a track from the timeline.
290
-
291
- Args:
292
- track_type: 'video', 'audio', or 'subtitle'.
293
- track_index: 1-based track index to delete.
294
- """
295
- _, tl, err = _get_timeline()
296
- if err:
297
- return err
298
- result = tl.DeleteTrack(track_type, track_index)
299
- return {"success": bool(result)}
300
-
301
-
302
- @mcp.tool()
303
- def timeline_get_track_sub_type(track_type: str, track_index: int) -> Dict[str, Any]:
304
- """Get the sub-type of a track (e.g. mono, stereo for audio).
305
-
306
- Args:
307
- track_type: 'video' or 'audio'.
308
- track_index: 1-based track index.
309
- """
310
- _, tl, err = _get_timeline()
311
- if err:
312
- return err
313
- sub = tl.GetTrackSubType(track_type, track_index)
314
- return {"track_type": track_type, "track_index": track_index, "sub_type": sub if sub else ""}
315
-
316
-
317
- @mcp.tool()
318
- def timeline_set_track_enable(track_type: str, track_index: int, enabled: bool) -> Dict[str, Any]:
319
- """Enable or disable a track.
320
-
321
- Args:
322
- track_type: 'video' or 'audio'.
323
- track_index: 1-based track index.
324
- enabled: True to enable, False to disable.
325
- """
326
- _, tl, err = _get_timeline()
327
- if err:
328
- return err
329
- result = tl.SetTrackEnable(track_type, track_index, enabled)
330
- return {"success": bool(result)}
331
-
332
-
333
- @mcp.tool()
334
- def timeline_get_is_track_enabled(track_type: str, track_index: int) -> Dict[str, Any]:
335
- """Check if a track is enabled.
336
-
337
- Args:
338
- track_type: 'video' or 'audio'.
339
- track_index: 1-based track index.
340
- """
341
- _, tl, err = _get_timeline()
342
- if err:
343
- return err
344
- enabled = tl.GetIsTrackEnabled(track_type, track_index)
345
- return {"enabled": bool(enabled)}
346
-
347
-
348
- @mcp.tool()
349
- def timeline_set_track_lock(track_type: str, track_index: int, locked: bool) -> Dict[str, Any]:
350
- """Lock or unlock a track.
351
-
352
- Args:
353
- track_type: 'video' or 'audio'.
354
- track_index: 1-based track index.
355
- locked: True to lock, False to unlock.
356
- """
357
- _, tl, err = _get_timeline()
358
- if err:
359
- return err
360
- result = tl.SetTrackLock(track_type, track_index, locked)
361
- return {"success": bool(result)}
362
-
363
-
364
- @mcp.tool()
365
- def timeline_get_is_track_locked(track_type: str, track_index: int) -> Dict[str, Any]:
366
- """Check if a track is locked.
367
-
368
- Args:
369
- track_type: 'video' or 'audio'.
370
- track_index: 1-based track index.
371
- """
372
- _, tl, err = _get_timeline()
373
- if err:
374
- return err
375
- locked = tl.GetIsTrackLocked(track_type, track_index)
376
- return {"locked": bool(locked)}
377
-
378
-
379
- @mcp.tool()
380
- def timeline_get_voice_isolation_state(track_index: int) -> Dict[str, Any]:
381
- """Get voice isolation state for an audio track.
382
-
383
- Args:
384
- track_index: 1-based audio track index.
385
- """
386
- _, tl, err = _get_timeline()
387
- if err:
388
- return err
389
- missing = _requires_method(tl, "GetVoiceIsolationState", "20.1")
390
- if missing:
391
- return missing
392
- state = tl.GetVoiceIsolationState(track_index)
393
- return {"state": state if state else {"isEnabled": False, "amount": 0}}
394
-
395
-
396
- @mcp.tool()
397
- def timeline_set_voice_isolation_state(track_index: int, state: Dict[str, Any]) -> Dict[str, Any]:
398
- """Set voice isolation state for an audio track.
399
-
400
- Args:
401
- track_index: 1-based audio track index.
402
- state: Dict with isEnabled (bool) and amount (0-100).
403
- """
404
- _, tl, err = _get_timeline()
405
- if err:
406
- return err
407
- missing = _requires_method(tl, "SetVoiceIsolationState", "20.1")
408
- if missing:
409
- return missing
410
- result = tl.SetVoiceIsolationState(track_index, state)
411
- return {"success": bool(result)}
412
-
413
-
414
- @mcp.tool()
415
- def timeline_delete_clips(clip_ids: List[str], track_type: str = "video", track_index: int = 1) -> Dict[str, Any]:
416
- """Delete clips from the timeline.
417
-
418
- Args:
419
- clip_ids: List of clip unique IDs to delete.
420
- track_type: 'video' or 'audio'. Default: 'video'.
421
- track_index: 1-based track index. Default: 1.
422
- """
423
- _, tl, err = _get_timeline()
424
- if err:
425
- return err
426
- items = tl.GetItemListInTrack(track_type, track_index)
427
- if not items:
428
- return {"error": "No items in track"}
429
- to_delete = [i for i in items if i.GetUniqueId() in clip_ids]
430
- if not to_delete:
431
- return {"error": "No matching clips found"}
432
- result = tl.DeleteClips(to_delete)
433
- return {"success": bool(result), "deleted": len(to_delete)}
434
-
435
-
436
- @mcp.tool()
437
- def timeline_set_clips_linked(clip_ids: List[str], linked: bool, track_type: str = "video", track_index: int = 1) -> Dict[str, Any]:
438
- """Link or unlink clips in the timeline.
439
-
440
- Args:
441
- clip_ids: List of clip unique IDs.
442
- linked: True to link, False to unlink.
443
- track_type: 'video' or 'audio'. Default: 'video'.
444
- track_index: 1-based track index. Default: 1.
445
- """
446
- _, tl, err = _get_timeline()
447
- if err:
448
- return err
449
- items = tl.GetItemListInTrack(track_type, track_index)
450
- if not items:
451
- return {"error": "No items in track"}
452
- targets = [i for i in items if i.GetUniqueId() in clip_ids]
453
- if not targets:
454
- return {"error": "No matching clips found"}
455
- result = tl.SetClipsLinked(targets, linked)
456
- return {"success": bool(result)}
457
-
458
-
459
- @mcp.tool()
460
- def timeline_add_marker(frame_id: int, color: str, name: str, note: str = "", duration: int = 1, custom_data: str = "") -> Dict[str, Any]:
461
- """Add a marker to the current timeline.
462
-
463
- Args:
464
- frame_id: Frame number for the marker, relative to the timeline start
465
- (frame 0 = first frame, even when the timeline starts at 01:00:00:00).
466
- color: Marker color (Blue, Cyan, Green, Yellow, Red, Pink, Purple, Fuchsia, Rose, Lavender, Sky, Mint, Lemon, Sand, Cocoa, Cream).
467
- name: Marker name.
468
- note: Marker note. Default: empty.
469
- duration: Duration in frames. Default: 1.
470
- custom_data: Custom data string. Default: empty.
471
- """
472
- _, tl, err = _get_timeline()
473
- if err:
474
- return err
475
- result = tl.AddMarker(frame_id, color, name, note, duration, custom_data)
476
- return {"success": bool(result)}
477
-
478
-
479
- @mcp.tool()
480
- def timeline_get_markers() -> Dict[str, Any]:
481
- """Get all markers on the current timeline."""
482
- _, tl, err = _get_timeline()
483
- if err:
484
- return err
485
- markers = tl.GetMarkers()
486
- return {"markers": markers if markers else {}}
487
-
488
-
489
- @mcp.tool()
490
- def timeline_get_marker_by_custom_data(custom_data: str) -> Dict[str, Any]:
491
- """Find a timeline marker by its custom data.
492
-
493
- Args:
494
- custom_data: Custom data string to search for.
495
- """
496
- _, tl, err = _get_timeline()
497
- if err:
498
- return err
499
- marker = tl.GetMarkerByCustomData(custom_data)
500
- return {"marker": marker if marker else {}}
501
-
502
-
503
- @mcp.tool()
504
- def timeline_update_marker_custom_data(frame_id: int, custom_data: str) -> Dict[str, Any]:
505
- """Update the custom data of a timeline marker.
506
-
507
- Args:
508
- frame_id: Frame number of the marker.
509
- custom_data: New custom data string.
510
- """
511
- _, tl, err = _get_timeline()
512
- if err:
513
- return err
514
- result = tl.UpdateMarkerCustomData(frame_id, custom_data)
515
- return {"success": bool(result)}
516
-
517
-
518
- @mcp.tool()
519
- def timeline_get_marker_custom_data(frame_id: int) -> Dict[str, Any]:
520
- """Get the custom data of a timeline marker.
521
-
522
- Args:
523
- frame_id: Frame number of the marker.
524
- """
525
- _, tl, err = _get_timeline()
526
- if err:
527
- return err
528
- data = tl.GetMarkerCustomData(frame_id)
529
- return {"frame_id": frame_id, "custom_data": data if data else ""}
530
-
531
-
532
- @mcp.tool()
533
- def timeline_delete_markers_by_color(color: str) -> Dict[str, Any]:
534
- """Delete all timeline markers of a specific color.
535
-
536
- Args:
537
- color: Color of markers to delete. Use '' to delete all.
538
- """
539
- _, tl, err = _get_timeline()
540
- if err:
541
- return err
542
- result = tl.DeleteMarkersByColor(color)
543
- return {"success": bool(result)}
544
-
545
-
546
- @mcp.tool()
547
- def timeline_delete_marker_at_frame(frame_id: int) -> Dict[str, Any]:
548
- """Delete a timeline marker at a specific frame.
549
-
550
- Args:
551
- frame_id: Frame number of the marker.
552
- """
553
- _, tl, err = _get_timeline()
554
- if err:
555
- return err
556
- result = tl.DeleteMarkerAtFrame(frame_id)
557
- return {"success": bool(result)}
558
-
559
-
560
- @mcp.tool()
561
- def timeline_delete_marker_by_custom_data(custom_data: str) -> Dict[str, Any]:
562
- """Delete a timeline marker by custom data.
563
-
564
- Args:
565
- custom_data: Custom data of the marker to delete.
566
- """
567
- _, tl, err = _get_timeline()
568
- if err:
569
- return err
570
- result = tl.DeleteMarkerByCustomData(custom_data)
571
- return {"success": bool(result)}
572
-
573
-
574
- @mcp.tool()
575
- def timeline_get_track_name(track_type: str, track_index: int) -> Dict[str, Any]:
576
- """Get the name of a track.
577
-
578
- Args:
579
- track_type: 'video' or 'audio'.
580
- track_index: 1-based track index.
581
- """
582
- _, tl, err = _get_timeline()
583
- if err:
584
- return err
585
- name = tl.GetTrackName(track_type, track_index)
586
- return {"track_name": name if name else ""}
587
-
588
-
589
- @mcp.tool()
590
- def timeline_set_track_name(track_type: str, track_index: int, name: str) -> Dict[str, Any]:
591
- """Set the name of a track.
592
-
593
- Args:
594
- track_type: 'video' or 'audio'.
595
- track_index: 1-based track index.
596
- name: New track name.
597
- """
598
- _, tl, err = _get_timeline()
599
- if err:
600
- return err
601
- result = tl.SetTrackName(track_type, track_index, name)
602
- return {"success": bool(result)}
603
-
604
-
605
- @mcp.tool()
606
- def timeline_duplicate() -> Dict[str, Any]:
607
- """Duplicate the current timeline."""
608
- _, tl, err = _get_timeline()
609
- if err:
610
- return err
611
- new_tl = tl.DuplicateTimeline()
612
- if new_tl:
613
- return {"success": True, "name": new_tl.GetName(), "unique_id": new_tl.GetUniqueId()}
614
- return {"success": False, "error": "Failed to duplicate timeline"}
615
-
616
-
617
- @mcp.tool()
618
- def timeline_create_compound_clip(
619
- clip_ids: List[str],
620
- track_type: str = "video",
621
- track_index: int = 1,
622
- name: Optional[str] = None,
623
- start_timecode: Optional[str] = None,
624
- ) -> Dict[str, Any]:
625
- """Create a compound clip from selected items.
626
-
627
- Mirrors Timeline.CreateCompoundClip([timelineItems], {clipInfo}) per docs line 369.
628
-
629
- Args:
630
- clip_ids: List of timeline item unique IDs.
631
- track_type: 'video' or 'audio'. Default: 'video'.
632
- track_index: 1-based track index. Default: 1.
633
- name: Optional name for the compound clip; maps to clipInfo.name.
634
- start_timecode: Optional start timecode (e.g. "01:00:00:00"); maps to clipInfo.startTimecode.
635
- """
636
- _, tl, err = _get_timeline()
637
- if err:
638
- return err
639
- items = tl.GetItemListInTrack(track_type, track_index)
640
- targets = [i for i in (items or []) if i.GetUniqueId() in clip_ids]
641
- if not targets:
642
- return {"error": "No matching items found"}
643
- clip_info: Dict[str, Any] = {}
644
- if name is not None:
645
- clip_info["name"] = name
646
- if start_timecode is not None:
647
- clip_info["startTimecode"] = start_timecode
648
- if clip_info:
649
- result = tl.CreateCompoundClip(targets, clip_info)
650
- else:
651
- result = tl.CreateCompoundClip(targets)
652
- if not result:
653
- return {"success": False, "error": "Failed to create compound clip"}
654
- return {
655
- "success": True,
656
- "name": result.GetName() if hasattr(result, "GetName") else None,
657
- "unique_id": result.GetUniqueId() if hasattr(result, "GetUniqueId") else None,
658
- }
659
-
660
-
661
- @mcp.tool()
662
- def timeline_create_fusion_clip(clip_ids: List[str], track_type: str = "video", track_index: int = 1) -> Dict[str, Any]:
663
- """Create a Fusion clip from selected items.
664
-
665
- Args:
666
- clip_ids: List of timeline item unique IDs.
667
- track_type: 'video' or 'audio'. Default: 'video'.
668
- track_index: 1-based track index. Default: 1.
669
- """
670
- _, tl, err = _get_timeline()
671
- if err:
672
- return err
673
- items = tl.GetItemListInTrack(track_type, track_index)
674
- targets = [i for i in (items or []) if i.GetUniqueId() in clip_ids]
675
- if not targets:
676
- return {"error": "No matching items found"}
677
- result = tl.CreateFusionClip(targets)
678
- if result:
679
- return {"success": True}
680
- return {"success": False, "error": "Failed to create Fusion clip"}
681
-
682
-
683
- @mcp.tool()
684
- def timeline_import_into(file_path: str, import_options: Optional[Dict[str, Any]] = None) -> Dict[str, Any]:
685
- """Import content into the current timeline from a file.
686
-
687
- Args:
688
- file_path: Path to the file to import (AAF, EDL, XML, etc.).
689
- import_options: Optional dict of import options.
690
- """
691
- _, tl, err = _get_timeline()
692
- if err:
693
- return err
694
- if import_options:
695
- result = tl.ImportIntoTimeline(file_path, import_options)
696
- else:
697
- result = tl.ImportIntoTimeline(file_path)
698
- return {"success": bool(result)}
699
-
700
-
701
- @mcp.tool()
702
- def timeline_export(file_path: str, export_type: str, export_subtype: str = "EXPORT_NONE") -> Dict[str, Any]:
703
- """Export the current timeline to a file.
704
-
705
- Args:
706
- file_path: Output file path.
707
- export_type: Export type (e.g. 'EXPORT_AAF', 'EXPORT_EDL', 'EXPORT_FCP_7_XML', 'EXPORT_FCPXML_1_10', 'EXPORT_DRT', 'EXPORT_TEXT_CSV', 'EXPORT_TEXT_TAB', 'EXPORT_OTIO', 'EXPORT_ALE').
708
- export_subtype: Export subtype for AAF/EDL. Default: 'EXPORT_NONE'.
709
- """
710
- _, tl, err = _get_timeline()
711
- if err:
712
- return err
713
- # Map string constants to resolve constants
714
- try:
715
- etype = getattr(resolve, export_type) if hasattr(resolve, export_type) else export_type
716
- esub = getattr(resolve, export_subtype) if hasattr(resolve, export_subtype) else export_subtype
717
- except Exception:
718
- logger.debug("Could not resolve timeline export constants", exc_info=True)
719
- etype = export_type
720
- esub = export_subtype
721
- result = tl.Export(file_path, etype, esub)
722
- return {"success": bool(result), "file_path": file_path}
723
-
724
-
725
- @mcp.tool()
726
- def timeline_insert_generator(generator_name: str, duration: Optional[int] = None) -> Dict[str, Any]:
727
- """Insert a generator into the timeline.
728
-
729
- Args:
730
- generator_name: Name of the generator to insert.
731
- duration: Optional duration in frames.
732
- """
733
- _, tl, err = _get_timeline()
734
- if err:
735
- return err
736
- if duration:
737
- result = tl.InsertGeneratorIntoTimeline(generator_name, {"duration": duration})
738
- else:
739
- result = tl.InsertGeneratorIntoTimeline(generator_name)
740
- return {"success": result is not None}
741
-
742
-
743
- @mcp.tool()
744
- def timeline_insert_fusion_generator(generator_name: str) -> Dict[str, Any]:
745
- """Insert a Fusion generator into the timeline.
746
-
747
- Args:
748
- generator_name: Name of the Fusion generator.
749
- """
750
- _, tl, err = _get_timeline()
751
- if err:
752
- return err
753
- result = tl.InsertFusionGeneratorIntoTimeline(generator_name)
754
- return {"success": result is not None}
755
-
756
-
757
- @mcp.tool()
758
- def timeline_insert_fusion_composition() -> Dict[str, Any]:
759
- """Insert a Fusion composition into the timeline."""
760
- _, tl, err = _get_timeline()
761
- if err:
762
- return err
763
- result = tl.InsertFusionCompositionIntoTimeline()
764
- return {"success": result is not None}
765
-
766
-
767
- @mcp.tool()
768
- def timeline_insert_ofx_generator(generator_name: str) -> Dict[str, Any]:
769
- """Insert an OFX generator into the timeline.
770
-
771
- Args:
772
- generator_name: Name of the OFX generator.
773
- """
774
- _, tl, err = _get_timeline()
775
- if err:
776
- return err
777
- result = tl.InsertOFXGeneratorIntoTimeline(generator_name)
778
- return {"success": result is not None}
779
-
780
-
781
- @mcp.tool()
782
- def timeline_insert_title(title_name: str) -> Dict[str, Any]:
783
- """Insert a title into the timeline.
784
-
785
- Args:
786
- title_name: Name of the title to insert.
787
- """
788
- _, tl, err = _get_timeline()
789
- if err:
790
- return err
791
- result = tl.InsertTitleIntoTimeline(title_name)
792
- return {"success": result is not None}
793
-
794
-
795
- @mcp.tool()
796
- def timeline_insert_fusion_title(title_name: str) -> Dict[str, Any]:
797
- """Insert a Fusion title into the timeline.
798
-
799
- Args:
800
- title_name: Name of the Fusion title.
801
- """
802
- _, tl, err = _get_timeline()
803
- if err:
804
- return err
805
- result = tl.InsertFusionTitleIntoTimeline(title_name)
806
- return {"success": result is not None}
807
-
808
-
809
- @mcp.tool()
810
- def timeline_grab_still() -> Dict[str, Any]:
811
- """Grab a still from the current frame of the timeline."""
812
- _, tl, err = _get_timeline()
813
- if err:
814
- return err
815
- result = tl.GrabStill()
816
- return {"success": result is not None}
817
-
818
-
819
- @mcp.tool()
820
- def timeline_grab_all_stills() -> Dict[str, Any]:
821
- """Grab stills from all frames at the current position across all timelines."""
822
- _, tl, err = _get_timeline()
823
- if err:
824
- return err
825
- result = tl.GrabAllStills()
826
- return {"success": result is not None}
827
-
828
-
829
- @mcp.tool()
830
- def timeline_get_unique_id() -> Dict[str, Any]:
831
- """Get the unique ID of the current timeline."""
832
- _, tl, err = _get_timeline()
833
- if err:
834
- return err
835
- return {"unique_id": tl.GetUniqueId()}
836
-
837
-
838
- @mcp.tool()
839
- def timeline_create_subtitles_from_audio(
840
- language: str = "auto",
841
- preset: str = "default",
842
- chars_per_line: Optional[int] = None,
843
- line_break: Optional[str] = None,
844
- gap: Optional[int] = None,
845
- ) -> Dict[str, Any]:
846
- """Create subtitles from audio in the current timeline.
847
-
848
- Mirrors Timeline.CreateSubtitlesFromAudio({autoCaptionSettings}) per docs lines 718-761.
849
-
850
- Args:
851
- language: 'auto', 'danish', 'dutch', 'english', 'french', 'german', 'italian',
852
- 'japanese', 'korean', 'mandarin_simplified', 'mandarin_traditional',
853
- 'norwegian', 'portuguese', 'russian', 'spanish', 'swedish'. Default: 'auto'.
854
- preset: 'default', 'teletext', 'netflix'. Default: 'default'.
855
- chars_per_line: Integer 1-60. Resolve default is 42 (or 16 for Netflix preset).
856
- line_break: 'single' or 'double'. Default: 'single' on Resolve side.
857
- gap: Integer 0-10. Default: 0 on Resolve side.
858
- """
859
- r = get_resolve()
860
- if r is None:
861
- return {"error": "Not connected to DaVinci Resolve"}
862
- _, tl, err = _get_timeline()
863
- if err:
864
- return err
865
- settings, settings_err = _build_subtitle_settings(
866
- r, language=language, preset=preset,
867
- chars_per_line=chars_per_line, line_break=line_break, gap=gap,
868
- )
869
- if settings_err:
870
- return settings_err
871
- result = tl.CreateSubtitlesFromAudio(settings)
872
- return {"success": bool(result)}
873
-
874
-
875
- @mcp.tool()
876
- def timeline_detect_scene_cuts() -> Dict[str, Any]:
877
- """Detect scene cuts in the current timeline."""
878
- _, tl, err = _get_timeline()
879
- if err:
880
- return err
881
- result = tl.DetectSceneCuts()
882
- return {"success": bool(result)}
883
-
884
-
885
- @mcp.tool()
886
- def timeline_convert_to_stereo() -> Dict[str, Any]:
887
- """Convert the current timeline to stereo."""
888
- _, tl, err = _get_timeline()
889
- if err:
890
- return err
891
- result = tl.ConvertTimelineToStereo()
892
- return {"success": bool(result)}
893
-
894
-
895
- @mcp.tool()
896
- def timeline_get_node_graph() -> Dict[str, Any]:
897
- """Get the node graph for the current timeline."""
898
- _, tl, err = _get_timeline()
899
- if err:
900
- return err
901
- graph = tl.GetNodeGraph()
902
- if graph:
903
- return {"has_graph": True, "num_nodes": graph.GetNumNodes()}
904
- return {"has_graph": False}
905
-
906
-
907
- @mcp.tool()
908
- def timeline_analyze_dolby_vision() -> Dict[str, Any]:
909
- """Analyze Dolby Vision for the current timeline."""
910
- _, tl, err = _get_timeline()
911
- if err:
912
- return err
913
- result = tl.AnalyzeDolbyVision()
914
- return {"success": bool(result)}
915
-
916
-
917
- @mcp.tool()
918
- def timeline_get_current_video_item() -> Dict[str, Any]:
919
- """Get the current video item at the playhead."""
920
- _, tl, err = _get_timeline()
921
- if err:
922
- return err
923
- item = tl.GetCurrentVideoItem()
924
- if item:
925
- return {"name": item.GetName(), "unique_id": item.GetUniqueId(), "start": item.GetStart(), "end": item.GetEnd()}
926
- return {"item": None}
927
-
928
-
929
- @mcp.tool()
930
- def timeline_get_current_clip_thumbnail(width: int = 320, height: int = 180) -> Dict[str, Any]:
931
- """Get thumbnail image data for the current clip.
932
-
933
- Args:
934
- width: Thumbnail width. Default: 320.
935
- height: Thumbnail height. Default: 180.
936
- """
937
- _, tl, err = _get_timeline()
938
- if err:
939
- return err
940
- result = tl.GetCurrentClipThumbnailImage()
941
- if result:
942
- return {"success": True, "has_data": bool(result)}
943
- return {"success": False}
944
-
945
-
946
- @mcp.tool()
947
- def timeline_get_media_pool_item() -> Dict[str, Any]:
948
- """Get the MediaPoolItem for the current timeline."""
949
- _, tl, err = _get_timeline()
950
- if err:
951
- return err
952
- mpi = tl.GetMediaPoolItem()
953
- if mpi:
954
- return {"name": mpi.GetName(), "unique_id": mpi.GetUniqueId()}
955
- return {"media_pool_item": None}
956
-
957
-
958
- @mcp.tool()
959
- def timeline_get_mark_in_out() -> Dict[str, Any]:
960
- """Get mark in/out points for the current timeline."""
961
- _, tl, err = _get_timeline()
962
- if err:
963
- return err
964
- result = tl.GetMarkInOut()
965
- return result if result else {}
966
-
967
-
968
- @mcp.tool()
969
- def timeline_set_mark_in_out(mark_in: int, mark_out: int) -> Dict[str, Any]:
970
- """Set mark in/out points for the current timeline.
971
-
972
- Args:
973
- mark_in: Mark in frame number.
974
- mark_out: Mark out frame number.
975
- """
976
- _, tl, err = _get_timeline()
977
- if err:
978
- return err
979
- result = tl.SetMarkInOut(mark_in, mark_out)
980
- return {"success": bool(result)}
981
-
982
-
983
- @mcp.tool()
984
- def timeline_clear_mark_in_out() -> Dict[str, Any]:
985
- """Clear mark in/out points for the current timeline."""
986
- _, tl, err = _get_timeline()
987
- if err:
988
- return err
989
- result = tl.ClearMarkInOut()
990
- return {"success": bool(result)}
991
-
992
-
993
- @mcp.tool()
994
- def create_timeline_from_clips(
995
- name: str,
996
- clip_ids: Optional[List[str]] = None,
997
- clip_infos: Optional[List[Dict[str, Any]]] = None,
998
- ) -> Dict[str, Any]:
999
- """Create a new timeline from specified media pool clips.
1000
-
1001
- Args:
1002
- name: Name for the new timeline.
1003
- clip_ids: Simple form — list of MediaPoolItem unique IDs to append end-to-end.
1004
- clip_infos: Positioned form — list of dicts with keys clip_id (or
1005
- media_pool_item_id), start_frame, end_frame, record_frame.
1006
- record_frame is relative to the created timeline start frame by
1007
- default; pass record_frame_mode="absolute" for raw Resolve values.
1008
- If both are None, uses the currently selected media pool clips.
1009
- """
1010
- project, mp, err = _get_mp()
1011
- if err:
1012
- return err
1013
- if clip_infos is not None:
1014
- if not isinstance(clip_infos, list) or not clip_infos:
1015
- return {"error": "clip_infos must be a non-empty list"}
1016
- root = mp.GetRootFolder()
1017
- for i, ci in enumerate(clip_infos):
1018
- _, row_err = _build_create_clip_info_dict(root, ci, i)
1019
- if row_err:
1020
- return row_err
1021
- tl = mp.CreateEmptyTimeline(name)
1022
- if not tl:
1023
- return {"success": False, "error": "Failed to create timeline"}
1024
- try:
1025
- if project:
1026
- project.SetCurrentTimeline(tl)
1027
- except Exception:
1028
- logger.debug("Could not set newly created timeline current", exc_info=True)
1029
- timeline_start = _timeline_start_frame(tl)
1030
- built = []
1031
- for i, ci in enumerate(clip_infos):
1032
- append_ci = dict(ci)
1033
- append_ci.setdefault("track_index", append_ci.get("trackIndex", 1))
1034
- row, row_err = _build_append_clip_info_dict(root, append_ci, i, timeline_start)
1035
- if row_err:
1036
- return row_err
1037
- built.append(row)
1038
- appended = mp.AppendToTimeline(built)
1039
- if not appended:
1040
- return {"success": False, "error": "Failed to append clip_infos to created timeline"}
1041
- elif clip_ids:
1042
- root = mp.GetRootFolder()
1043
- clips = []
1044
- for cid in clip_ids:
1045
- clip = _find_clip_by_id(root, cid)
1046
- if clip:
1047
- clips.append(clip)
1048
- else:
1049
- return {"error": f"Clip not found: {cid}"}
1050
- tl = mp.CreateTimelineFromClips(name, clips)
1051
- else:
1052
- selected = mp.GetSelectedClips()
1053
- if not selected:
1054
- return {"error": "No clips specified and no clips selected in media pool"}
1055
- tl = mp.CreateTimelineFromClips(name, selected)
1056
- if tl:
1057
- return {"success": True, "timeline_name": tl.GetName(), "timeline_id": tl.GetUniqueId()}
1058
- return {"success": False, "error": "Failed to create timeline from clips"}
1059
-
1060
-
1061
- @mcp.tool()
1062
- def set_timeline_setting(setting_name: str, setting_value: str) -> Dict[str, Any]:
1063
- """Set a timeline setting value.
1064
-
1065
- Args:
1066
- setting_name: Name of the timeline setting to set (e.g. 'useCustomSettings', 'timelineFrameRate',
1067
- 'timelineResolutionWidth', 'timelineResolutionHeight', 'timelineOutputResolutionWidth',
1068
- 'timelineOutputResolutionHeight', 'colorSpaceTimeline', 'colorSpaceOutput').
1069
- setting_value: Value to set for the setting (string).
1070
- """
1071
- _, tl, err = _get_timeline()
1072
- if err:
1073
- return err
1074
- result = tl.SetSetting(setting_name, setting_value)
1075
- return {"success": bool(result), "setting_name": setting_name, "setting_value": setting_value}