Fixed setups
This commit is contained in:
+77
-118
@@ -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.
|
||||
|
||||
Reference in New Issue
Block a user