Fixed setups

This commit is contained in:
Henner M. Kruse
2026-08-04 11:15:24 +02:00
parent e485d33f00
commit 6c6fc35a1f
9 changed files with 609 additions and 288 deletions
+77 -118
View File
@@ -3,135 +3,94 @@ description: Set up the git-manager skill (permissions whitelist, optional anti-
argument-hint: [repo-name] [repo-path]
---
Set up the `git-manager` skill end to end. As part of the `git-manager`
plugin, this command is automatically namespaced by Claude Code and invoked
as `/git-manager:setup`. Follow these steps in order.
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`.
## 1. Determine the skill's install directory
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.
This plugin's `skills/git-manager/` is a symlink into the repo's
tool-neutral `skills/git-manager/` directory (the single source of truth
for `SKILL.md` and `scripts/`, shared across all vendor adapters in this
repo). Resolve it to its real, absolute, symlink-free path:
## 1. Ask the user — three selectable questions first, repo path last
**1a. First turn: three questions via the selection UI, fixed options for
all three:**
- Whether to register any repos at all: yes/no.
- 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).
**1b. Only if the answer to "register any repos" was yes: 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.) If the answer to "register any repos" was no, skip this
sub-step entirely — don't ask it at all.
## 2. 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>/`.
For this repo's marketplace (`skill-repo`) and this plugin's current
version (`1.0.0` — check this plugin's own `.claude-plugin/plugin.json` if
this has since changed), that's:
```bash
realpath <plugin-dir>/skills/git-manager
~/.claude/plugins/cache/skill-repo/git-manager/1.0.0/scripts/setup.sh \
--settings-scope <project|user> \
[--project-dir <path>] \
[--repo <name>=<path> ...] \
[--install-hook]
```
This resolved path is `<SKILL_DIR>` for the rest of this setup.
Include `--repo name=path` once per repo from step 1, `--install-hook` only
if the user opted in, and `--project-dir` only if `--settings-scope
project` and the project isn't the current working directory. Try this
path directly first — don't `find`/`ls` preemptively.
## 2. Optionally register named repos
If `$ARGUMENTS` contains a repo name and path, or the user wants to
pre-register repos now (e.g. an Obsidian vault repo used alongside a code
repo), write/merge them into
`~/.agent-skills/git-manager/config.json`:
If that exact path doesn't exist (installed version differs from `1.0.0`,
differently named marketplace, or a future Claude Code cache layout
change), fall back to exactly one bounded lookup instead of guessing
further:
```bash
mkdir -p ~/.agent-skills/git-manager
cat > ~/.agent-skills/git-manager/config.json << 'EOF'
{
"repos": [
{"name": "<short-name>", "path": "<absolute-repo-path>"}
]
}
EOF
find ~/.claude/plugins/cache/skill-repo/git-manager -maxdepth 2 -type d 2>/dev/null
```
If the file already exists, merge new entries in rather than overwriting.
This step is entirely optional — the skill works without any named repos,
operating on the current working directory by default.
and construct the same `scripts/setup.sh` call using whatever version
directory that reveals. 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. Generate and merge the minimal permissions whitelist
## 3. Relay the result
Exactly one command needs whitelisting — everything else about this skill's
safety comes from the wrapper script's own subcommand allowlist and repo
resolution, not from a long list of Bash rules:
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.
- `Bash(<SKILL_DIR>/scripts/git_cmd.sh:*)`
- `Read(~/.agent-skills/git-manager/config.json)`
Steps:
1. Locate the target settings file: prefer the project-level
`.claude/settings.json` if a project is open, otherwise the user-level
`~/.claude/settings.json`. Ask the user which one they want if unclear —
note that if they work across many separate git repos/projects, the
user-level file avoids repeating this setup per project.
2. If the target file doesn't exist yet, create it containing just these
two entries under `permissions.allow`.
3. If it exists, read it first and merge: add only entries not already
present. Don't duplicate, don't remove or overwrite unrelated existing
permissions.
4. Show the user exactly what was added before writing.
Do **not** whitelist a generic `Bash(git:*)` or anything targeting `cd`.
Do **not** whitelist writing to the config file — that keeps prompting for
confirmation, so registering a new repo is always a visible, confirmed
action.
## 4. Offer the anti-chaining hook
Explain to the user: this hook never silently blocks and never silently
allows anything. It only ever forces the *normal* confirmation prompt
(`permissionDecision: "ask"`) when a Bash command contains shell chaining
or substitution operators (`&&`, `;`, `|`, backticks, `$(...)`). This exists
because Claude Code's own Bash allow-list matching has had bugs where
compound commands either bypass per-command checks entirely, or where a
chain of individually-allowed commands still isn't recognized as such — see
`hooks/force-ask-on-chaining.sh` for the reasoning and a link to the
relevant upstream issue. With this hook installed, if a chained command
ever gets constructed anyway (it shouldn't, since `git_cmd.sh` removes the
need for `cd`/chaining), the user will always see a normal approval prompt
for it rather than it silently going through or silently failing.
Ask the user whether to install it. If yes:
1. Locate `hooks/force-ask-on-chaining.sh` next to this plugin's
`plugin.json` and note its absolute path, `<HOOK_PATH>`.
2. Ensure it's executable: `chmod +x <HOOK_PATH>`.
3. Merge this into the same settings file chosen in step 3 (project or
user-level — ask if unclear, but note this hook is most useful applied
broadly at the user level, since it's about Bash hygiene in general, not
specific to git):
```json
{
"hooks": {
"PreToolUse": [
{
"matcher": "Bash",
"hooks": [
{
"type": "command",
"command": "<HOOK_PATH>"
}
]
}
]
}
}
```
Merge into any existing `hooks.PreToolUse` array rather than overwriting it
— don't remove other existing PreToolUse hooks for the `Bash` matcher or
other matchers.
If the user declines, skip this step entirely; the whitelist from step 3
still works on its own, it just doesn't have this extra safety net.
## 5. Make the wrapper script executable
```bash
chmod +x <SKILL_DIR>/scripts/git_cmd.sh
```
## 6. Confirm and offer a test run
Summarize to the user:
- Any repos registered in step 2
- The exact permission entries added, and where
- Whether the anti-chaining hook was installed, and where
Then offer to run `<SKILL_DIR>/scripts/git_cmd.sh status` (against the
current directory, or a registered repo) as a quick sanity check.
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.