@hybridlabor-api/aos 4.4.1 → 4.4.2-beta.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.agents/skills/firecrawl/SKILL.md +149 -0
- package/.agents/skills/firecrawl/rules/install.md +82 -0
- package/.agents/skills/firecrawl/rules/security.md +26 -0
- package/.agents/skills/firecrawl-agent/SKILL.md +58 -0
- package/.agents/skills/firecrawl-build/SKILL.md +39 -0
- package/.agents/skills/firecrawl-build-interact/SKILL.md +68 -0
- package/.agents/skills/firecrawl-build-onboarding/SKILL.md +103 -0
- package/.agents/skills/firecrawl-build-onboarding/references/auth-flow.md +39 -0
- package/.agents/skills/firecrawl-build-onboarding/references/project-setup.md +20 -0
- package/.agents/skills/firecrawl-build-onboarding/references/sdk-installation.md +17 -0
- package/.agents/skills/firecrawl-build-scrape/SKILL.md +69 -0
- package/.agents/skills/firecrawl-build-search/SKILL.md +69 -0
- package/.agents/skills/firecrawl-crawl/SKILL.md +59 -0
- package/.agents/skills/firecrawl-download/SKILL.md +70 -0
- package/.agents/skills/firecrawl-interact/SKILL.md +84 -0
- package/.agents/skills/firecrawl-map/SKILL.md +51 -0
- package/.agents/skills/firecrawl-scrape/SKILL.md +69 -0
- package/.agents/skills/firecrawl-search/SKILL.md +60 -0
- package/CLAUDE.md +573 -0
- package/README.de.md +0 -8
- package/README.md +0 -8
- package/README.pt.md +0 -8
- package/assets/brand/ao-ant-mark.svg +91 -0
- package/assets/brand/bdb-core-mark.svg +34 -0
- package/assets/brand/heimdall-guardian-mark.svg +16 -0
- package/assets/brand/memb-crystal-mark.svg +18 -0
- package/bin/aos-config.mjs +89 -0
- package/bin/aos-dashboard.mjs +608 -0
- package/bin/aos-uninstall.mjs +227 -0
- package/docs/sessions/audit-2026-09-14-silent-failures.md +114 -0
- package/docs/skills_table.md +0 -3
- package/installer.js +471 -237
- package/mcps/RhinoMCP/cc-plugin/.claude/settings.json +10 -0
- package/mcps/after-effects-mcp/build/index.js +840 -0
- package/mcps/after-effects-mcp/build/scripts/applyEffect.jsx +153 -0
- package/mcps/after-effects-mcp/build/scripts/applyEffectTemplate.jsx +218 -0
- package/mcps/after-effects-mcp/build/scripts/createComposition.jsx +71 -0
- package/mcps/after-effects-mcp/build/scripts/createShapeLayer.jsx +147 -0
- package/mcps/after-effects-mcp/build/scripts/createSolidLayer.jsx +114 -0
- package/mcps/after-effects-mcp/build/scripts/createTextLayer.jsx +115 -0
- package/mcps/after-effects-mcp/build/scripts/getLayerInfo.jsx +192 -0
- package/mcps/after-effects-mcp/build/scripts/getProjectInfo.jsx +90 -0
- package/mcps/after-effects-mcp/build/scripts/listCompositions.jsx +50 -0
- package/mcps/after-effects-mcp/build/scripts/mcp-bridge-auto.jsx +1773 -0
- package/mcps/after-effects-mcp/build/scripts/setLayerProperties.jsx +160 -0
- package/mcps/computer-use-mcp/dist/client.d.ts +150 -0
- package/mcps/computer-use-mcp/dist/client.js +136 -0
- package/mcps/computer-use-mcp/dist/entrypoint.d.ts +16 -0
- package/mcps/computer-use-mcp/dist/entrypoint.js +26 -0
- package/mcps/computer-use-mcp/dist/native.d.ts +212 -0
- package/mcps/computer-use-mcp/dist/native.js +50 -0
- package/mcps/computer-use-mcp/dist/server.d.ts +32 -0
- package/mcps/computer-use-mcp/dist/server.js +342 -0
- package/mcps/computer-use-mcp/dist/session.d.ts +101 -0
- package/mcps/computer-use-mcp/dist/session.js +2372 -0
- package/package.json +13 -4
- package/skills/global_config/aos-project-init/SKILL.md +97 -130
- package/skills/global_config/aos-project-init/assets/openwikiignore.template +62 -0
- package/skills/global_config/aos-project-init/scripts/aos-project-doctor.mjs +38 -1
- package/skills/global_config/aos-setup/SKILL.md +98 -8
- package/skills/global_config/aos-setup/scripts/aos-doctor.mjs +21 -2
- package/skills/global_config/ask-tim/SKILL.md +2 -7
- package/skills/global_config/openwiki-skill/scripts/openwiki_daemon.py +65 -12
- package/bin/setup-saas.mjs +0 -792
- package/mcps/blender-mcp-server/.dockerignore +0 -19
- package/mcps/blender-mcp-server/.github/workflows/ci.yml +0 -67
- package/mcps/blender-mcp-server/.github/workflows/publish-pypi.yml +0 -54
- package/mcps/blender-mcp-server/CHANGELOG.md +0 -64
- package/mcps/blender-mcp-server/CONTRIBUTING.md +0 -107
- package/mcps/blender-mcp-server/Dockerfile +0 -19
- package/mcps/blender-mcp-server/LICENSE +0 -21
- package/mcps/blender-mcp-server/README.md +0 -409
- package/mcps/blender-mcp-server/addon/__init__.py +0 -1440
- package/mcps/blender-mcp-server/addon/models.py +0 -223
- package/mcps/blender-mcp-server/pyproject.toml +0 -120
- package/mcps/blender-mcp-server/scripts/blender_bridge_request.py +0 -71
- package/mcps/blender-mcp-server/scripts/blender_create_test_cube.py +0 -49
- package/mcps/blender-mcp-server/scripts/blender_scene_info.py +0 -38
- package/mcps/blender-mcp-server/scripts/build_addon_zip.sh +0 -29
- package/mcps/blender-mcp-server/scripts/demos/README.md +0 -186
- package/mcps/blender-mcp-server/scripts/demos/dam_break_scene.py +0 -276
- package/mcps/blender-mcp-server/scripts/demos/open_dam_break_gui.py +0 -33
- package/mcps/blender-mcp-server/scripts/demos/pipe_movement_study.py +0 -518
- package/mcps/blender-mcp-server/scripts/demos/pipe_pressure_failure_scene.py +0 -806
- package/mcps/blender-mcp-server/scripts/demos/procedural_dam_break_scene.py +0 -600
- package/mcps/blender-mcp-server/scripts/demos/run_dam_break.py +0 -510
- package/mcps/blender-mcp-server/scripts/launch_blender_gui.py +0 -41
- package/mcps/blender-mcp-server/scripts/library/README.md +0 -64
- package/mcps/blender-mcp-server/scripts/library/apply_transforms.py +0 -46
- package/mcps/blender-mcp-server/scripts/library/camera.py +0 -51
- package/mcps/blender-mcp-server/scripts/library/collections.py +0 -65
- package/mcps/blender-mcp-server/scripts/library/create_mesh.py +0 -41
- package/mcps/blender-mcp-server/scripts/library/effector.py +0 -48
- package/mcps/blender-mcp-server/scripts/library/fluid_domain.py +0 -80
- package/mcps/blender-mcp-server/scripts/library/fluid_inflow.py +0 -98
- package/mcps/blender-mcp-server/scripts/library/frame_range.py +0 -35
- package/mcps/blender-mcp-server/scripts/library/keyframes.py +0 -59
- package/mcps/blender-mcp-server/scripts/library/rigid_body.py +0 -52
- package/mcps/blender-mcp-server/scripts/library/save_blend.py +0 -40
- package/mcps/blender-mcp-server/scripts/server_start.sh +0 -26
- package/mcps/blender-mcp-server/src/blender_mcp_server/__init__.py +0 -3
- package/mcps/blender-mcp-server/src/blender_mcp_server/headless.py +0 -330
- package/mcps/blender-mcp-server/src/blender_mcp_server/server.py +0 -606
- package/mcps/davinci-mcp-professional/.bandit +0 -35
- package/mcps/davinci-mcp-professional/.claude/commands/security-review.md +0 -191
- package/mcps/davinci-mcp-professional/.claude/settings.json +0 -1
- package/mcps/davinci-mcp-professional/.editorconfig +0 -27
- package/mcps/davinci-mcp-professional/.gitattributes +0 -207
- package/mcps/davinci-mcp-professional/.github/CODEOWNERS +0 -2
- package/mcps/davinci-mcp-professional/.github/ISSUE_TEMPLATE/bug_report.md +0 -33
- package/mcps/davinci-mcp-professional/.github/ISSUE_TEMPLATE/feature_request.md +0 -19
- package/mcps/davinci-mcp-professional/.github/PULL_REQUEST_TEMPLATE.md +0 -20
- package/mcps/davinci-mcp-professional/.github/SECURITY.md +0 -97
- package/mcps/davinci-mcp-professional/.github/dependabot.yml +0 -27
- package/mcps/davinci-mcp-professional/.github/workflows/ci.yml +0 -39
- package/mcps/davinci-mcp-professional/ATTRIBUTION.md +0 -4
- package/mcps/davinci-mcp-professional/AUTHORS.md +0 -9
- package/mcps/davinci-mcp-professional/BUGS.md +0 -55
- package/mcps/davinci-mcp-professional/CLAUDE.md +0 -229
- package/mcps/davinci-mcp-professional/CONTRIBUTING.md +0 -51
- package/mcps/davinci-mcp-professional/COPYING.md +0 -228
- package/mcps/davinci-mcp-professional/Doxyfile +0 -379
- package/mcps/davinci-mcp-professional/README.md +0 -143
- package/mcps/davinci-mcp-professional/SECURITY.md +0 -40
- package/mcps/davinci-mcp-professional/USING.md +0 -301
- package/mcps/davinci-mcp-professional/VERSION.md +0 -13
- package/mcps/davinci-mcp-professional/build.py +0 -169
- package/mcps/davinci-mcp-professional/claude_desktop_config_template.json +0 -11
- package/mcps/davinci-mcp-professional/hooks/ci-check.sh +0 -29
- package/mcps/davinci-mcp-professional/hooks/pre-push +0 -46
- package/mcps/davinci-mcp-professional/main.py +0 -40
- package/mcps/davinci-mcp-professional/mcp_server.py +0 -30
- package/mcps/davinci-mcp-professional/pyproject.toml +0 -115
- package/mcps/davinci-mcp-professional/security_audit.py +0 -379
- package/mcps/davinci-mcp-professional/src/davinci_mcp/__init__.py +0 -19
- package/mcps/davinci-mcp-professional/src/davinci_mcp/cli.py +0 -138
- package/mcps/davinci-mcp-professional/src/davinci_mcp/resolve_client.py +0 -342
- package/mcps/davinci-mcp-professional/src/davinci_mcp/resources/__init__.py +0 -60
- package/mcps/davinci-mcp-professional/src/davinci_mcp/server.py +0 -185
- package/mcps/davinci-mcp-professional/src/davinci_mcp/tools/__init__.py +0 -146
- package/mcps/davinci-mcp-professional/src/davinci_mcp/types.py +0 -125
- package/mcps/davinci-mcp-professional/src/davinci_mcp/utils/__init__.py +0 -19
- package/mcps/davinci-mcp-professional/src/davinci_mcp/utils/platform.py +0 -239
- package/mcps/davinci-mcp-professional/test.py +0 -186
- package/mcps/davinci-mcp-professional/uv.lock +0 -2073
- package/mcps/davinci-resolve-mcp/.claude/skills/media-analysis.md +0 -44
- package/mcps/davinci-resolve-mcp/.clinerules +0 -17
- package/mcps/davinci-resolve-mcp/.cursorrules +0 -17
- package/mcps/davinci-resolve-mcp/.github/copilot-instructions.md +0 -17
- package/mcps/davinci-resolve-mcp/.github/workflows/npm-publish.yml +0 -109
- package/mcps/davinci-resolve-mcp/.windsurfrules +0 -17
- package/mcps/davinci-resolve-mcp/AGENTS.md +0 -114
- package/mcps/davinci-resolve-mcp/CHANGELOG.md +0 -2648
- package/mcps/davinci-resolve-mcp/CLAUDE.md +0 -15
- package/mcps/davinci-resolve-mcp/LICENSE +0 -21
- package/mcps/davinci-resolve-mcp/README.md +0 -173
- package/mcps/davinci-resolve-mcp/SECURITY.md +0 -53
- package/mcps/davinci-resolve-mcp/bin/davinci-resolve-mcp.mjs +0 -450
- package/mcps/davinci-resolve-mcp/examples/README.md +0 -53
- package/mcps/davinci-resolve-mcp/examples/markers/README.md +0 -81
- package/mcps/davinci-resolve-mcp/examples/media/README.md +0 -94
- package/mcps/davinci-resolve-mcp/examples/timeline/README.md +0 -98
- package/mcps/davinci-resolve-mcp/install.py +0 -1687
- package/mcps/davinci-resolve-mcp/package.json +0 -52
- package/mcps/davinci-resolve-mcp/release-notes/v2.22.0.md +0 -51
- package/mcps/davinci-resolve-mcp/release-notes/v2.23.0.md +0 -51
- package/mcps/davinci-resolve-mcp/release-notes/v2.23.1.md +0 -35
- package/mcps/davinci-resolve-mcp/release-notes/v2.24.1.md +0 -32
- package/mcps/davinci-resolve-mcp/scripts/audit_api_parity.py +0 -275
- package/mcps/davinci-resolve-mcp/scripts/audit_readwrite_symmetry.py +0 -80
- package/mcps/davinci-resolve-mcp/scripts/doctor.py +0 -227
- package/mcps/davinci-resolve-mcp/scripts/gen_api_limitations.py +0 -144
- package/mcps/davinci-resolve-mcp/scripts/live_media_analysis_polish_probe.py +0 -65
- package/mcps/davinci-resolve-mcp/scripts/measure_bridge_cost.py +0 -65
- package/mcps/davinci-resolve-mcp/scripts/regen_panel_screenshots.py +0 -76
- package/mcps/davinci-resolve-mcp/src/__init__.py +0 -3
- package/mcps/davinci-resolve-mcp/src/analysis_dashboard.py +0 -15505
- package/mcps/davinci-resolve-mcp/src/batch_cli.py +0 -540
- package/mcps/davinci-resolve-mcp/src/control_panel.py +0 -13
- package/mcps/davinci-resolve-mcp/src/granular/__init__.py +0 -17
- package/mcps/davinci-resolve-mcp/src/granular/common.py +0 -741
- package/mcps/davinci-resolve-mcp/src/granular/folder.py +0 -420
- package/mcps/davinci-resolve-mcp/src/granular/gallery.py +0 -306
- package/mcps/davinci-resolve-mcp/src/granular/graph.py +0 -309
- package/mcps/davinci-resolve-mcp/src/granular/media_pool.py +0 -679
- package/mcps/davinci-resolve-mcp/src/granular/media_pool_item.py +0 -1020
- package/mcps/davinci-resolve-mcp/src/granular/media_storage.py +0 -179
- package/mcps/davinci-resolve-mcp/src/granular/project.py +0 -1654
- package/mcps/davinci-resolve-mcp/src/granular/resolve_control.py +0 -538
- package/mcps/davinci-resolve-mcp/src/granular/timeline.py +0 -1075
- package/mcps/davinci-resolve-mcp/src/granular/timeline_item.py +0 -2251
- package/mcps/davinci-resolve-mcp/src/resolve_mcp_server.py +0 -43
- package/mcps/davinci-resolve-mcp/src/server.py +0 -24116
- package/mcps/davinci-resolve-mcp/src/utils/__init__.py +0 -3
- package/mcps/davinci-resolve-mcp/src/utils/actor_identity.py +0 -46
- package/mcps/davinci-resolve-mcp/src/utils/analysis_caps.py +0 -678
- package/mcps/davinci-resolve-mcp/src/utils/analysis_memory.py +0 -755
- package/mcps/davinci-resolve-mcp/src/utils/analysis_runs.py +0 -307
- package/mcps/davinci-resolve-mcp/src/utils/analysis_store.py +0 -945
- package/mcps/davinci-resolve-mcp/src/utils/api_truth.py +0 -525
- package/mcps/davinci-resolve-mcp/src/utils/app_control.py +0 -319
- package/mcps/davinci-resolve-mcp/src/utils/audio_fairlight_live_probe.py +0 -263
- package/mcps/davinci-resolve-mcp/src/utils/brain_edits.py +0 -387
- package/mcps/davinci-resolve-mcp/src/utils/bridge_metrics.py +0 -76
- package/mcps/davinci-resolve-mcp/src/utils/cdl.py +0 -20
- package/mcps/davinci-resolve-mcp/src/utils/clip_query.py +0 -85
- package/mcps/davinci-resolve-mcp/src/utils/cloud_operations.py +0 -192
- package/mcps/davinci-resolve-mcp/src/utils/color_grade_live_probe.py +0 -444
- package/mcps/davinci-resolve-mcp/src/utils/contracts.py +0 -102
- package/mcps/davinci-resolve-mcp/src/utils/cut_ir.py +0 -115
- package/mcps/davinci-resolve-mcp/src/utils/dctl_templates.py +0 -368
- package/mcps/davinci-resolve-mcp/src/utils/deep_vision.py +0 -643
- package/mcps/davinci-resolve-mcp/src/utils/destructive_hook.py +0 -606
- package/mcps/davinci-resolve-mcp/src/utils/edit_engine.py +0 -737
- package/mcps/davinci-resolve-mcp/src/utils/embeddings.py +0 -922
- package/mcps/davinci-resolve-mcp/src/utils/entities.py +0 -579
- package/mcps/davinci-resolve-mcp/src/utils/extension_authoring_live_probe.py +0 -292
- package/mcps/davinci-resolve-mcp/src/utils/failure_tracker.py +0 -119
- package/mcps/davinci-resolve-mcp/src/utils/fuse_templates.py +0 -1968
- package/mcps/davinci-resolve-mcp/src/utils/fusion_composition_live_probe.py +0 -284
- package/mcps/davinci-resolve-mcp/src/utils/fusion_group_settings.py +0 -334
- package/mcps/davinci-resolve-mcp/src/utils/layout_presets.py +0 -333
- package/mcps/davinci-resolve-mcp/src/utils/mcp_stdio.py +0 -32
- package/mcps/davinci-resolve-mcp/src/utils/mcp_transport.py +0 -128
- package/mcps/davinci-resolve-mcp/src/utils/media_analysis.py +0 -7690
- package/mcps/davinci-resolve-mcp/src/utils/media_analysis_jobs.py +0 -805
- package/mcps/davinci-resolve-mcp/src/utils/media_pool_changes.py +0 -121
- package/mcps/davinci-resolve-mcp/src/utils/media_pool_ingest_live_probe.py +0 -592
- package/mcps/davinci-resolve-mcp/src/utils/multicam.py +0 -393
- package/mcps/davinci-resolve-mcp/src/utils/object_inspection.py +0 -301
- package/mcps/davinci-resolve-mcp/src/utils/page_lock.py +0 -75
- package/mcps/davinci-resolve-mcp/src/utils/platform.py +0 -157
- package/mcps/davinci-resolve-mcp/src/utils/proc.py +0 -26
- package/mcps/davinci-resolve-mcp/src/utils/project_cleanup.py +0 -73
- package/mcps/davinci-resolve-mcp/src/utils/project_lifecycle_live_probe.py +0 -376
- package/mcps/davinci-resolve-mcp/src/utils/project_lint.py +0 -131
- package/mcps/davinci-resolve-mcp/src/utils/project_properties.py +0 -601
- package/mcps/davinci-resolve-mcp/src/utils/project_spec.py +0 -459
- package/mcps/davinci-resolve-mcp/src/utils/readback.py +0 -91
- package/mcps/davinci-resolve-mcp/src/utils/render_deliver_live_probe.py +0 -384
- package/mcps/davinci-resolve-mcp/src/utils/resolve_ai_governance.py +0 -214
- package/mcps/davinci-resolve-mcp/src/utils/resolve_ai_ledger.py +0 -244
- package/mcps/davinci-resolve-mcp/src/utils/resolve_busy.py +0 -171
- package/mcps/davinci-resolve-mcp/src/utils/resolve_connection.py +0 -77
- package/mcps/davinci-resolve-mcp/src/utils/review_annotation_live_probe.py +0 -352
- package/mcps/davinci-resolve-mcp/src/utils/script_templates.py +0 -1193
- package/mcps/davinci-resolve-mcp/src/utils/shot_relationships.py +0 -544
- package/mcps/davinci-resolve-mcp/src/utils/structural_diff.py +0 -175
- package/mcps/davinci-resolve-mcp/src/utils/sync_detection.py +0 -889
- package/mcps/davinci-resolve-mcp/src/utils/timeline_brain_db.py +0 -826
- package/mcps/davinci-resolve-mcp/src/utils/timeline_conform_live_probe.py +0 -280
- package/mcps/davinci-resolve-mcp/src/utils/timeline_kernel_live_probe.py +0 -1092
- package/mcps/davinci-resolve-mcp/src/utils/timeline_kernel_probe.py +0 -185
- package/mcps/davinci-resolve-mcp/src/utils/timeline_title_text.py +0 -87
- package/mcps/davinci-resolve-mcp/src/utils/timeline_versioning.py +0 -730
- package/mcps/davinci-resolve-mcp/src/utils/update_check.py +0 -685
- package/mcps/vectorworks-mcp/.dockerignore +0 -8
- package/mcps/vectorworks-mcp/Dockerfile +0 -28
- package/mcps/vectorworks-mcp/README.md +0 -156
- package/mcps/vectorworks-mcp/app/__init__.py +0 -2
- package/mcps/vectorworks-mcp/app/api.py +0 -52
- package/mcps/vectorworks-mcp/app/chunking.py +0 -56
- package/mcps/vectorworks-mcp/app/config.py +0 -29
- package/mcps/vectorworks-mcp/app/embeddings.py +0 -28
- package/mcps/vectorworks-mcp/app/indexer.py +0 -106
- package/mcps/vectorworks-mcp/app/main.py +0 -33
- package/mcps/vectorworks-mcp/app/mcp_server.py +0 -71
- package/mcps/vectorworks-mcp/app/search.py +0 -54
- package/mcps/vectorworks-mcp/app/utils.py +0 -14
- package/mcps/vectorworks-mcp/data/.gitkeep +0 -1
- package/mcps/vectorworks-mcp/data/vw-app-help/VW2022_PluginScript.htm +0 -95
- package/mcps/vectorworks-mcp/data/vw-app-help/VW2022_ScriptEditor.htm +0 -266
- package/mcps/vectorworks-mcp/data/vw-app-help/VW2022_Scripting.htm +0 -106
- package/mcps/vectorworks-mcp/data/vw-app-help/VW2023_CreatingScriptedPlugins.htm +0 -327
- package/mcps/vectorworks-mcp/data/vw-app-help/VW2024_RunningScripts.htm +0 -116
- package/mcps/vectorworks-mcp/data/vw-devwiki/VS_Function_Reference_category.html +0 -2129
- package/mcps/vectorworks-mcp/data/vw-jp-ref/ObjectsSymbols.html +0 -2035
- package/mcps/vectorworks-mcp/data/vw-jp-ref/ScriptFunctionReference.html +0 -29
- package/mcps/vectorworks-mcp/design.md +0 -57
- package/mcps/vectorworks-mcp/docker-compose.yml +0 -18
- package/mcps/vectorworks-mcp/index/.gitkeep +0 -1
- package/mcps/vectorworks-mcp/index/meta.jsonl +0 -3956
- package/mcps/vectorworks-mcp/index/vw.faiss +0 -0
- package/mcps/vectorworks-mcp/requirements.txt +0 -10
- package/mcps/vectorworks-mcp/scripts/fetch_docs_minimal.sh +0 -84
- package/mcps/vectorworks-mcp/scripts/fetch_github_vectorworks.sh +0 -85
- package/mcps/vectorworks-mcp/templates/index.html +0 -40
- package/scripts/ecosystem-health-audit.js +0 -257
- package/skills/bdb-dev-os-skill/SKILL.md +0 -49
- package/skills/bdb-dev-os-skill/package.json +0 -11
- package/skills/bdbsaastraining/SKILL.md +0 -316
- package/skills/bdbsaastraining/references/exam-pool.md +0 -313
- package/skills/bdbsaastraining/references/interaction-modes.md +0 -94
- package/skills/bdbsaastraining/references/track-a-ai-agent.md +0 -111
- package/skills/bdbsaastraining/references/track-b-wordpress.md +0 -111
- package/skills/bdbsaastraining/references/track-c-mailserver.md +0 -107
- package/skills/bdbsaastraining/references/track-d-debian.md +0 -109
- package/skills/bdbsaastraining/references/track-e-custom.md +0 -83
- package/skills/bdbsaastraining/scripts/build_profile.py +0 -529
- package/skills/bdbsaastraining/scripts/generate_certificate.py +0 -161
- package/skills/bdbsaastraining/scripts/preflight_check.sh +0 -150
- package/skills/bdbsaastraining/templates/certificate_template.html +0 -508
- package/skills/global_config/bdb-ecosystem-health/SKILL.md +0 -68
- package/skills/global_config/bdbsaas-ops/SKILL.md +0 -16
- package/skills/global_config/bdbsaashost/SKILL.md +0 -125
|
@@ -1,342 +0,0 @@
|
|
|
1
|
-
"""
|
|
2
|
-
DaVinci Resolve client wrapper.
|
|
3
|
-
|
|
4
|
-
Provides a clean interface to the DaVinci Resolve API with proper error handling
|
|
5
|
-
and logging.
|
|
6
|
-
"""
|
|
7
|
-
|
|
8
|
-
import logging
|
|
9
|
-
from typing import TYPE_CHECKING, Any
|
|
10
|
-
|
|
11
|
-
if TYPE_CHECKING:
|
|
12
|
-
# Import for type checking only to avoid runtime import issues
|
|
13
|
-
from .types import DaVinciProject, DaVinciProjectManager, DaVinciResolveApp
|
|
14
|
-
|
|
15
|
-
from .utils.platform import (
|
|
16
|
-
check_python_runtime_compatibility,
|
|
17
|
-
check_resolve_running,
|
|
18
|
-
setup_resolve_environment,
|
|
19
|
-
)
|
|
20
|
-
|
|
21
|
-
logger = logging.getLogger(__name__)
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
class DaVinciResolveError(Exception):
|
|
25
|
-
"""Base exception for DaVinci Resolve related errors."""
|
|
26
|
-
|
|
27
|
-
pass
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
class DaVinciResolveNotRunningError(DaVinciResolveError):
|
|
31
|
-
"""Raised when DaVinci Resolve is not running."""
|
|
32
|
-
|
|
33
|
-
pass
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
class DaVinciResolveConnectionError(DaVinciResolveError):
|
|
37
|
-
"""Raised when connection to DaVinci Resolve fails."""
|
|
38
|
-
|
|
39
|
-
pass
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
class DaVinciResolveClient:
|
|
43
|
-
"""
|
|
44
|
-
A clean interface to the DaVinci Resolve API.
|
|
45
|
-
|
|
46
|
-
This class handles the connection to DaVinci Resolve and provides
|
|
47
|
-
organized methods for interacting with projects, timelines, media, etc.
|
|
48
|
-
"""
|
|
49
|
-
|
|
50
|
-
def __init__(self) -> None:
|
|
51
|
-
self._resolve: DaVinciResolveApp | None = None
|
|
52
|
-
self._project_manager: DaVinciProjectManager | None = None
|
|
53
|
-
self._current_project: DaVinciProject | None = None
|
|
54
|
-
self._is_connected = False
|
|
55
|
-
|
|
56
|
-
def connect(self) -> None:
|
|
57
|
-
"""Connect to DaVinci Resolve."""
|
|
58
|
-
# Check if Resolve is running
|
|
59
|
-
if not check_resolve_running():
|
|
60
|
-
raise DaVinciResolveNotRunningError(
|
|
61
|
-
"DaVinci Resolve is not running. Please start DaVinci Resolve first."
|
|
62
|
-
)
|
|
63
|
-
|
|
64
|
-
# Set up environment (env vars, sys.path, DLL search dirs)
|
|
65
|
-
if not setup_resolve_environment():
|
|
66
|
-
raise DaVinciResolveConnectionError(
|
|
67
|
-
"Failed to set up DaVinci Resolve environment variables."
|
|
68
|
-
)
|
|
69
|
-
|
|
70
|
-
# On Windows, fusionscript.dll discovers Python via the Windows
|
|
71
|
-
# registry and loads python3.dll by full path. If the running
|
|
72
|
-
# Python is a different installation (e.g. uv-managed), two
|
|
73
|
-
# runtimes end up in the same process and it crashes.
|
|
74
|
-
compat_ok, compat_msg = check_python_runtime_compatibility()
|
|
75
|
-
if not compat_ok:
|
|
76
|
-
raise DaVinciResolveConnectionError(compat_msg)
|
|
77
|
-
|
|
78
|
-
try:
|
|
79
|
-
# Import and connect to Resolve
|
|
80
|
-
import DaVinciResolveScript as dvr_script # type: ignore[reportMissingImports]
|
|
81
|
-
|
|
82
|
-
self._resolve = dvr_script.scriptapp("Resolve") # type: ignore[reportUnknownMemberType]
|
|
83
|
-
|
|
84
|
-
if self._resolve is None:
|
|
85
|
-
raise DaVinciResolveConnectionError(
|
|
86
|
-
"Failed to get Resolve object. "
|
|
87
|
-
"Check that DaVinci Resolve is running."
|
|
88
|
-
) # type: ignore[reportUnknownMemberType]
|
|
89
|
-
|
|
90
|
-
# Get project manager
|
|
91
|
-
self._project_manager = self._resolve.GetProjectManager() # type: ignore[reportUnknownMemberType]
|
|
92
|
-
if self._project_manager is None:
|
|
93
|
-
raise DaVinciResolveConnectionError("Failed to get Project Manager.")
|
|
94
|
-
|
|
95
|
-
# Get current project if one is open
|
|
96
|
-
self._current_project = self._project_manager.GetCurrentProject() # type: ignore[reportUnknownMemberType]
|
|
97
|
-
|
|
98
|
-
self._is_connected = True
|
|
99
|
-
logger.info(f"Connected to {self.get_version()}")
|
|
100
|
-
|
|
101
|
-
except SystemError as e:
|
|
102
|
-
raise DaVinciResolveConnectionError(
|
|
103
|
-
f"fusionscript.dll initialization failed: {e}. "
|
|
104
|
-
"Check that DaVinci Resolve Studio is running with "
|
|
105
|
-
"external scripting enabled in Preferences."
|
|
106
|
-
)
|
|
107
|
-
except ImportError as e:
|
|
108
|
-
raise DaVinciResolveConnectionError(
|
|
109
|
-
f"Failed to import DaVinciResolveScript: {e}. "
|
|
110
|
-
"Check environment variables and DaVinci Resolve installation."
|
|
111
|
-
)
|
|
112
|
-
except DaVinciResolveConnectionError:
|
|
113
|
-
raise
|
|
114
|
-
except Exception as e:
|
|
115
|
-
raise DaVinciResolveConnectionError(f"Unexpected error connecting: {e}")
|
|
116
|
-
|
|
117
|
-
def disconnect(self) -> None:
|
|
118
|
-
"""Disconnect from DaVinci Resolve."""
|
|
119
|
-
self._resolve = None
|
|
120
|
-
self._project_manager = None
|
|
121
|
-
self._current_project = None
|
|
122
|
-
self._is_connected = False
|
|
123
|
-
logger.info("Disconnected from DaVinci Resolve")
|
|
124
|
-
|
|
125
|
-
def is_connected(self) -> bool:
|
|
126
|
-
"""Check if connected to DaVinci Resolve."""
|
|
127
|
-
return self._is_connected
|
|
128
|
-
|
|
129
|
-
def _ensure_connected(self) -> None:
|
|
130
|
-
"""Ensure we're connected to Resolve."""
|
|
131
|
-
if not self._is_connected:
|
|
132
|
-
raise DaVinciResolveConnectionError("Not connected to DaVinci Resolve")
|
|
133
|
-
|
|
134
|
-
def _ensure_project(self) -> Any:
|
|
135
|
-
"""Ensure we have a current project."""
|
|
136
|
-
self._ensure_connected()
|
|
137
|
-
|
|
138
|
-
# Refresh current project
|
|
139
|
-
if self._project_manager:
|
|
140
|
-
self._current_project = self._project_manager.GetCurrentProject()
|
|
141
|
-
|
|
142
|
-
if self._current_project is None:
|
|
143
|
-
raise DaVinciResolveError("No project is currently open")
|
|
144
|
-
|
|
145
|
-
return self._current_project
|
|
146
|
-
|
|
147
|
-
# System Information
|
|
148
|
-
def get_version(self) -> str:
|
|
149
|
-
"""Get DaVinci Resolve version."""
|
|
150
|
-
self._ensure_connected()
|
|
151
|
-
if self._resolve:
|
|
152
|
-
return (
|
|
153
|
-
f"{self._resolve.GetProductName()} {self._resolve.GetVersionString()}"
|
|
154
|
-
)
|
|
155
|
-
return "Unknown"
|
|
156
|
-
|
|
157
|
-
def get_current_page(self) -> str:
|
|
158
|
-
"""Get the current page (Edit, Color, Fusion, etc.)."""
|
|
159
|
-
self._ensure_connected()
|
|
160
|
-
if self._resolve:
|
|
161
|
-
return self._resolve.GetCurrentPage()
|
|
162
|
-
return "Unknown"
|
|
163
|
-
|
|
164
|
-
def switch_page(self, page: str) -> bool:
|
|
165
|
-
"""Switch to a specific page."""
|
|
166
|
-
self._ensure_connected()
|
|
167
|
-
|
|
168
|
-
valid_pages = [
|
|
169
|
-
"media",
|
|
170
|
-
"cut",
|
|
171
|
-
"edit",
|
|
172
|
-
"fusion",
|
|
173
|
-
"color",
|
|
174
|
-
"fairlight",
|
|
175
|
-
"deliver",
|
|
176
|
-
]
|
|
177
|
-
if page.lower() not in valid_pages:
|
|
178
|
-
raise ValueError(f"Invalid page. Must be one of: {', '.join(valid_pages)}")
|
|
179
|
-
|
|
180
|
-
if self._resolve:
|
|
181
|
-
return bool(self._resolve.OpenPage(page.lower()))
|
|
182
|
-
return False
|
|
183
|
-
|
|
184
|
-
# Project Management
|
|
185
|
-
def list_projects(self) -> list[str]:
|
|
186
|
-
"""List all projects in the current database."""
|
|
187
|
-
self._ensure_connected()
|
|
188
|
-
|
|
189
|
-
if self._project_manager:
|
|
190
|
-
projects = self._project_manager.GetProjectListInCurrentFolder()
|
|
191
|
-
return [p for p in projects if p] # Filter out empty strings
|
|
192
|
-
return []
|
|
193
|
-
|
|
194
|
-
def get_current_project_name(self) -> str | None:
|
|
195
|
-
"""Get the name of the currently open project."""
|
|
196
|
-
try:
|
|
197
|
-
project = self._ensure_project()
|
|
198
|
-
return project.GetName()
|
|
199
|
-
except DaVinciResolveError:
|
|
200
|
-
return None
|
|
201
|
-
|
|
202
|
-
def open_project(self, name: str) -> bool:
|
|
203
|
-
"""Open a project by name."""
|
|
204
|
-
self._ensure_connected()
|
|
205
|
-
|
|
206
|
-
if not self._project_manager:
|
|
207
|
-
return False
|
|
208
|
-
|
|
209
|
-
# Check if project exists
|
|
210
|
-
projects = self.list_projects()
|
|
211
|
-
if name not in projects:
|
|
212
|
-
raise ValueError(
|
|
213
|
-
f"Project '{name}' not found. Available: {', '.join(projects)}"
|
|
214
|
-
)
|
|
215
|
-
|
|
216
|
-
result = self._project_manager.LoadProject(name)
|
|
217
|
-
if result:
|
|
218
|
-
self._current_project = self._project_manager.GetCurrentProject()
|
|
219
|
-
logger.info(f"Opened project: {name}")
|
|
220
|
-
|
|
221
|
-
return bool(result)
|
|
222
|
-
|
|
223
|
-
def create_project(self, name: str) -> bool:
|
|
224
|
-
"""Create a new project."""
|
|
225
|
-
self._ensure_connected()
|
|
226
|
-
|
|
227
|
-
if not self._project_manager:
|
|
228
|
-
return False
|
|
229
|
-
|
|
230
|
-
# Check if project already exists
|
|
231
|
-
projects = self.list_projects()
|
|
232
|
-
if name in projects:
|
|
233
|
-
raise ValueError(f"Project '{name}' already exists")
|
|
234
|
-
|
|
235
|
-
result = self._project_manager.CreateProject(name)
|
|
236
|
-
if result:
|
|
237
|
-
self._current_project = self._project_manager.GetCurrentProject()
|
|
238
|
-
logger.info(f"Created project: {name}")
|
|
239
|
-
|
|
240
|
-
return bool(result)
|
|
241
|
-
|
|
242
|
-
# Timeline Management
|
|
243
|
-
def list_timelines(self) -> list[str]:
|
|
244
|
-
"""List all timelines in the current project."""
|
|
245
|
-
project = self._ensure_project()
|
|
246
|
-
|
|
247
|
-
timeline_count = project.GetTimelineCount()
|
|
248
|
-
timelines: list[str] = []
|
|
249
|
-
|
|
250
|
-
for i in range(1, timeline_count + 1):
|
|
251
|
-
timeline = project.GetTimelineByIndex(i)
|
|
252
|
-
if timeline:
|
|
253
|
-
name = timeline.GetName()
|
|
254
|
-
if isinstance(name, str):
|
|
255
|
-
timelines.append(name)
|
|
256
|
-
|
|
257
|
-
return timelines
|
|
258
|
-
|
|
259
|
-
def get_current_timeline_name(self) -> str | None:
|
|
260
|
-
"""Get the name of the current timeline."""
|
|
261
|
-
try:
|
|
262
|
-
project = self._ensure_project()
|
|
263
|
-
current_timeline = project.GetCurrentTimeline()
|
|
264
|
-
return current_timeline.GetName() if current_timeline else None
|
|
265
|
-
except DaVinciResolveError:
|
|
266
|
-
return None
|
|
267
|
-
|
|
268
|
-
def create_timeline(self, name: str) -> bool:
|
|
269
|
-
"""Create a new timeline."""
|
|
270
|
-
project = self._ensure_project()
|
|
271
|
-
|
|
272
|
-
media_pool = project.GetMediaPool()
|
|
273
|
-
if not media_pool:
|
|
274
|
-
raise DaVinciResolveError("Failed to get Media Pool")
|
|
275
|
-
|
|
276
|
-
timeline = media_pool.CreateEmptyTimeline(name)
|
|
277
|
-
if timeline:
|
|
278
|
-
logger.info(f"Created timeline: {name}")
|
|
279
|
-
return True
|
|
280
|
-
|
|
281
|
-
return False
|
|
282
|
-
|
|
283
|
-
def switch_timeline(self, name: str) -> bool:
|
|
284
|
-
"""Switch to a timeline by name."""
|
|
285
|
-
project = self._ensure_project()
|
|
286
|
-
|
|
287
|
-
# Find timeline by name
|
|
288
|
-
timeline_count = project.GetTimelineCount()
|
|
289
|
-
for i in range(1, timeline_count + 1):
|
|
290
|
-
timeline = project.GetTimelineByIndex(i)
|
|
291
|
-
if timeline and timeline.GetName() == name:
|
|
292
|
-
result = project.SetCurrentTimeline(timeline)
|
|
293
|
-
if result:
|
|
294
|
-
logger.info(f"Switched to timeline: {name}")
|
|
295
|
-
return bool(result)
|
|
296
|
-
|
|
297
|
-
raise ValueError(f"Timeline '{name}' not found")
|
|
298
|
-
|
|
299
|
-
# Media Pool Management
|
|
300
|
-
def list_media_clips(self) -> list[dict[str, Any]]:
|
|
301
|
-
"""List all clips in the media pool root folder."""
|
|
302
|
-
project = self._ensure_project()
|
|
303
|
-
|
|
304
|
-
media_pool = project.GetMediaPool()
|
|
305
|
-
if not media_pool:
|
|
306
|
-
raise DaVinciResolveError("Failed to get Media Pool")
|
|
307
|
-
|
|
308
|
-
root_folder = media_pool.GetRootFolder()
|
|
309
|
-
if not root_folder:
|
|
310
|
-
raise DaVinciResolveError("Failed to get root folder")
|
|
311
|
-
|
|
312
|
-
clips = root_folder.GetClipList()
|
|
313
|
-
if not clips:
|
|
314
|
-
return []
|
|
315
|
-
|
|
316
|
-
result: list[dict[str, Any]] = []
|
|
317
|
-
for clip in clips:
|
|
318
|
-
clip_info = {
|
|
319
|
-
"name": clip.GetName(),
|
|
320
|
-
"duration": clip.GetDuration(),
|
|
321
|
-
"fps": clip.GetClipProperty("FPS") or "Unknown",
|
|
322
|
-
}
|
|
323
|
-
result.append(clip_info)
|
|
324
|
-
|
|
325
|
-
return result
|
|
326
|
-
|
|
327
|
-
def import_media(self, file_path: str) -> bool:
|
|
328
|
-
"""Import a media file into the media pool."""
|
|
329
|
-
project = self._ensure_project()
|
|
330
|
-
|
|
331
|
-
media_pool = project.GetMediaPool()
|
|
332
|
-
if not media_pool:
|
|
333
|
-
raise DaVinciResolveError("Failed to get Media Pool")
|
|
334
|
-
|
|
335
|
-
# Import the media file
|
|
336
|
-
imported_clips = media_pool.ImportMedia([file_path])
|
|
337
|
-
|
|
338
|
-
if imported_clips:
|
|
339
|
-
logger.info(f"Imported media: {file_path}")
|
|
340
|
-
return True
|
|
341
|
-
|
|
342
|
-
return False
|
|
@@ -1,60 +0,0 @@
|
|
|
1
|
-
"""
|
|
2
|
-
MCP resources for DaVinci Resolve integration.
|
|
3
|
-
"""
|
|
4
|
-
|
|
5
|
-
from typing import cast
|
|
6
|
-
|
|
7
|
-
import mcp.types as types
|
|
8
|
-
from pydantic import AnyUrl
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
def get_all_resources() -> list[types.Resource]:
|
|
12
|
-
"""Get all available MCP resources."""
|
|
13
|
-
return [
|
|
14
|
-
# System resources
|
|
15
|
-
types.Resource(
|
|
16
|
-
uri=cast(AnyUrl, "resolve://version"),
|
|
17
|
-
name="DaVinci Resolve Version",
|
|
18
|
-
description="Current version of DaVinci Resolve",
|
|
19
|
-
mimeType="text/plain",
|
|
20
|
-
),
|
|
21
|
-
types.Resource(
|
|
22
|
-
uri=cast(AnyUrl, "resolve://current-page"),
|
|
23
|
-
name="Current Page",
|
|
24
|
-
description="The currently active page in DaVinci Resolve",
|
|
25
|
-
mimeType="text/plain",
|
|
26
|
-
),
|
|
27
|
-
# Project resources
|
|
28
|
-
types.Resource(
|
|
29
|
-
uri=cast(AnyUrl, "resolve://projects"),
|
|
30
|
-
name="Available Projects",
|
|
31
|
-
description="List of all available projects in the current database",
|
|
32
|
-
mimeType="application/json",
|
|
33
|
-
),
|
|
34
|
-
types.Resource(
|
|
35
|
-
uri=cast(AnyUrl, "resolve://current-project"),
|
|
36
|
-
name="Current Project",
|
|
37
|
-
description="Name of the currently open project",
|
|
38
|
-
mimeType="text/plain",
|
|
39
|
-
),
|
|
40
|
-
# Timeline resources
|
|
41
|
-
types.Resource(
|
|
42
|
-
uri=cast(AnyUrl, "resolve://timelines"),
|
|
43
|
-
name="Available Timelines",
|
|
44
|
-
description="List of all timelines in the current project",
|
|
45
|
-
mimeType="application/json",
|
|
46
|
-
),
|
|
47
|
-
types.Resource(
|
|
48
|
-
uri=cast(AnyUrl, "resolve://current-timeline"),
|
|
49
|
-
name="Current Timeline",
|
|
50
|
-
description="Name of the current timeline",
|
|
51
|
-
mimeType="text/plain",
|
|
52
|
-
),
|
|
53
|
-
# Media resources
|
|
54
|
-
types.Resource(
|
|
55
|
-
uri=cast(AnyUrl, "resolve://media-clips"),
|
|
56
|
-
name="Media Pool Clips",
|
|
57
|
-
description="List of all clips in the media pool",
|
|
58
|
-
mimeType="application/json",
|
|
59
|
-
),
|
|
60
|
-
]
|
|
@@ -1,185 +0,0 @@
|
|
|
1
|
-
"""
|
|
2
|
-
DaVinci Resolve MCP Server.
|
|
3
|
-
|
|
4
|
-
A clean, modern implementation of the Model Context Protocol server
|
|
5
|
-
for DaVinci Resolve integration.
|
|
6
|
-
"""
|
|
7
|
-
|
|
8
|
-
import logging
|
|
9
|
-
from typing import Any
|
|
10
|
-
|
|
11
|
-
import mcp.server.stdio
|
|
12
|
-
import mcp.types as types
|
|
13
|
-
from mcp.server import NotificationOptions, Server
|
|
14
|
-
from mcp.server.models import InitializationOptions
|
|
15
|
-
from pydantic import AnyUrl
|
|
16
|
-
|
|
17
|
-
from . import __version__
|
|
18
|
-
from .resolve_client import DaVinciResolveClient, DaVinciResolveError
|
|
19
|
-
from .resources import get_all_resources
|
|
20
|
-
from .tools import get_all_tools
|
|
21
|
-
|
|
22
|
-
logger = logging.getLogger(__name__)
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
class DaVinciMCPServer:
|
|
26
|
-
"""
|
|
27
|
-
DaVinci Resolve MCP Server.
|
|
28
|
-
|
|
29
|
-
Provides a clean interface between MCP clients and DaVinci Resolve
|
|
30
|
-
through organized tools and resources.
|
|
31
|
-
"""
|
|
32
|
-
|
|
33
|
-
def __init__(self) -> None:
|
|
34
|
-
self.server = Server("davinci-resolve-mcp")
|
|
35
|
-
self.resolve_client = DaVinciResolveClient()
|
|
36
|
-
self._register_handlers()
|
|
37
|
-
|
|
38
|
-
def _register_handlers(self) -> None:
|
|
39
|
-
"""Register MCP server handlers."""
|
|
40
|
-
|
|
41
|
-
@self.server.list_tools()
|
|
42
|
-
async def handle_list_tools() -> list[types.Tool]: # type: ignore[reportUnusedFunction]
|
|
43
|
-
return get_all_tools()
|
|
44
|
-
|
|
45
|
-
@self.server.call_tool()
|
|
46
|
-
async def handle_call_tool( # type: ignore[reportUnusedFunction]
|
|
47
|
-
name: str, arguments: dict[str, Any] | None = None
|
|
48
|
-
) -> list[types.TextContent]:
|
|
49
|
-
if arguments is None:
|
|
50
|
-
arguments = {}
|
|
51
|
-
try:
|
|
52
|
-
if not self.resolve_client.is_connected():
|
|
53
|
-
self.resolve_client.connect()
|
|
54
|
-
result = await self._call_tool(name, arguments)
|
|
55
|
-
return [types.TextContent(type="text", text=str(result))]
|
|
56
|
-
except DaVinciResolveError as e:
|
|
57
|
-
error_msg = f"DaVinci Resolve error: {e}"
|
|
58
|
-
logger.exception(error_msg)
|
|
59
|
-
return [types.TextContent(type="text", text=error_msg)]
|
|
60
|
-
except Exception as e:
|
|
61
|
-
error_msg = f"Unexpected error: {e}"
|
|
62
|
-
logger.exception(error_msg)
|
|
63
|
-
return [types.TextContent(type="text", text=error_msg)]
|
|
64
|
-
|
|
65
|
-
@self.server.list_resources()
|
|
66
|
-
async def handle_list_resources() -> list[types.Resource]: # type: ignore[reportUnusedFunction]
|
|
67
|
-
return get_all_resources()
|
|
68
|
-
|
|
69
|
-
@self.server.read_resource()
|
|
70
|
-
async def handle_read_resource( # type: ignore[reportUnusedFunction]
|
|
71
|
-
uri: AnyUrl,
|
|
72
|
-
) -> str:
|
|
73
|
-
try:
|
|
74
|
-
if not self.resolve_client.is_connected():
|
|
75
|
-
self.resolve_client.connect()
|
|
76
|
-
result = await self._read_resource(str(uri))
|
|
77
|
-
return str(result)
|
|
78
|
-
except DaVinciResolveError as e:
|
|
79
|
-
error_msg = f"DaVinci Resolve error: {e}"
|
|
80
|
-
logger.exception(error_msg)
|
|
81
|
-
return error_msg
|
|
82
|
-
except Exception as e:
|
|
83
|
-
error_msg = f"Unexpected error: {e}"
|
|
84
|
-
logger.exception(error_msg)
|
|
85
|
-
return error_msg
|
|
86
|
-
|
|
87
|
-
async def _call_tool(self, name: str, arguments: dict[str, Any]) -> Any:
|
|
88
|
-
"""Dispatch a tool call to the resolve client."""
|
|
89
|
-
if name == "get_version":
|
|
90
|
-
return self.resolve_client.get_version()
|
|
91
|
-
elif name == "get_current_page":
|
|
92
|
-
return self.resolve_client.get_current_page()
|
|
93
|
-
elif name == "switch_page":
|
|
94
|
-
return self.resolve_client.switch_page(arguments.get("page", ""))
|
|
95
|
-
elif name == "list_projects":
|
|
96
|
-
return self.resolve_client.list_projects()
|
|
97
|
-
elif name == "get_current_project":
|
|
98
|
-
return self.resolve_client.get_current_project_name()
|
|
99
|
-
elif name == "open_project":
|
|
100
|
-
name_arg = arguments.get("name", "")
|
|
101
|
-
result = self.resolve_client.open_project(name_arg)
|
|
102
|
-
return (
|
|
103
|
-
f"Successfully opened project '{name_arg}'"
|
|
104
|
-
if result
|
|
105
|
-
else f"Failed to open project '{name_arg}'"
|
|
106
|
-
)
|
|
107
|
-
elif name == "create_project":
|
|
108
|
-
name_arg = arguments.get("name", "")
|
|
109
|
-
result = self.resolve_client.create_project(name_arg)
|
|
110
|
-
return (
|
|
111
|
-
f"Successfully created project '{name_arg}'"
|
|
112
|
-
if result
|
|
113
|
-
else f"Failed to create project '{name_arg}'"
|
|
114
|
-
)
|
|
115
|
-
elif name == "list_timelines":
|
|
116
|
-
return self.resolve_client.list_timelines()
|
|
117
|
-
elif name == "get_current_timeline":
|
|
118
|
-
return self.resolve_client.get_current_timeline_name()
|
|
119
|
-
elif name == "create_timeline":
|
|
120
|
-
name_arg = arguments.get("name", "")
|
|
121
|
-
result = self.resolve_client.create_timeline(name_arg)
|
|
122
|
-
return (
|
|
123
|
-
f"Successfully created timeline '{name_arg}'"
|
|
124
|
-
if result
|
|
125
|
-
else f"Failed to create timeline '{name_arg}'"
|
|
126
|
-
)
|
|
127
|
-
elif name == "switch_timeline":
|
|
128
|
-
name_arg = arguments.get("name", "")
|
|
129
|
-
result = self.resolve_client.switch_timeline(name_arg)
|
|
130
|
-
return (
|
|
131
|
-
f"Successfully switched to timeline '{name_arg}'"
|
|
132
|
-
if result
|
|
133
|
-
else f"Failed to switch to timeline '{name_arg}'"
|
|
134
|
-
)
|
|
135
|
-
elif name == "list_media_clips":
|
|
136
|
-
return self.resolve_client.list_media_clips()
|
|
137
|
-
elif name == "import_media":
|
|
138
|
-
file_path = arguments.get("file_path", "")
|
|
139
|
-
result = self.resolve_client.import_media(file_path)
|
|
140
|
-
return (
|
|
141
|
-
f"Successfully imported media '{file_path}'"
|
|
142
|
-
if result
|
|
143
|
-
else f"Failed to import media '{file_path}'"
|
|
144
|
-
)
|
|
145
|
-
else:
|
|
146
|
-
raise ValueError(f"Unknown tool: {name}")
|
|
147
|
-
|
|
148
|
-
async def _read_resource(self, uri: str) -> Any:
|
|
149
|
-
"""Dispatch a resource read to the resolve client."""
|
|
150
|
-
if uri == "resolve://version":
|
|
151
|
-
return self.resolve_client.get_version()
|
|
152
|
-
elif uri == "resolve://current-page":
|
|
153
|
-
return self.resolve_client.get_current_page()
|
|
154
|
-
elif uri == "resolve://projects":
|
|
155
|
-
return self.resolve_client.list_projects()
|
|
156
|
-
elif uri == "resolve://current-project":
|
|
157
|
-
name = self.resolve_client.get_current_project_name()
|
|
158
|
-
return name if name else "No project open"
|
|
159
|
-
elif uri == "resolve://timelines":
|
|
160
|
-
return self.resolve_client.list_timelines()
|
|
161
|
-
elif uri == "resolve://current-timeline":
|
|
162
|
-
name = self.resolve_client.get_current_timeline_name()
|
|
163
|
-
return name if name else "No timeline active"
|
|
164
|
-
elif uri == "resolve://media-clips":
|
|
165
|
-
return self.resolve_client.list_media_clips()
|
|
166
|
-
else:
|
|
167
|
-
raise ValueError(f"Unknown resource: {uri}")
|
|
168
|
-
|
|
169
|
-
async def run(self) -> None:
|
|
170
|
-
"""Run the MCP server."""
|
|
171
|
-
logger.info("Starting DaVinci Resolve MCP Server...")
|
|
172
|
-
|
|
173
|
-
async with mcp.server.stdio.stdio_server() as (read_stream, write_stream):
|
|
174
|
-
await self.server.run(
|
|
175
|
-
read_stream,
|
|
176
|
-
write_stream,
|
|
177
|
-
InitializationOptions(
|
|
178
|
-
server_name="davinci-mcp-professional",
|
|
179
|
-
server_version=__version__,
|
|
180
|
-
capabilities=self.server.get_capabilities(
|
|
181
|
-
notification_options=NotificationOptions(),
|
|
182
|
-
experimental_capabilities={},
|
|
183
|
-
),
|
|
184
|
-
),
|
|
185
|
-
)
|