@@ -40,7 +40,7 @@ def render_bundle(
4040 if spec .automation .bootstrap_cluster :
4141 manifest_paths .extend (render_cluster_bootstrap (spec , resolved , out_root ))
4242 elif spec .uses_single_machine :
43- manifest_paths = _render_single_machine (spec , out_root , resolved )
43+ manifest_paths = _render_single_machine (spec , workspace , out_root , resolved )
4444 else :
4545 manifest_paths = _render_private (spec , workspace , out_root , resolved )
4646
@@ -55,6 +55,12 @@ def _render_kubernetes(
5555) -> list [Path ]:
5656 include_mcp_service = spec .runtime .mcp .mode == "service"
5757 campaign_image , mcp_image = resolve_images (spec , workspace )
58+ mcp_allowed_hosts = "," .join (
59+ _allowed_hosts_with_port_variants (
60+ hosts = resolved .allowed_hosts ,
61+ port = spec .runtime .mcp .port ,
62+ )
63+ )
5864 k8s_dir = out_root / "kubernetes"
5965 k8s_dir .mkdir (parents = True , exist_ok = True )
6066
@@ -96,7 +102,7 @@ def _render_kubernetes(
96102 "REFUA_MCP_TRANSPORT" : spec .runtime .mcp .transport ,
97103 "REFUA_MCP_HOST" : "0.0.0.0" ,
98104 "REFUA_MCP_PORT" : str (spec .runtime .mcp .port ),
99- "REFUA_MCP_ALLOWED_HOSTS" : "," . join ( resolved . allowed_hosts ) ,
105+ "REFUA_MCP_ALLOWED_HOSTS" : mcp_allowed_hosts ,
100106 "REFUA_MCP_ALLOWED_ORIGINS" : "," .join (resolved .allowed_origins ),
101107 }
102108 )
@@ -191,7 +197,7 @@ def _render_kubernetes(
191197 },
192198 {
193199 "name" : "REFUA_MCP_ALLOWED_HOSTS" ,
194- "value" : "," . join ( resolved . allowed_hosts ) ,
200+ "value" : mcp_allowed_hosts ,
195201 },
196202 {
197203 "name" : "REFUA_MCP_ALLOWED_ORIGINS" ,
@@ -578,6 +584,7 @@ def _render_private(
578584
579585def _render_single_machine (
580586 spec : DeploymentSpec ,
587+ workspace : WorkspaceIntegration ,
581588 out_root : Path ,
582589 resolved : ResolvedAutomation ,
583590) -> list [Path ]:
@@ -591,26 +598,67 @@ def _render_single_machine(
591598 studio_path = single_dir / "run-studio.sh"
592599
593600 packages = ecosystem_packages ()
601+ workspace_root_default = str (workspace .root )
594602 install_lines = [
595603 "#!/usr/bin/env bash" ,
596604 "set -euo pipefail" ,
597605 "" ,
598606 'ROOT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"' ,
607+ f'WORKSPACE_ROOT="${{REFUA_ECOSYSTEM_WORKSPACE_ROOT:-{ workspace_root_default } }}"' ,
599608 'VENV_DIR="${VENV_DIR:-$ROOT_DIR/.venv-refua}"' ,
600- 'PYTHON_BIN="${PYTHON_BIN:-python3}"' ,
609+ 'if [[ -z "${PYTHON_BIN:-}" ]]; then' ,
610+ ' for _CANDIDATE in python3.12 python3.13 python3.11 python3; do' ,
611+ ' if command -v "$_CANDIDATE" >/dev/null 2>&1; then' ,
612+ ' PYTHON_BIN="$_CANDIDATE"' ,
613+ " break" ,
614+ " fi" ,
615+ " done" ,
616+ "fi" ,
617+ 'if [[ -z "${PYTHON_BIN:-}" ]]; then' ,
618+ ' echo "No python3 interpreter found. Install Python 3.12." >&2' ,
619+ " exit 1" ,
620+ "fi" ,
621+ (
622+ 'PYTHON_VERSION="$("$PYTHON_BIN" -c '
623+ '\' import sys; print("{}.{}".format('
624+ 'sys.version_info.major, sys.version_info.minor))\' )"'
625+ ),
626+ 'case "$PYTHON_VERSION" in' ,
627+ " 3.12) ;;" ,
628+ (
629+ ' *) echo "Unsupported Python version $PYTHON_VERSION. '
630+ 'Full ecosystem install currently requires Python 3.12." >&2; exit 1 ;;'
631+ ),
632+ "esac" ,
601633 "" ,
602634 '"$PYTHON_BIN" -m venv "$VENV_DIR"' ,
603635 '"$VENV_DIR/bin/python" -m pip install --upgrade pip' ,
604- '"$VENV_DIR/bin/python" -m pip install --upgrade \\ ' ,
605- * [f" { package_name } \\ " for package_name in packages [:- 1 ]],
606- f" { packages [- 1 ]} " ,
636+ "" ,
637+ "PACKAGES=(" ,
638+ * [f' "{ package_name } "' for package_name in packages ],
639+ ")" ,
640+ "" ,
641+ 'for PACKAGE_NAME in "${PACKAGES[@]}"; do' ,
642+ ' LOCAL_PACKAGE_PATH="$WORKSPACE_ROOT/$PACKAGE_NAME"' ,
643+ ' if [[ -f "$LOCAL_PACKAGE_PATH/pyproject.toml" ]]; then' ,
644+ ' "$VENV_DIR/bin/python" -m pip install --upgrade -e "$LOCAL_PACKAGE_PATH"' ,
645+ " else" ,
646+ ' "$VENV_DIR/bin/python" -m pip install --upgrade "$PACKAGE_NAME"' ,
647+ " fi" ,
648+ "done" ,
607649 "" ,
608650 'echo "Refua ecosystem installed in $VENV_DIR"' ,
651+ 'echo "Workspace root used for local editable installs: $WORKSPACE_ROOT"' ,
609652 'echo "Create .env from .env.template, then run ./run-studio.sh or ./run-campaign.sh"' ,
610653 ]
611654 _write_script (install_path , install_lines )
612655
613- mcp_allowed_hosts = "," .join (resolved .allowed_hosts )
656+ mcp_allowed_hosts = "," .join (
657+ _allowed_hosts_with_port_variants (
658+ hosts = resolved .allowed_hosts ,
659+ port = spec .runtime .mcp .port ,
660+ )
661+ )
614662 mcp_allowed_origins = "," .join (resolved .allowed_origins )
615663 campaign_objective_literal = json .dumps (spec .runtime .campaign .objective )
616664 env_template = "\n " .join (
@@ -785,6 +833,26 @@ def _gpu_container_env(spec: DeploymentSpec, *, enabled: bool) -> list[dict[str,
785833 return env
786834
787835
836+ def _allowed_hosts_with_port_variants (* , hosts : list [str ], port : int ) -> list [str ]:
837+ expanded : list [str ] = []
838+ seen : set [str ] = set ()
839+ for host in hosts :
840+ normalized = host .strip ()
841+ if not normalized :
842+ continue
843+
844+ candidates = [normalized ]
845+ if ":" not in normalized :
846+ candidates .append (f"{ normalized } :{ port } " )
847+
848+ for candidate in candidates :
849+ if candidate in seen :
850+ continue
851+ seen .add (candidate )
852+ expanded .append (candidate )
853+ return expanded
854+
855+
788856def _gpu_compose_env (spec : DeploymentSpec , * , enabled : bool ) -> dict [str , str ]:
789857 if not enabled or spec .gpu .mode == "off" :
790858 return {}
0 commit comments