Skip to content

fix(sc-git-worktree): global-safe installs via .local.j2 templating (#112) - #114

Open
randlee wants to merge 8 commits into
developfrom
fix/sc-git-worktree-dynamic-base-path
Open

randlee wants to merge 8 commits into
developfrom
fix/sc-git-worktree-dynamic-base-path

Conversation

@randlee

@randlee randlee commented Sep 23, 2026

Copy link
Copy Markdown
Owner

Summary

Fixes #112: the naive {{REPO_NAME}} install-time string-replace silently no-ops for global/user installs (since dest_dir.parent isn't a git repo there), leaking the literal token into shipped docs/commands.

  • Any package artifact (any category: commands, skills, agents, scripts, assets, plugin) with a sibling <path>.local.j2 file is rendered through sc-compose (auto-installed on first use) instead of copied verbatim, for local/project-style installs only. Global/user installs never consult .local.j2.
  • sc-git-worktree's docs (SKILL.md, commands/, agents/, README.md) now carry explicit runtime-derivation instructions (basename $(git rev-parse --show-toplevel)) instead of relying on install-time token substitution, so the package is safe to install globally.
  • Fixed sc-git-worktree's SKILL.md frontmatter name (sc-managing-worktreessc-git-worktree) to match its directory and cross-references.
  • test_token_expansion_repo_name now exercises the legacy {{REPO_NAME}} mechanism via a synthetic fixture package, since sc-git-worktree itself no longer consumes it.

Also added: install.py prepare/complete/cleanup hooks (Tier 3)

A package root may optionally ship install.py defining prepare()/complete()/cleanup(), run once per install target (.claude/.codex) around the artifact-copy step, and once on uninstall. This covers repo-specific rendering, conditional cleanup of prior-version files, and anything .local.j2 can't (multiple templates, conditional logic, non-trivial failure messages).

  • New repeatable --set KEY=VALUE CLI flag (both install and uninstall) forwards arbitrary key/value pairs into options["args"]; sc-install itself never interprets these, only a package's own hook does. Lets a hook fail with an actionable message when it needs info sc-install has no generic way to know.
  • Every hook returns {"result": "success"} or {"result": "fail", "message": "<reason, instructions to fix>"}; anything else (exception, wrong shape) is treated as an sc-install-level bug, not a caller input error.
  • packages/sc-git-worktree/install.py is the first consumer: renders .j2 templates with the consuming repo's name for --local/--project installs when a repo is found, no-ops otherwise.
  • Full normative reference: src/sc_cli/README.md.
  • Documented across CONTRIBUTING.md, docs/MARKETPLACE-INFRASTRUCTURE.md, the marketplace skill's README/SKILL/TROUBLESHOOTING/USE-CASES, and marketplace-package-installer.md (Tier 3, not a manifest field — discovered by file presence).

Test plan

  • python3 -m pytest tests/ -q — 1403 passed
  • python3 scripts/validate-all.py — 9/9 validators passed

randlee and others added 6 commits September 23, 2026 12:26
{{REPO_NAME}} is a Tier 1 install-time substitution. When the skill is
globally installed (e.g. ~/.claude/skills/), the token gets baked in as
the install-time repo name and produces the wrong worktree base path in
all other repos.

Replace with a runtime instruction: derive repo name at execution time
via `basename $(git rev-parse --show-toplevel)`. This is portable and
correct regardless of where or how the skill is installed.

Changes:
- skills/sc-git-worktree/SKILL.md: dynamic runtime derivation
- agents/sc-git-worktree-update.md: same fix for default worktree_base
- commands/sc-git-worktree.md: same fix for both path references
- manifest.yaml: remove REPO_NAME variable (no longer consumed by any artifact)

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Codex CLI (~/.codex) only has a skills directory relevant to us and no
commands/agents concept, so a --codex install should skip commands,
agents, and registry.yaml maintenance entirely rather than mimicking
the ~/.claude layout.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
…ating

- --claude/--codex are now independent target flags under a scope
  (--global/--local/--user/--project), symmetric with each other: either
  alone installs only that target, neither installs both .claude and
  .codex. --dest remains a single, explicit .claude-only path and now
  rejects --codex outright instead of silently ignoring it.
- Installing to both targets shares one code path (_resolve_install_scope
  + _resolve_install_targets + a single install_target() closure) instead
  of duplicating the artifact-copy loop per target.
- Any artifact in any category with a sibling <path>.local.j2 file is
  rendered through sc-compose (auto-installed on first use) instead of
  copied verbatim, for any install that isn't --global/--user; .codex
  never consults .local.j2, matching --global/--user.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
…dex-target

# Conflicts:
#	src/sc_cli/install.py
)

- Any package artifact (any category) with a sibling <path>.local.j2 file
  is rendered through sc-compose (auto-installed on first use) instead of
  copied verbatim, for local/project-style installs only. Global/user
  installs never consult .local.j2, since install-time repo-specific
  customization isn't meaningful there.
- Fix sc-git-worktree's SKILL.md frontmatter name (sc-managing-worktrees ->
  sc-git-worktree) to match its directory and references.
- Close the last {{REPO_NAME}}-token gap in README.md: point at the
  runtime-derivation instructions already shipped in SKILL.md/commands/
  agents (basename $(git rev-parse --show-toplevel)) instead of the
  install-time token that silently no-ops for global installs (#112).
- Swap test_token_expansion_repo_name to a synthetic fixture package,
  since sc-git-worktree itself no longer consumes {{REPO_NAME}}.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
…-path' into feat/sc-install-codex-target

# Conflicts:
#	src/sc_cli/install.py
#	tests/test_sc_install_phase1_2.py
@randlee
randlee added this pull request to stack #115 September 23, 2026 21:47
@randlee
randlee removed this pull request from stack #115 September 23, 2026 22:09
randlee and others added 2 commits September 23, 2026 16:29
Packages may ship an optional install.py with prepare()/complete()/
cleanup() hooks, run around the artifact-copy step and on uninstall.
Adds --set KEY=VALUE (repeatable) so a hook can request info sc-install
has no generic way to know, failing with an actionable message when a
required value is missing. sc-git-worktree's install.py is the first
consumer, rendering .j2 templates with the repo name for local installs.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Covers the new Tier 3 install-time hook mechanism (prepare/complete/
cleanup, --set KEY=VALUE) in CONTRIBUTING.md, MARKETPLACE-INFRASTRUCTURE.md,
the marketplace skill's README/SKILL/TROUBLESHOOTING/USE-CASES, and the
marketplace-package-installer agent, pointing to src/sc_cli/README.md as
the normative reference.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>

This branch has not been deployed

No deployments
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant