1d0b66df2e
Forces a normal confirmation prompt (never a silent block, never a silent allow) when Bash runs raw git instead of git_cmd.sh, worded more insistently when the subcommand is one the wrapper already supports. Raw git stays a valid fallback for unsupported subcommands and unregistered repos - a hard deny would remove that fallback entirely. Also documents in SKILL.md that repo ambiguity (which registered repo is meant, or none at all) must be resolved by asking the user rather than guessing - a hook only sees the literal command string, not the conversation, so that judgment can't live in the hook itself.
134 lines
7.0 KiB
Markdown
134 lines
7.0 KiB
Markdown
---
|
|
name: git-manager
|
|
description: Manages git operations (status, log, diff, show, fetch, remote, branch, checkout, add, commit, push, pull, tag) across one or more git repositories — including non-code repositories such as an Obsidian vault kept under version control — through a single wrapper script instead of raw shell `git`/`cd` commands. Always use this skill instead of running `git` or `cd` directly whenever the task involves checking status, committing, pushing, pulling, or otherwise managing a git repository, especially when multiple repositories are involved in the same session (e.g. a code repo and a separate notes/vault repo).
|
|
---
|
|
|
|
# Git Manager
|
|
|
|
This skill wraps all git operations in a single script, permanently
|
|
installed at `~/.agent-skills/git-manager/bin/git_cmd.sh` by this plugin's
|
|
setup (not run from wherever this skill's own files happen to live — see
|
|
"Setup and permissions" below for why), so that:
|
|
|
|
- There is never a need for `cd <path> && git ...` to operate on a
|
|
non-default repository — pass `--repo <name>` instead.
|
|
- There is never a need to chain multiple git commands with `&&`/`;`/`|` in
|
|
one shell invocation — each git operation is its own separate call to the
|
|
wrapper.
|
|
|
|
This matters beyond convenience: on the host tool side (see "Setup and
|
|
permissions" below), only this single wrapper script is whitelisted to run
|
|
without a confirmation prompt. Chained or `cd`-based commands don't match
|
|
that whitelist entry, so avoiding them isn't just tidier — it's what keeps
|
|
every git operation actually covered by the whitelist instead of falling
|
|
back to prompts (or, worse, slipping through on a stale broad rule).
|
|
|
|
## How to run git commands
|
|
|
|
Always use:
|
|
|
|
```bash
|
|
~/.agent-skills/git-manager/bin/git_cmd.sh <subcommand> [--repo <name>] [-- <git-args...>]
|
|
```
|
|
|
|
- `<subcommand>` must be one of: `status`, `log`, `diff`, `show`, `fetch`,
|
|
`remote`, `branch`, `checkout`, `add`, `commit`, `push`, `pull`, `tag`.
|
|
Anything else is rejected by the script itself before git runs.
|
|
- `--repo <name>` targets a specific pre-configured repository. The script
|
|
itself (not this skill's own logic) decides what happens if it's
|
|
omitted: with exactly one repo registered in
|
|
`~/.agent-skills/git-manager/config.json`, that one is used
|
|
automatically; with more than one, the script errors and lists the
|
|
registered names so you can retry with `--repo`; with none registered,
|
|
it errors saying to register one first. The current working directory
|
|
is never consulted for this — whether it happens to be a git repository
|
|
itself is not a signal this skill acts on. If the task names a repo
|
|
explicitly, pass `--repo <name>` for that one regardless of how many are
|
|
registered.
|
|
- Everything after `--` is passed through to `git` literally (e.g.
|
|
`-- -m "commit message"`, `-- --oneline -10`, `-- origin main`).
|
|
- Don't pre-check whether `~/.agent-skills/git-manager/bin/git_cmd.sh`
|
|
exists with a separate command (e.g. `test -x ... && ...`) before
|
|
calling it — that's exactly the kind of chained command this skill exists
|
|
to avoid, and it'll trigger the anti-chaining hook if installed. Just
|
|
invoke it directly. If it fails with "No such file or directory" (or
|
|
similar), that means setup hasn't been run for this tool yet — tell the
|
|
user to run it first (for Claude Code: `/git-manager:setup`) rather than
|
|
trying to invoke the script from wherever this skill's own files happen
|
|
to be mounted (a plugin cache, a symlink target, etc.) — that location
|
|
isn't guaranteed stable and isn't what gets whitelisted.
|
|
|
|
Examples:
|
|
|
|
```bash
|
|
~/.agent-skills/git-manager/bin/git_cmd.sh status
|
|
~/.agent-skills/git-manager/bin/git_cmd.sh log -- --oneline -10
|
|
~/.agent-skills/git-manager/bin/git_cmd.sh add -- -A
|
|
~/.agent-skills/git-manager/bin/git_cmd.sh commit -- -m "Update DNS notes"
|
|
~/.agent-skills/git-manager/bin/git_cmd.sh push --repo homelab-notes -- origin main
|
|
```
|
|
|
|
Never call `git` directly, and never use `cd` to switch into a different
|
|
repo before running git — use `--repo` instead. If a task genuinely needs a
|
|
subcommand outside the allowed list (e.g. `stash`, `merge`, `rebase`,
|
|
`reset`), say so explicitly to the user rather than working around
|
|
the restriction (e.g. via `git -C` called outside this script, or editing
|
|
`.git` internals directly) — that path isn't whitelisted and existing on
|
|
purpose as a guardrail, not an oversight. Those excluded subcommands can
|
|
rewrite or discard history/working-tree state in ways that are hard to
|
|
reverse; `tag` is allowed because tagging a commit doesn't carry that risk.
|
|
|
|
## When it's unclear which repo is meant
|
|
|
|
Don't guess. If a task says "the repo" or otherwise implies a repo without
|
|
naming one, and it's genuinely ambiguous which registered repo (if any) it
|
|
refers to, or the request's context doesn't clearly match any registered
|
|
repo at all, ask the user before picking a `--repo` or falling back to raw
|
|
git. Concretely, this is already handled operationally rather than needing
|
|
new logic: call `git_cmd.sh` without `--repo` and let it resolve —
|
|
`resolve_repo_path` in `_lib.sh` errors out listing every registered name
|
|
when more than one repo is configured and none was specified, and errors
|
|
saying none are registered when the config is empty. Either error is the
|
|
signal to ask the user which repo (or whether to register a new one),
|
|
rather than picking one, or reaching for raw git, on your own.
|
|
|
|
## Multi-repo setup
|
|
|
|
If a task refers to a named repo (e.g. "push the homelab-notes vault") and
|
|
`~/.agent-skills/git-manager/config.json` doesn't have an entry for it yet,
|
|
ask the user for its absolute path and add it. Use the Read/Write file
|
|
tools for this, not `cat`/Bash — the whitelisted permission for this file
|
|
is `Read(~/.agent-skills/git-manager/config.json)`, which covers the Read
|
|
file tool, not a Bash `cat` invocation of the same path (those are
|
|
separate permission checks in Claude Code, even though they access the
|
|
same file). Read the file (it may not exist yet, that's fine — treat that
|
|
as no repos registered):
|
|
|
|
```json
|
|
{
|
|
"repos": [
|
|
{"name": "homelab-notes", "path": "/absolute/path/to/vault"},
|
|
{"name": "dwh-pipeline", "path": "/absolute/path/to/repo"}
|
|
]
|
|
}
|
|
```
|
|
|
|
Merge new entries in rather than overwriting existing ones. At least one
|
|
repo must be registered for this skill to do anything — there is no
|
|
current-working-directory fallback.
|
|
|
|
## Setup and permissions
|
|
|
|
Configuration lives at the tool-neutral path
|
|
`~/.agent-skills/git-manager/config.json`, not a Claude-specific location.
|
|
Host-specific setup (permissions whitelist, hooks) lives under `vendor/<tool>/`
|
|
in this repo, not in this skill itself. For Claude Code, see
|
|
`vendor/claude-code/plugins/git-manager/commands/setup.md`
|
|
(`/git-manager:setup`), which whitelists exactly one command —
|
|
`Bash(~/.agent-skills/git-manager/bin/git_cmd.sh:*)` — and optionally installs a
|
|
PreToolUse hook that forces a normal confirmation prompt (not a silent
|
|
block, not a silent allow) for any Bash call containing shell chaining
|
|
operators (`&&`, `;`, `|`, backticks, `$(...)`), as a safety net against
|
|
Claude Code's own permission-matching not always splitting compound
|
|
commands correctly.
|