fix(skills): use workspace path for sandbox skills

default sandbox skill paths to /workspace/skills/<name>/SKILL.md
when loading config and when exposing sandbox paths.
preserve cached sandbox paths when available to avoid losing
resolved locations for existing skills.
This commit is contained in:
RC-CHN
2026-02-27 14:08:59 +08:00
parent 4ff4c5f1bf
commit 13c8fa3f92
+22 -4
View File
@@ -20,6 +20,7 @@ SKILLS_CONFIG_FILENAME = "skills.json"
SANDBOX_SKILLS_CACHE_FILENAME = "sandbox_skills_cache.json" SANDBOX_SKILLS_CACHE_FILENAME = "sandbox_skills_cache.json"
DEFAULT_SKILLS_CONFIG: dict[str, dict] = {"skills": {}} DEFAULT_SKILLS_CONFIG: dict[str, dict] = {"skills": {}}
SANDBOX_SKILLS_ROOT = "skills" SANDBOX_SKILLS_ROOT = "skills"
SANDBOX_WORKSPACE_ROOT = "/workspace"
_SANDBOX_SKILLS_CACHE_VERSION = 1 _SANDBOX_SKILLS_CACHE_VERSION = 1
_SKILL_NAME_RE = re.compile(r"^[A-Za-z0-9._-]+$") _SKILL_NAME_RE = re.compile(r"^[A-Za-z0-9._-]+$")
@@ -185,7 +186,7 @@ class SkillManager:
description = str(item.get("description", "") or "") description = str(item.get("description", "") or "")
path = str(item.get("path", "") or "") path = str(item.get("path", "") or "")
if not path: if not path:
path = f"{SANDBOX_SKILLS_ROOT}/{name}/SKILL.md" path = f"{SANDBOX_WORKSPACE_ROOT}/{SANDBOX_SKILLS_ROOT}/{name}/SKILL.md"
deduped[name] = { deduped[name] = {
"name": name, "name": name,
"description": description, "description": description,
@@ -215,6 +216,17 @@ class SkillManager:
modified = False modified = False
skills_by_name: dict[str, SkillInfo] = {} skills_by_name: dict[str, SkillInfo] = {}
sandbox_cached_paths: dict[str, str] = {}
if runtime == "sandbox":
cache_for_paths = self._load_sandbox_skills_cache()
for item in cache_for_paths.get("skills", []):
if not isinstance(item, dict):
continue
name = str(item.get("name", "") or "").strip()
path = str(item.get("path", "") or "").strip().replace("\\", "/")
if name and path and _SKILL_NAME_RE.match(name):
sandbox_cached_paths[name] = path
for entry in sorted(Path(self.skills_root).iterdir()): for entry in sorted(Path(self.skills_root).iterdir()):
if not entry.is_dir(): if not entry.is_dir():
continue continue
@@ -235,7 +247,9 @@ class SkillManager:
except Exception: except Exception:
description = "" description = ""
if runtime == "sandbox" and show_sandbox_path: if runtime == "sandbox" and show_sandbox_path:
path_str = f"{SANDBOX_SKILLS_ROOT}/{skill_name}/SKILL.md" path_str = sandbox_cached_paths.get(skill_name) or (
f"{SANDBOX_WORKSPACE_ROOT}/{SANDBOX_SKILLS_ROOT}/{skill_name}/SKILL.md"
)
else: else:
path_str = str(skill_md) path_str = str(skill_md)
path_str = path_str.replace("\\", "/") path_str = path_str.replace("\\", "/")
@@ -266,11 +280,15 @@ class SkillManager:
continue continue
description = str(item.get("description", "") or "") description = str(item.get("description", "") or "")
if show_sandbox_path: if show_sandbox_path:
path_str = f"{SANDBOX_SKILLS_ROOT}/{skill_name}/SKILL.md" path_str = (
f"{SANDBOX_WORKSPACE_ROOT}/{SANDBOX_SKILLS_ROOT}/{skill_name}/SKILL.md"
)
else: else:
path_str = str(item.get("path", "") or "") path_str = str(item.get("path", "") or "")
if not path_str: if not path_str:
path_str = f"{SANDBOX_SKILLS_ROOT}/{skill_name}/SKILL.md" path_str = (
f"{SANDBOX_WORKSPACE_ROOT}/{SANDBOX_SKILLS_ROOT}/{skill_name}/SKILL.md"
)
skills_by_name[skill_name] = SkillInfo( skills_by_name[skill_name] = SkillInfo(
name=skill_name, name=skill_name,
description=description, description=description,