diff --git a/src/octopal/runtime/workers/launcher.py b/src/octopal/runtime/workers/launcher.py index 631c380..f7dd5ef 100644 --- a/src/octopal/runtime/workers/launcher.py +++ b/src/octopal/runtime/workers/launcher.py @@ -8,6 +8,8 @@ from pathlib import Path from typing import Protocol +_WORKER_SHARED_WORKSPACE_DIRS = ("skills", ".skill-envs") + class WorkerLauncher(Protocol): async def launch( @@ -87,15 +89,21 @@ async def launch( host_ws_path = Path(self.host_workspace).resolve() seen_mounts: set[tuple[str, str]] = set() - host_skills_dir = host_ws_path / "skills" - host_skills_dir.mkdir(parents=True, exist_ok=True) - _prepare_worker_mount_target( - host_worker_dir, - rel_path="skills", - source_path=host_skills_dir, - ) - cmd_args.extend(["-v", f"{host_skills_dir}:{container_worker_dir}/skills"]) - seen_mounts.add((str(host_skills_dir), f"{container_worker_dir}/skills")) + for rel_path in _WORKER_SHARED_WORKSPACE_DIRS: + host_shared_dir = host_ws_path / rel_path + host_shared_dir.mkdir(parents=True, exist_ok=True) + _prepare_worker_mount_target( + host_worker_dir, + rel_path=rel_path, + source_path=host_shared_dir, + ) + mount_targets = ( + f"{container_ws}/{rel_path}", + f"{container_worker_dir}/{rel_path}", + ) + for mount_target in mount_targets: + cmd_args.extend(["-v", f"{host_shared_dir}:{mount_target}"]) + seen_mounts.add((str(host_shared_dir), mount_target)) for rel_path in allowed_paths or []: if not isinstance(rel_path, str) or not rel_path.strip(): continue diff --git a/tests/test_worker_launcher_isolation.py b/tests/test_worker_launcher_isolation.py index 6f07c0f..b445488 100644 --- a/tests/test_worker_launcher_isolation.py +++ b/tests/test_worker_launcher_isolation.py @@ -47,7 +47,10 @@ async def _fake_exec(*args, **kwargs): assert "--user" in args assert "1000:1000" in args assert f"{worker_dir}:/workspace/workers/worker-1" in args + assert f"{workspace / 'skills'}:/workspace/skills" in args assert f"{workspace / 'skills'}:/workspace/workers/worker-1/skills" in args + assert f"{workspace / '.skill-envs'}:/workspace/.skill-envs" in args + assert f"{workspace / '.skill-envs'}:/workspace/workers/worker-1/.skill-envs" in args assert "-e" in args assert "OCTOPAL_WORKSPACE_DIR=/workspace" in args assert "HOME=/workspace/workers/worker-1" in args @@ -93,7 +96,10 @@ async def _fake_exec(*args, **kwargs): assert "--user" in args assert "1000:1000" in args assert f"{worker_dir}:/workspace/workers/worker-1" in args + assert f"{workspace / 'skills'}:/workspace/skills" in args assert f"{workspace / 'skills'}:/workspace/workers/worker-1/skills" in args + assert f"{workspace / '.skill-envs'}:/workspace/.skill-envs" in args + assert f"{workspace / '.skill-envs'}:/workspace/workers/worker-1/.skill-envs" in args assert f"{shared_dir}:/workspace/src" in args assert f"{shared_dir}:/workspace/workers/worker-1/src" in args assert "OCTOPAL_WORKSPACE_DIR=/workspace" in args @@ -148,6 +154,7 @@ async def _fake_exec(*args, **kwargs): args = captured["args"] assert (worker_dir / "skills").is_dir() + assert (worker_dir / ".skill-envs").is_dir() assert (worker_dir / "memory" / "canon" / "facts.md").is_file() assert (worker_dir / "research" / "jobs").is_dir() assert f"{shared_file}:/workspace/workers/worker-1/memory/canon/facts.md" in args