138 lines
4.9 KiB
Markdown
138 lines
4.9 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 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.
|
|
|
|
## 1. Determine the skill's install directory
|
|
|
|
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:
|
|
|
|
```bash
|
|
realpath <plugin-dir>/skills/git-manager
|
|
```
|
|
|
|
This resolved path is `<SKILL_DIR>` for the rest of this setup.
|
|
|
|
## 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`:
|
|
|
|
```bash
|
|
mkdir -p ~/.agent-skills/git-manager
|
|
cat > ~/.agent-skills/git-manager/config.json << 'EOF'
|
|
{
|
|
"repos": [
|
|
{"name": "<short-name>", "path": "<absolute-repo-path>"}
|
|
]
|
|
}
|
|
EOF
|
|
```
|
|
|
|
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.
|
|
|
|
## 3. Generate and merge the minimal permissions whitelist
|
|
|
|
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:
|
|
|
|
- `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.
|