From 7736ad68a01672d80ee5e3d4d90923369691335c Mon Sep 17 00:00:00 2001 From: Nick Shirokov Date: Thu, 7 May 2026 15:30:37 +0300 Subject: [PATCH] feat(switch): handle ${CLAUDE_SKILL_DIR} for non-Claude targets MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit After SKILL.md refactor, paths use ${CLAUDE_SKILL_DIR} which Claude Code substitutes natively. Other agents (Cursor, Codex, Copilot, etc.) don't know about this variable, so switch.py now expands it to a literal path when the target is not claude-code: ${CLAUDE_SKILL_DIR}/ -> // ${CLAUDE_SKILL_DIR}/..// -> // For claude-code target the variable is left intact — drop-in install via copy still works because Claude Code resolves it identically in project, personal, and plugin scopes. Verified by running: python scripts/switch.py codex --project-dir python scripts/switch.py claude-code --project-dir Both produce correct output with 0 leftover variable literals in non-Claude targets and full preservation in Claude target. Co-Authored-By: Claude Opus 4.7 (1M context) --- scripts/switch.py | 28 +++++++++++++++++++++++----- 1 file changed, 23 insertions(+), 5 deletions(-) diff --git a/scripts/switch.py b/scripts/switch.py index 4c74b497..f559fa17 100644 --- a/scripts/switch.py +++ b/scripts/switch.py @@ -1,5 +1,5 @@ #!/usr/bin/env python3 -# switch.py v1.3 — Переключение навыков 1С между AI-платформами и рантаймами +# switch.py v1.4 — Переключение навыков 1С между AI-платформами и рантаймами # Source: https://github.com/Nikolay-Shirokov/cc-1c-skills """ Копирует (или создаёт ссылки на) навыки из .claude/skills/ на другие AI-платформы @@ -43,6 +43,11 @@ PLATFORMS = { SOURCE_PREFIX = '.claude/skills' +# ${CLAUDE_SKILL_DIR}/..// — cross-skill reference (more specific, match first) +RX_SKILL_DIR_CROSS = re.compile(r'\$\{CLAUDE_SKILL_DIR\}/\.\./([a-z][a-z0-9-]+)/') +# ${CLAUDE_SKILL_DIR}/ — same-skill reference +SKILL_DIR_VAR = '${CLAUDE_SKILL_DIR}/' + # Рекомендуемые записи для .gitignore целевого проекта GITIGNORE_RECOMMENDATIONS = [ '.v8-project.json', @@ -179,9 +184,22 @@ def is_different_dir(dir1, dir2): # --------------------------------------------------------------------------- # Transformations # --------------------------------------------------------------------------- -def rewrite_paths(content, source_prefix, target_prefix): - """Replace .claude/skills/ path prefix with target platform prefix.""" - return content.replace(source_prefix + '/', target_prefix + '/') +def rewrite_paths(content, platform, target_prefix, skill_name): + """Resolve ${CLAUDE_SKILL_DIR} placeholders to target platform prefix. + + For claude-code target, leave ${CLAUDE_SKILL_DIR} untouched — Claude Code + substitutes it natively at invocation time. For all other targets, + expand to a literal path: + ${CLAUDE_SKILL_DIR}/// + ${CLAUDE_SKILL_DIR}/..//// + """ + if platform == 'claude-code': + return content + # Cross-skill first (more specific pattern) + content = RX_SKILL_DIR_CROSS.sub(f'{target_prefix}/\\1/', content) + # Then same-skill + content = content.replace(SKILL_DIR_VAR, f'{target_prefix}/{skill_name}/') + return content def switch_runtime_content(content, target_runtime): @@ -305,7 +323,7 @@ def cmd_install(platform, runtime, project_dir): with open(md_path, 'r', encoding='utf-8') as f: content = f.read() - new_content = rewrite_paths(content, SOURCE_PREFIX, target_prefix) + new_content = rewrite_paths(content, platform, target_prefix, skill_name) # Apply runtime switch (skip for single-runtime skills # where target runtime is not available)