davinci-resolve-mcp 2.63.2 → 2.65.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.
- package/CHANGELOG.md +81 -0
- package/README.md +1 -1
- package/docs/SKILL.md +8 -2
- package/docs/guides/media-analysis-guide.md +17 -0
- package/docs/install.md +23 -1
- package/install.py +30 -3
- package/package.json +1 -1
- package/scripts/doctor.py +73 -15
- package/src/analysis_dashboard.py +156 -18
- package/src/control_panel_i18n.py +780 -0
- package/src/granular/common.py +4 -3
- package/src/server.py +3 -2
- package/src/utils/media_analysis.py +146 -3
- package/src/utils/resolve_connection.py +46 -13
package/src/granular/common.py
CHANGED
|
@@ -44,6 +44,7 @@ from src.utils.layout_presets import (
|
|
|
44
44
|
)
|
|
45
45
|
from src.utils.object_inspection import inspect_object, print_object_help
|
|
46
46
|
from src.utils.platform import get_platform, get_resolve_paths
|
|
47
|
+
from src.utils.resolve_connection import connect_resolve
|
|
47
48
|
from src.utils.project_properties import (
|
|
48
49
|
get_all_project_properties,
|
|
49
50
|
get_color_settings,
|
|
@@ -80,7 +81,7 @@ if not logging.getLogger().handlers:
|
|
|
80
81
|
handlers=[logging.StreamHandler()],
|
|
81
82
|
)
|
|
82
83
|
|
|
83
|
-
VERSION = "2.
|
|
84
|
+
VERSION = "2.65.0"
|
|
84
85
|
logger = logging.getLogger("davinci-resolve-mcp")
|
|
85
86
|
logger.info(f"Starting DaVinci Resolve MCP Server v{VERSION}")
|
|
86
87
|
logger.info(f"Detected platform: {get_platform()}")
|
|
@@ -233,7 +234,7 @@ dvr_script = None
|
|
|
233
234
|
try:
|
|
234
235
|
import DaVinciResolveScript as dvr_script # type: ignore
|
|
235
236
|
|
|
236
|
-
resolve = dvr_script
|
|
237
|
+
resolve = connect_resolve(dvr_script)
|
|
237
238
|
if resolve:
|
|
238
239
|
logger.info(
|
|
239
240
|
f"Connected to DaVinci Resolve: {resolve.GetProductName()} {resolve.GetVersionString()}"
|
|
@@ -311,7 +312,7 @@ def _try_connect():
|
|
|
311
312
|
"""Attempt to connect to Resolve once. Returns resolve object or None."""
|
|
312
313
|
global resolve
|
|
313
314
|
try:
|
|
314
|
-
candidate = dvr_script
|
|
315
|
+
candidate = connect_resolve(dvr_script)
|
|
315
316
|
if candidate and _is_resolve_handle_live(candidate):
|
|
316
317
|
resolve = candidate
|
|
317
318
|
logger.info(f"Connected: {resolve.GetProductName()} {resolve.GetVersionString()}")
|
package/src/server.py
CHANGED
|
@@ -11,7 +11,7 @@ Usage:
|
|
|
11
11
|
python src/server.py --full # Start the 341-tool granular server instead
|
|
12
12
|
"""
|
|
13
13
|
|
|
14
|
-
VERSION = "2.
|
|
14
|
+
VERSION = "2.65.0"
|
|
15
15
|
|
|
16
16
|
import base64
|
|
17
17
|
import os
|
|
@@ -97,6 +97,7 @@ from src.utils.media_analysis_jobs import (
|
|
|
97
97
|
run_batch_job_slice as run_media_analysis_batch_job_slice,
|
|
98
98
|
)
|
|
99
99
|
from src.utils.platform import get_resolve_paths, get_resolve_plugin_paths
|
|
100
|
+
from src.utils.resolve_connection import connect_resolve
|
|
100
101
|
from src.utils.lut_paths import master_lut_dir, ensure_lut_in_master
|
|
101
102
|
from src.utils import fuse_templates, dctl_templates, script_templates
|
|
102
103
|
from src.utils.timeline_title_text import (
|
|
@@ -804,7 +805,7 @@ def _try_connect():
|
|
|
804
805
|
if dvr_script is None:
|
|
805
806
|
return None
|
|
806
807
|
try:
|
|
807
|
-
candidate = dvr_script
|
|
808
|
+
candidate = connect_resolve(dvr_script)
|
|
808
809
|
if candidate and _is_resolve_handle_live(candidate):
|
|
809
810
|
resolve = candidate
|
|
810
811
|
logger.info(f"Connected: {resolve.GetProductName()} {resolve.GetVersionString()}")
|
|
@@ -22,6 +22,8 @@ import subprocess
|
|
|
22
22
|
import sys
|
|
23
23
|
import threading
|
|
24
24
|
import time
|
|
25
|
+
import urllib.error
|
|
26
|
+
import urllib.request
|
|
25
27
|
from datetime import datetime, timezone
|
|
26
28
|
from pathlib import Path
|
|
27
29
|
from typing import Any, Callable, Dict, Iterable, List, Optional, Tuple
|
|
@@ -354,6 +356,9 @@ _ensure_path_includes_standard_tool_dirs()
|
|
|
354
356
|
ANALYSIS_DIR_NAME = "davinci-resolve-mcp-analysis"
|
|
355
357
|
HIDDEN_ANALYSIS_DIR_NAME = ".davinci-resolve-mcp-analysis"
|
|
356
358
|
ANALYSIS_VERSION = "0.2"
|
|
359
|
+
|
|
360
|
+
MLX_AUDIO_ROUTER_URL_ENV = "DAVINCI_RESOLVE_MCP_MLX_AUDIO_URL"
|
|
361
|
+
MLX_AUDIO_ROUTER_MODEL_ENV = "DAVINCI_RESOLVE_MCP_MLX_AUDIO_MODEL"
|
|
357
362
|
ANALYSIS_INDEX_FILENAME = "index.sqlite"
|
|
358
363
|
ANALYSIS_REGISTRY_FILENAME = "analysis_registry.json"
|
|
359
364
|
ANALYSIS_INDEX_SCHEMA_VERSION = 1
|
|
@@ -1606,6 +1611,49 @@ def install_plan_for(tool_name: str, platform_id: Optional[str] = None) -> Dict[
|
|
|
1606
1611
|
}
|
|
1607
1612
|
|
|
1608
1613
|
|
|
1614
|
+
def _detect_mlx_audio_router(env: Dict[str, str]) -> Dict[str, Any]:
|
|
1615
|
+
router_url = (env.get(MLX_AUDIO_ROUTER_URL_ENV) or "").strip().rstrip("/")
|
|
1616
|
+
model = (env.get(MLX_AUDIO_ROUTER_MODEL_ENV) or "").strip() or None
|
|
1617
|
+
if not router_url:
|
|
1618
|
+
return {
|
|
1619
|
+
"available": False,
|
|
1620
|
+
"configured": False,
|
|
1621
|
+
"url_env": MLX_AUDIO_ROUTER_URL_ENV,
|
|
1622
|
+
"model_env": MLX_AUDIO_ROUTER_MODEL_ENV,
|
|
1623
|
+
}
|
|
1624
|
+
if not router_url.startswith(("http://", "https://")):
|
|
1625
|
+
return {
|
|
1626
|
+
"available": False,
|
|
1627
|
+
"configured": True,
|
|
1628
|
+
"url": router_url,
|
|
1629
|
+
"model": model,
|
|
1630
|
+
"error": f"{MLX_AUDIO_ROUTER_URL_ENV} must use http:// or https://",
|
|
1631
|
+
}
|
|
1632
|
+
|
|
1633
|
+
try:
|
|
1634
|
+
request = urllib.request.Request(f"{router_url}/health", method="GET")
|
|
1635
|
+
with urllib.request.urlopen(request, timeout=1.0) as response:
|
|
1636
|
+
payload = json.loads(response.read().decode("utf-8"))
|
|
1637
|
+
if payload.get("status") != "ok":
|
|
1638
|
+
raise ValueError("health response status is not 'ok'")
|
|
1639
|
+
except (OSError, ValueError) as exc:
|
|
1640
|
+
return {
|
|
1641
|
+
"available": False,
|
|
1642
|
+
"configured": True,
|
|
1643
|
+
"url": router_url,
|
|
1644
|
+
"model": model,
|
|
1645
|
+
"error": str(exc),
|
|
1646
|
+
}
|
|
1647
|
+
|
|
1648
|
+
return {
|
|
1649
|
+
"available": True,
|
|
1650
|
+
"configured": True,
|
|
1651
|
+
"url": router_url,
|
|
1652
|
+
"model": model,
|
|
1653
|
+
"api_version": payload.get("api_version"),
|
|
1654
|
+
}
|
|
1655
|
+
|
|
1656
|
+
|
|
1609
1657
|
def detect_capabilities(env: Optional[Dict[str, str]] = None) -> Dict[str, Any]:
|
|
1610
1658
|
"""Detect available analysis helpers without installing or downloading."""
|
|
1611
1659
|
env = env if env is not None else os.environ
|
|
@@ -1618,6 +1666,7 @@ def detect_capabilities(env: Optional[Dict[str, str]] = None) -> Dict[str, Any]:
|
|
|
1618
1666
|
mlx_whisper = importlib.util.find_spec("mlx_whisper") is not None
|
|
1619
1667
|
cv2 = importlib.util.find_spec("cv2") is not None
|
|
1620
1668
|
provider = env.get("DAVINCI_RESOLVE_MCP_VISION_PROVIDER")
|
|
1669
|
+
mlx_audio_router = _detect_mlx_audio_router(env)
|
|
1621
1670
|
|
|
1622
1671
|
sync_events = detect_sync_event_capabilities()
|
|
1623
1672
|
|
|
@@ -1653,6 +1702,7 @@ def detect_capabilities(env: Optional[Dict[str, str]] = None) -> Dict[str, Any]:
|
|
|
1653
1702
|
"whisper_cli": _tool_entry("whisper_cli", bool(whisper_cli), {"path": whisper_cli}),
|
|
1654
1703
|
"whisper_cpp": _tool_entry("whisper_cpp", bool(whisper_cpp), {"path": whisper_cpp}),
|
|
1655
1704
|
"mlx_whisper": _tool_entry("mlx_whisper", bool(mlx_whisper), {"python_module": "mlx_whisper"}),
|
|
1705
|
+
"mlx_audio_router": mlx_audio_router,
|
|
1656
1706
|
"opencv": _tool_entry("opencv", bool(cv2), {"python_module": "cv2"}),
|
|
1657
1707
|
"ollama_embeddings": _tool_entry(
|
|
1658
1708
|
"ollama_embeddings",
|
|
@@ -1672,9 +1722,10 @@ def detect_capabilities(env: Optional[Dict[str, str]] = None) -> Dict[str, Any]:
|
|
|
1672
1722
|
},
|
|
1673
1723
|
"embeddings": embedding_caps,
|
|
1674
1724
|
"transcription": {
|
|
1675
|
-
"available": bool(whisper_cli or whisper_cpp or mlx_whisper),
|
|
1725
|
+
"available": bool(mlx_audio_router["available"] or whisper_cli or whisper_cpp or mlx_whisper),
|
|
1676
1726
|
"backends": [
|
|
1677
1727
|
name for name, available in (
|
|
1728
|
+
("mlx_audio_router", mlx_audio_router["available"]),
|
|
1678
1729
|
("whisper_cli", bool(whisper_cli)),
|
|
1679
1730
|
("whisper_cpp", bool(whisper_cpp)),
|
|
1680
1731
|
("mlx_whisper", bool(mlx_whisper)),
|
|
@@ -1730,12 +1781,13 @@ def install_guidance(capabilities: Optional[Dict[str, Any]] = None) -> Dict[str,
|
|
|
1730
1781
|
missing["transcription"] = {
|
|
1731
1782
|
"required_for": ["transcription analysis", "default Resolve media analysis"],
|
|
1732
1783
|
"options": [
|
|
1784
|
+
f"Configure an MLX Audio Router with {MLX_AUDIO_ROUTER_URL_ENV}",
|
|
1733
1785
|
"Install/configure whisper CLI",
|
|
1734
1786
|
"Install/configure whisper-cpp",
|
|
1735
1787
|
"Install mlx-whisper on supported Apple Silicon systems",
|
|
1736
1788
|
],
|
|
1737
1789
|
"macos": "Ask the user before running: brew install whisper-cpp, or configure another supported local Whisper backend.",
|
|
1738
|
-
"note": "The MCP server must not install
|
|
1790
|
+
"note": "The MCP server must not install backends or download model files automatically.",
|
|
1739
1791
|
}
|
|
1740
1792
|
if not tools.get("opencv", {}).get("available"):
|
|
1741
1793
|
missing["opencv"] = {
|
|
@@ -3934,6 +3986,95 @@ def _transcribe_with_mlx_whisper(path: str, artifacts: Dict[str, Any], transcrip
|
|
|
3934
3986
|
return payload
|
|
3935
3987
|
|
|
3936
3988
|
|
|
3989
|
+
def _transcribe_with_mlx_audio_router(
|
|
3990
|
+
path: str,
|
|
3991
|
+
artifacts: Dict[str, Any],
|
|
3992
|
+
transcription: Dict[str, Any],
|
|
3993
|
+
) -> Dict[str, Any]:
|
|
3994
|
+
router_url = str(
|
|
3995
|
+
transcription.get("router_url")
|
|
3996
|
+
or os.environ.get(MLX_AUDIO_ROUTER_URL_ENV)
|
|
3997
|
+
or ""
|
|
3998
|
+
).strip().rstrip("/")
|
|
3999
|
+
if not router_url:
|
|
4000
|
+
return {
|
|
4001
|
+
"success": False,
|
|
4002
|
+
"status": "skipped",
|
|
4003
|
+
"backend": "mlx_audio_router",
|
|
4004
|
+
"reason": f"Set {MLX_AUDIO_ROUTER_URL_ENV} to the MLX Audio Router base URL.",
|
|
4005
|
+
}
|
|
4006
|
+
|
|
4007
|
+
model = str(
|
|
4008
|
+
transcription.get("model")
|
|
4009
|
+
or os.environ.get(MLX_AUDIO_ROUTER_MODEL_ENV)
|
|
4010
|
+
or ""
|
|
4011
|
+
).strip()
|
|
4012
|
+
transcript_json = artifacts.get("transcript_json") or artifacts["analysis_json"]
|
|
4013
|
+
output_base = os.path.splitext(transcript_json)[0]
|
|
4014
|
+
request_payload = {
|
|
4015
|
+
"provider": "mlx",
|
|
4016
|
+
"audio": path,
|
|
4017
|
+
"output_path": output_base,
|
|
4018
|
+
"format": "json",
|
|
4019
|
+
"verbose": False,
|
|
4020
|
+
"allow_download": _coerce_bool(transcription.get("allow_model_download"), default=False),
|
|
4021
|
+
}
|
|
4022
|
+
if model:
|
|
4023
|
+
request_payload["model"] = model
|
|
4024
|
+
request = urllib.request.Request(
|
|
4025
|
+
f"{router_url}/stt",
|
|
4026
|
+
data=json.dumps(request_payload).encode("utf-8"),
|
|
4027
|
+
headers={"Content-Type": "application/json"},
|
|
4028
|
+
method="POST",
|
|
4029
|
+
)
|
|
4030
|
+
try:
|
|
4031
|
+
with urllib.request.urlopen(request, timeout=int(transcription.get("timeout", 1800))) as response:
|
|
4032
|
+
response_payload = json.loads(response.read().decode("utf-8"))
|
|
4033
|
+
except urllib.error.HTTPError as exc:
|
|
4034
|
+
detail = exc.read().decode("utf-8", errors="replace").strip()
|
|
4035
|
+
return {
|
|
4036
|
+
"success": False,
|
|
4037
|
+
"backend": "mlx_audio_router",
|
|
4038
|
+
"error": detail or f"MLX Audio Router returned HTTP {exc.code}",
|
|
4039
|
+
}
|
|
4040
|
+
except (OSError, ValueError) as exc:
|
|
4041
|
+
return {"success": False, "backend": "mlx_audio_router", "error": str(exc)}
|
|
4042
|
+
|
|
4043
|
+
if not isinstance(response_payload, dict):
|
|
4044
|
+
return {
|
|
4045
|
+
"success": False,
|
|
4046
|
+
"backend": "mlx_audio_router",
|
|
4047
|
+
"error": "MLX Audio Router response must be a JSON object.",
|
|
4048
|
+
}
|
|
4049
|
+
raw_transcript = response_payload.get("transcript")
|
|
4050
|
+
if not isinstance(raw_transcript, str) or not raw_transcript.strip():
|
|
4051
|
+
return {
|
|
4052
|
+
"success": False,
|
|
4053
|
+
"backend": "mlx_audio_router",
|
|
4054
|
+
"error": "MLX Audio Router response did not include a JSON transcript.",
|
|
4055
|
+
}
|
|
4056
|
+
try:
|
|
4057
|
+
raw = json.loads(raw_transcript)
|
|
4058
|
+
except json.JSONDecodeError as exc:
|
|
4059
|
+
return {
|
|
4060
|
+
"success": False,
|
|
4061
|
+
"backend": "mlx_audio_router",
|
|
4062
|
+
"error": f"MLX Audio Router transcript is not valid JSON: {exc}",
|
|
4063
|
+
}
|
|
4064
|
+
if not isinstance(raw, dict):
|
|
4065
|
+
return {
|
|
4066
|
+
"success": False,
|
|
4067
|
+
"backend": "mlx_audio_router",
|
|
4068
|
+
"error": "MLX Audio Router transcript JSON must be an object.",
|
|
4069
|
+
}
|
|
4070
|
+
|
|
4071
|
+
payload = _normalize_transcript_payload(raw, "mlx_audio_router", transcription.get("language"))
|
|
4072
|
+
if response_payload.get("model") or model:
|
|
4073
|
+
payload["model"] = response_payload.get("model") or model
|
|
4074
|
+
_write_transcript_artifacts(payload, artifacts)
|
|
4075
|
+
return payload
|
|
4076
|
+
|
|
4077
|
+
|
|
3937
4078
|
def _transcribe(path: str, artifacts: Dict[str, Any], options: Dict[str, Any], capabilities: Dict[str, Any]) -> Dict[str, Any]:
|
|
3938
4079
|
transcription = options.get("transcription") or {}
|
|
3939
4080
|
if not _coerce_bool(transcription.get("enabled"), default=DEFAULT_TRANSCRIPTION_ENABLED):
|
|
@@ -3975,6 +4116,8 @@ def _transcribe(path: str, artifacts: Dict[str, Any], options: Dict[str, Any], c
|
|
|
3975
4116
|
payload = {"success": True, "backend": backend, "language": transcription.get("language", "unknown"), "segments": segments, "text": " ".join(s.get("text", "") for s in segments)}
|
|
3976
4117
|
_write_transcript_artifacts(payload, artifacts)
|
|
3977
4118
|
return payload
|
|
4119
|
+
if backend == "mlx_audio_router":
|
|
4120
|
+
return _transcribe_with_mlx_audio_router(path, artifacts, transcription)
|
|
3978
4121
|
if backend in {"whisper_cli", "mlx_whisper"}:
|
|
3979
4122
|
if not _coerce_bool(transcription.get("allow_model_download"), default=False):
|
|
3980
4123
|
return {
|
|
@@ -4016,7 +4159,7 @@ def _transcribe(path: str, artifacts: Dict[str, Any], options: Dict[str, Any], c
|
|
|
4016
4159
|
# original branches below so behaviour stays identical for those.
|
|
4017
4160
|
if result is not None and result.get("status") != "fallthrough":
|
|
4018
4161
|
return result
|
|
4019
|
-
if backend in {"mock", "local_mock", "whisper_cli", "mlx_whisper"}:
|
|
4162
|
+
if backend in {"mock", "local_mock", "mlx_audio_router", "whisper_cli", "mlx_whisper"}:
|
|
4020
4163
|
return result if result is not None else {"success": False, "backend": backend}
|
|
4021
4164
|
elif backend == "whisper_cpp":
|
|
4022
4165
|
if not transcription.get("model_path"):
|
|
@@ -3,35 +3,66 @@
|
|
|
3
3
|
DaVinci Resolve Connection Utilities
|
|
4
4
|
"""
|
|
5
5
|
|
|
6
|
-
import os
|
|
7
6
|
import logging
|
|
7
|
+
import math
|
|
8
|
+
import os
|
|
9
|
+
|
|
8
10
|
from .platform import get_platform, get_resolve_paths, setup_environment
|
|
9
11
|
|
|
10
12
|
logger = logging.getLogger("davinci-resolve-mcp.connection")
|
|
11
13
|
|
|
14
|
+
DEFAULT_RESOLVE_SCRIPT_TIMEOUT = 5.0
|
|
15
|
+
|
|
16
|
+
|
|
17
|
+
def _network_timeout():
|
|
18
|
+
value = os.environ.get(
|
|
19
|
+
"RESOLVE_SCRIPT_TIMEOUT",
|
|
20
|
+
str(DEFAULT_RESOLVE_SCRIPT_TIMEOUT),
|
|
21
|
+
)
|
|
22
|
+
try:
|
|
23
|
+
timeout = float(value)
|
|
24
|
+
except ValueError as exc:
|
|
25
|
+
raise ValueError(
|
|
26
|
+
"RESOLVE_SCRIPT_TIMEOUT must be a positive finite number"
|
|
27
|
+
) from exc
|
|
28
|
+
if not math.isfinite(timeout) or timeout <= 0:
|
|
29
|
+
raise ValueError(
|
|
30
|
+
"RESOLVE_SCRIPT_TIMEOUT must be a positive finite number"
|
|
31
|
+
)
|
|
32
|
+
return timeout
|
|
33
|
+
|
|
34
|
+
|
|
35
|
+
def connect_resolve(dvr_script):
|
|
36
|
+
"""Create a Resolve handle, optionally targeting an explicit network host."""
|
|
37
|
+
host = os.environ.get("RESOLVE_SCRIPT_HOST")
|
|
38
|
+
if host:
|
|
39
|
+
return dvr_script.scriptapp("Resolve", host, _network_timeout())
|
|
40
|
+
return dvr_script.scriptapp("Resolve")
|
|
41
|
+
|
|
42
|
+
|
|
12
43
|
def initialize_resolve():
|
|
13
44
|
"""Initialize connection to DaVinci Resolve application."""
|
|
14
45
|
try:
|
|
15
46
|
# Import the DaVinci Resolve scripting module
|
|
16
47
|
import DaVinciResolveScript as dvr_script
|
|
17
|
-
|
|
48
|
+
|
|
18
49
|
# Get the resolve object
|
|
19
|
-
resolve = dvr_script
|
|
20
|
-
|
|
50
|
+
resolve = connect_resolve(dvr_script)
|
|
51
|
+
|
|
21
52
|
if resolve is None:
|
|
22
53
|
logger.error("Failed to get Resolve object. Is DaVinci Resolve running?")
|
|
23
54
|
return None
|
|
24
|
-
|
|
55
|
+
|
|
25
56
|
logger.info(f"Connected to DaVinci Resolve: {resolve.GetProductName()} {resolve.GetVersionString()}")
|
|
26
57
|
return resolve
|
|
27
|
-
|
|
58
|
+
|
|
28
59
|
except ImportError:
|
|
29
60
|
platform_name = get_platform()
|
|
30
61
|
paths = get_resolve_paths()
|
|
31
|
-
|
|
62
|
+
|
|
32
63
|
logger.error("Failed to import DaVinciResolveScript. Check environment variables.")
|
|
33
64
|
logger.error("RESOLVE_SCRIPT_API, RESOLVE_SCRIPT_LIB, and PYTHONPATH must be set correctly.")
|
|
34
|
-
|
|
65
|
+
|
|
35
66
|
if platform_name == 'darwin':
|
|
36
67
|
logger.error("On macOS, typically:")
|
|
37
68
|
logger.error(f'export RESOLVE_SCRIPT_API="{paths["api_path"]}"')
|
|
@@ -47,24 +78,25 @@ def initialize_resolve():
|
|
|
47
78
|
logger.error(f'export RESOLVE_SCRIPT_API="{paths["api_path"]}"')
|
|
48
79
|
logger.error(f'export RESOLVE_SCRIPT_LIB="{paths["lib_path"]}"')
|
|
49
80
|
logger.error(f'export PYTHONPATH="$PYTHONPATH:{paths["modules_path"]}"')
|
|
50
|
-
|
|
81
|
+
|
|
51
82
|
return None
|
|
52
|
-
|
|
83
|
+
|
|
53
84
|
except Exception as e:
|
|
54
85
|
logger.error(f"Unexpected error initializing Resolve: {str(e)}")
|
|
55
86
|
return None
|
|
56
87
|
|
|
88
|
+
|
|
57
89
|
def check_environment_variables():
|
|
58
90
|
"""Check if the required environment variables are set."""
|
|
59
91
|
resolve_script_api = os.environ.get("RESOLVE_SCRIPT_API")
|
|
60
92
|
resolve_script_lib = os.environ.get("RESOLVE_SCRIPT_LIB")
|
|
61
|
-
|
|
93
|
+
|
|
62
94
|
missing_vars = []
|
|
63
95
|
if not resolve_script_api:
|
|
64
96
|
missing_vars.append("RESOLVE_SCRIPT_API")
|
|
65
97
|
if not resolve_script_lib:
|
|
66
98
|
missing_vars.append("RESOLVE_SCRIPT_LIB")
|
|
67
|
-
|
|
99
|
+
|
|
68
100
|
return {
|
|
69
101
|
"all_set": len(missing_vars) == 0,
|
|
70
102
|
"missing": missing_vars,
|
|
@@ -72,6 +104,7 @@ def check_environment_variables():
|
|
|
72
104
|
"resolve_script_lib": resolve_script_lib
|
|
73
105
|
}
|
|
74
106
|
|
|
107
|
+
|
|
75
108
|
def set_default_environment_variables():
|
|
76
109
|
"""Set the default environment variables based on platform."""
|
|
77
|
-
return setup_environment()
|
|
110
|
+
return setup_environment()
|