""" JIANGCHANG_* 数据根与用户目录:解析规则 + 可选本地 CLI 默认值。 各技能 scripts/jiangchang_skill_core/ 为发布用副本,与 kit 保持同步。 """ from __future__ import annotations import os import sys # 发版/嵌入宿主前改为 False,或仅通过环境变量 JIANGCHANG_CLI_LOCAL_DEV=1 开启 CLI_LOCAL_DEV_ENABLED = True # 本地开发且未设置 JIANGCHANG_USER_ID 时注入(与宿主约定一致即可修改) DEFAULT_LOCAL_USER_ID = "10032" # Windows 下未设置 JIANGCHANG_DATA_ROOT 时的默认盘路径 WIN_DEFAULT_DATA_ROOT = r"D:\jiangchang-data" # 匠厂桌面宿主应用根(未设置 JIANGCHANG_APP_ROOT 时 Windows 兜底;技能一般在 {APP}/skills/ 下并列) WIN_DEFAULT_JIANGCHANG_APP_ROOT = r"D:\AI\jiangchang" def platform_default_data_root() -> str: if sys.platform == "win32": return WIN_DEFAULT_DATA_ROOT return os.path.join(os.path.expanduser("~"), ".jiangchang-data") def get_data_root() -> str: env = (os.getenv("JIANGCHANG_DATA_ROOT") or "").strip() if env: return env return platform_default_data_root() def get_user_id() -> str: return (os.getenv("JIANGCHANG_USER_ID") or "").strip() or "_anon" def _looks_like_skills_root(path: str) -> bool: if not path or not os.path.isdir(path): return False for marker in ( "llm-manager", "content-manager", "account-manager", "sohu-publisher", "api-key-vault", ): if os.path.isdir(os.path.join(path, marker)): return True return False def get_skills_root() -> str: """ 并列技能安装目录(其下为「技能 slug」子目录)。 优先级: 1) JIANGCHANG_SKILLS_ROOT 2) CLAW_SKILLS_ROOT 3) JIANGCHANG_APP_ROOT:若 {APP}/skills 存在且像技能根则用之;否则若 APP 下已有技能子目录则 APP 即根 4) Windows:默认 D:\\AI\\jiangchang 同上规则 5) 其他平台:~/.openclaw/skills """ for key in ("JIANGCHANG_SKILLS_ROOT", "CLAW_SKILLS_ROOT"): v = (os.getenv(key) or "").strip() if v: return os.path.normpath(v) app = (os.getenv("JIANGCHANG_APP_ROOT") or "").strip() if sys.platform == "win32" and not app: app = WIN_DEFAULT_JIANGCHANG_APP_ROOT if app: nested = os.path.join(app, "skills") if _looks_like_skills_root(nested): return os.path.normpath(nested) if _looks_like_skills_root(app): return os.path.normpath(app) if sys.platform == "win32": nested = os.path.join(WIN_DEFAULT_JIANGCHANG_APP_ROOT, "skills") if _looks_like_skills_root(nested): return os.path.normpath(nested) if _looks_like_skills_root(WIN_DEFAULT_JIANGCHANG_APP_ROOT): return os.path.normpath(WIN_DEFAULT_JIANGCHANG_APP_ROOT) return os.path.normpath(os.path.join(os.path.expanduser("~"), ".openclaw", "skills")) def get_sibling_skills_root(skill_scripts_dir: str | None = None) -> str: """ 编排子进程调用兄弟技能时用:先根据本技能 scripts 目录推断并列根;若目录下能识别出兄弟技能 则用之(开发仓与安装目录均满足「技能根之上一级 = 并列根」), 避免全局 JIANGCHANG_SKILLS_ROOT / CLAW_SKILLS_ROOT 与当前检出不一致时错调兄弟进程。 推断失败时再读上述环境变量,最后回落 get_skills_root()。 """ if skill_scripts_dir: scripts = os.path.abspath(skill_scripts_dir) skill_root = os.path.dirname(scripts) inferred = os.path.dirname(skill_root) if _looks_like_skills_root(inferred): return os.path.normpath(inferred) for key in ("JIANGCHANG_SKILLS_ROOT", "CLAW_SKILLS_ROOT"): v = (os.getenv(key) or "").strip() if v: return os.path.normpath(v) return get_skills_root() def apply_cli_local_defaults() -> None: """ 在 CLI 最早阶段调用(main.py 在 import 业务包之前)。 宿主已设置 JIANGCHANG_* 时不会覆盖。 """ enabled = CLI_LOCAL_DEV_ENABLED if not enabled: v = (os.getenv("JIANGCHANG_CLI_LOCAL_DEV") or "").strip().lower() enabled = v in ("1", "true", "yes", "on") if not enabled: return if not (os.getenv("JIANGCHANG_DATA_ROOT") or "").strip(): os.environ["JIANGCHANG_DATA_ROOT"] = platform_default_data_root() if not (os.getenv("JIANGCHANG_USER_ID") or "").strip(): os.environ["JIANGCHANG_USER_ID"] = DEFAULT_LOCAL_USER_ID.strip()