9f39a898c4
Observed live: a stale plugin-cache version dir (1.0.0) coexisted with the active one (1.1.0). setup.md's 'try the hardcoded version path first' advice picked the stale one, its --install-raw-git-hook flag failed silently, and Claude went on an unscripted forensic dig (chained test&&echo, --help probing, grep/cat across both version dirs, cat'ing plugin.json, stat'ing .in_use mtimes) to figure out which version was actually active. Fix, in both plugins' commands/setup.md: - Never hardcode a version number. Always do one bounded find -maxdepth 1 -type d first; disambiguate multiple hits via the .in_use marker Claude Code itself writes, falling back to highest plugin.json version. Explicitly rule out the exploration that happened here (stat/mtime, --help, reading source, diffing versions) since setup.sh has no --help and unrecognized flags just error. - Wire up the declared but previously-unused argument-hint ([repo-name] [repo-path] / [vault-path] [mode]): if the user already supplied it on the command line, skip asking the question that would just re-collect the same info.
134 lines
7.1 KiB
Markdown
134 lines
7.1 KiB
Markdown
---
|
|
description: Set up the git-manager skill (permissions whitelist, optional anti-chaining hook)
|
|
argument-hint: [repo-name] [repo-path]
|
|
---
|
|
|
|
Set up the `git-manager` skill. As part of the `git-manager` plugin, this
|
|
command is automatically namespaced by Claude Code and invoked as
|
|
`/git-manager:setup`.
|
|
|
|
Almost everything about this setup — reading/writing the skill's config,
|
|
merging permissions and the hook into settings.json, setting executable
|
|
bits — happens inside one bundled script, `scripts/setup.sh`, which you run
|
|
as a **single** Bash call. That script also copies the wrapper script(s) it
|
|
needs to a stable, self-controlled location
|
|
(`~/.agent-skills/git-manager/bin/`) before writing any permissions, so the
|
|
permission rule never has to change again across future plugin updates —
|
|
only this first run (and, optionally, a re-run after a plugin update) needs
|
|
to locate the plugin itself.
|
|
|
|
## 1. Ask the user — three selectable questions first, repo path last
|
|
|
|
**1a. Before asking anything, check for arguments.** This command's
|
|
`argument-hint` is `[repo-name] [repo-path]`. If the user invoked it with
|
|
both (e.g. `/git-manager:setup homelab-vault /home/hmk/projects/homelab`),
|
|
that already answers "whether to register a repo" and "which repo" — use
|
|
the given `name=path` pair directly as the `--repo` flag in step 2, and
|
|
skip both the "register any repos" option below and step 1c entirely,
|
|
without asking about either. If no arguments (or only one of the two) were
|
|
given, proceed normally: nothing here is decided yet, ask 1b and, if
|
|
needed, 1c below.
|
|
|
|
**1b. First turn: questions via the selection UI:**
|
|
- Whether to register any repos at all: yes/no. **Omit this question if
|
|
1a already determined a repo was given as an argument** — in that case
|
|
there's nothing to ask, it's already yes.
|
|
- Settings scope: `project` (`.claude/settings.json` in the current
|
|
project) or `user` (`~/.claude/settings.json`). Mention: if they work
|
|
across many separate repos/projects, `user` avoids repeating setup per
|
|
project.
|
|
- Anti-chaining hook: yes/no, after explaining it never silently blocks or
|
|
silently allows anything, it only forces the *normal* confirmation
|
|
prompt when a Bash command contains shell chaining operators (`&&`, `;`,
|
|
`|`, backticks, `$(...)`), as a safety net given Claude Code's Bash
|
|
allow-list matching has had bugs around compound commands (see
|
|
`hooks/force-ask-on-chaining.sh` for details).
|
|
- Ask-before-raw-git hook: yes/no, after explaining it never silently
|
|
blocks or silently allows anything either — it only forces the normal
|
|
confirmation prompt when a Bash command runs raw `git` instead of the
|
|
`git_cmd.sh` wrapper. It never fully blocks raw git (that stays a valid
|
|
fallback for subcommands the wrapper deliberately doesn't support, e.g.
|
|
`stash`/`merge`/`rebase`/`reset`, or for repos that aren't registered
|
|
yet) — it just makes sure raw git use is always a visible, confirmed
|
|
choice rather than something that slips through unnoticed (see
|
|
`hooks/force-ask-on-raw-git.sh` for details). Independent of the
|
|
anti-chaining hook — either, both, or neither can be installed.
|
|
|
|
**1c. Only if the answer to "register any repos" was yes AND 1a didn't
|
|
already supply a repo: a second turn, plain chat message, no tool call.**
|
|
Ask exactly: "Which repos should git-manager know about? Provide as
|
|
`name=path` pairs." End your turn right after asking this, with nothing
|
|
else queued up, so the user's reply is what actually gets collected before
|
|
you continue. (Only a tool call reliably pauses for a reply in this
|
|
environment; plain text followed immediately by a tool call in the same
|
|
turn does not wait — that's what caused this question to appear skipped in
|
|
an earlier version of this command.) Skip this sub-step entirely — don't
|
|
ask it at all — if the answer to "register any repos" was no, or if 1a
|
|
already supplied a repo.
|
|
|
|
## 2. Locate the plugin, then run the setup script — one command
|
|
|
|
Claude Code installs plugins added from a local marketplace at
|
|
`~/.claude/plugins/cache/<marketplace-name>/<plugin-name>/<plugin-version>/`.
|
|
**Never hardcode or guess a version number** — it changes on every release
|
|
of this plugin, and a stale directory from a previous version can still be
|
|
sitting on disk right alongside the current one (an old version won't
|
|
recognize newer flags like `--install-raw-git-hook`, so running it by
|
|
mistake fails in a confusing way). Always start with exactly one bounded,
|
|
read-only lookup instead:
|
|
|
|
```bash
|
|
find ~/.claude/plugins/cache/skill-repo/git-manager -maxdepth 1 -type d 2>/dev/null
|
|
```
|
|
|
|
- **Exactly one version directory found:** use it.
|
|
- **More than one found:** prefer whichever one contains a `.in_use`
|
|
marker file (Claude Code writes this into the currently-active version's
|
|
directory). If none of them has one, or more than one does, fall back to
|
|
whichever directory's `.claude-plugin/plugin.json` reports the highest
|
|
`version`. Don't disambiguate any other way — no `stat`/mtime
|
|
comparisons, no diffing scripts between versions, no probing with
|
|
`--help` (there is no `--help`; unrecognized flags just print `Error:
|
|
unknown argument`). That kind of exploration is exactly what this
|
|
bounded lookup exists to avoid.
|
|
- **None found:** the plugin likely isn't installed under this name or
|
|
marketplace — say so and stop rather than guessing at a different path.
|
|
|
|
Then run, as a **single** Bash call (no `test -f ... &&` pre-check, no
|
|
piping through `grep`/`head` to inspect it first):
|
|
|
|
```bash
|
|
~/.claude/plugins/cache/skill-repo/git-manager/<version>/scripts/setup.sh \
|
|
--settings-scope <project|user> \
|
|
[--project-dir <path>] \
|
|
[--repo <name>=<path> ...] \
|
|
[--install-hook] \
|
|
[--install-raw-git-hook]
|
|
```
|
|
|
|
Include `--repo name=path` once per repo from step 1, `--install-hook` and
|
|
`--install-raw-git-hook` only for the ones the user opted into (they're
|
|
independent flags), and `--project-dir` only if `--settings-scope
|
|
project` and the project isn't the current working directory. If this one
|
|
call errors, that means the version picked above was wrong — re-run the
|
|
`find` above (and re-check `.in_use`/`plugin.json`) rather than falling
|
|
back to reading source files or trying more flags. This is expected to
|
|
prompt for approval the first time — there's no way to pre-whitelist it
|
|
before the setup that establishes the whitelist has run.
|
|
|
|
## 3. Relay the result
|
|
|
|
The script prints a JSON summary (stable script location, settings file
|
|
written, config file, whether the hook was installed, repos registered,
|
|
the exact permission rules added, and a note about session reload).
|
|
Present that summary to the user in plain language — don't re-read any of
|
|
those files yourself to "double check"; the script's own output already
|
|
reflects exactly what's on disk.
|
|
|
|
Do **not** follow this with a test invocation of `git_cmd.sh` — Claude Code
|
|
loads permissions at session start and doesn't always pick up changes made
|
|
by its own file edits within the same session, so an immediate test can
|
|
prompt (or not) in a way that doesn't reliably indicate success either way.
|
|
If a real command later still prompts, the fix is a fresh session, not
|
|
re-running this setup — the configuration is already correctly saved.
|