docs(gitflow): run C — push-mode verb, skills never push; CHANGELOG, SETTINGS, gitflow skill, README, USAGE
This commit is contained in:
+5
-1
@@ -7,11 +7,15 @@ Format follows [Keep a Changelog](https://keepachangelog.com/) and this project
|
||||
## [Unreleased]
|
||||
|
||||
### Added
|
||||
- **Manual-push mode**: `git config gitflow.autopush false` (human-set) now stops every push the gitflow lib makes, not only the post-commit / post-merge hooks. `gitflow start` and `finish` branch, commit and merge locally and push nothing; `gitflow delete` leaves the `origin/` copy in place and prints `git push origin --delete <br>` for the user to run. `hooks/unpushed-guard.sh` stays silent at turn end in this mode and opens each session with one `ℹ manual push mode:` line counting the commits no remote holds across every local branch; an unparseable `gitflow.autopush` value is named and treated as auto. `hooks/push-guard.sh` (PreToolUse, `Bash|Monitor`) refuses any `git push` Claude types while `gitflow.autopush` reads false in the session cwd or in a literal `-C`/`cd` directory the command names (global config counts outside a repo); the refusal tells the user to run it with `! git push`. It fails closed: for this hook a non-boolean value reads as manual, and a git failure while reading the key, an internal error or more than 20 distinct directory tokens in one command refuse the push (these pathological cases fire in auto mode too). In manual mode it over-blocks any command where a `push` word follows a `git` token; the misses listed in its header fall to a new `autoMode.soft_deny` rule that no request in the turn clears. The session banner adds `🔒 push : manual (autopush=false) — ! git push` when the key reads false. Skills that push on their own do not honour the mode yet. Tests: `lib/gitflow-test.sh` T18m block, `lib/tests/unpushed-guard.test.sh` T10-T16, `lib/tests/push-guard.test.sh` (71 checks).
|
||||
- **Manual-push mode**: `git config gitflow.autopush false` (human-set) now stops every push the gitflow lib makes, not only the post-commit / post-merge hooks. `gitflow start` and `finish` branch, commit and merge locally and push nothing; `gitflow delete` leaves the `origin/` copy in place and prints `git push origin --delete <br>` for the user to run. `hooks/unpushed-guard.sh` stays silent at turn end in this mode and opens each session with one `ℹ manual push mode:` line counting the commits no remote holds across every local branch; an unparseable `gitflow.autopush` value is named and treated as auto. `hooks/push-guard.sh` (PreToolUse, `Bash|Monitor`) refuses any `git push` Claude types while `gitflow.autopush` reads false in the session cwd or in a literal `-C`/`cd` directory the command names (global config counts outside a repo); the refusal tells the user to run it with `! git push`. It fails closed: for this hook a non-boolean value reads as manual, and a git failure while reading the key, an internal error or more than 20 distinct directory tokens in one command refuse the push (these pathological cases fire in auto mode too). In manual mode it over-blocks any command where a `push` word follows a `git` token; the misses listed in its header fall to a new `autoMode.soft_deny` rule that no request in the turn clears. The session banner adds `🔒 push : manual (autopush=false) — ! git push` when the key reads false. Skills read the mode through a new lib verb, `bash ~/.claude/lib/gitflow.sh push-mode`: it prints `auto`, `manual` or `invalid` (rc 0) and names an invalid value on stderr (printable characters only, 64 at most). It is the one reader a skill may call, since the `git config` read of the key is denied to Claude. Skills push nothing on their own, except the `/release-candidate` tag in auto-push mode on an explicit go. Every "on origin" or "not pushed" line they print comes from `git rev-list --count origin/<br>..<br>` read after the fact, with the complete `! git …` command when something is left for the user to push. An invalid value is named, but the lib and the git hooks still push on it as auto. Tests: `lib/gitflow-test.sh` T11b (push-mode verb) and T18m block, `lib/tests/unpushed-guard.test.sh` T10-T16, `lib/tests/push-guard.test.sh` (71 checks).
|
||||
|
||||
### Changed
|
||||
- `settings.json` denies every write form of the human-only `gitflow.*` keys (18 entries): any `git … config` spelling, section remove/rename, `git -c`, the git config env overrides, and Edit/Write of `.git/config`, `.gitconfig` and `~/.config/git/config`. Side effect: Claude can no longer read `gitflow.autopush` through `git config` either; hooks and `lib/gitflow.sh` still read it. The `hard_deny` rule on routing around a guardrail now names PreToolUse hook refusals.
|
||||
- `gitflow start` and `finish` warn on stderr when a base is behind origin and cannot fast-forward, instead of a silent `git pull --ff-only || true` (T18l, T18n).
|
||||
- `/close` (`/capitalize` STEP 5C) no longer runs its own push of develop: `gitflow finish` already pushes develop in auto-push mode (BDR-095). The closing line reports the real state, read after the merge: pushed, manual push mode with the `! git push origin develop` to run, not on origin, push failed, or an invalid `gitflow.autopush` value named. A finish whose merge landed but whose branch delete failed (rc 5/2/6) still reports the push state.
|
||||
- `/client-handover` no longer asks "Push to origin now?" and no longer pushes: the hooks had already pushed in auto-push mode, and push-guard refuses it in manual mode. The agent reads the branch's ahead count after the fix-loop commits, at the deploy pause and before each end report. A pending push is handed to the user as `! git push -u origin <branch>` before the deploy pause, and both reports carry a `Push:` line. A branch name outside `^[A-Za-z0-9._/][A-Za-z0-9._/-]*$` is never interpolated into a command.
|
||||
- `/release-candidate` STEP 6: in manual push mode, with an invalid mode value, or when main or develop is not on origin, Claude pushes nothing and prints one command for the user, `! git push --atomic origin main develop v<X.Y.Z>`. The tag-push question remains for auto-push mode with both branches on origin. The version must match `^[0-9]+\.[0-9]+\.[0-9]+$` before it enters a command or tag.
|
||||
- `/tour`: each summary row says `on origin` or `local only` with the `! git -C <project> push -u origin <branch>` to run. The tour never pushes or retries.
|
||||
|
||||
### Fixed
|
||||
- `gitflow delete` (and `finish`) land on the base that contains the branch and drop the branch's upstream before `git branch -d`, so a branch whose upstream lags (manual-push mode) is deleted instead of refused by git (T18k).
|
||||
|
||||
@@ -184,7 +184,7 @@ a different package, ships its own conflicting `graphify` bin) — see
|
||||
| `/impeccable` | Design verbs (audit, polish, bolder…) + deterministic anti-slop detector (`npx impeccable detect`) |
|
||||
| `/commit-change` | Smart commit grouping from staged/unstaged changes |
|
||||
| `/gitflow` | Gitflow branch operations — bootstrap main+develop, start a typed branch, directed merge |
|
||||
| `/release-candidate` | Cut a versioned release — finalize version.txt + CHANGELOG, merge develop→main, tag, push |
|
||||
| `/release-candidate` | Cut a versioned release — finalize version.txt + CHANGELOG, merge develop→main, tag, push (auto-push mode, tag on your go; manual push mode: one `! git push --atomic` command you run) |
|
||||
| `/deploy` | Compose the deploy checklist from a project's committed runbook (delta only); you run it, the skill resumes cold on your report |
|
||||
| `/graphify` | Codebase knowledge graph — navigation for large-scope tasks |
|
||||
| `/plugin-check` | Check active plugins vs project needs — recommend enable/disable |
|
||||
|
||||
@@ -146,7 +146,7 @@ Tu veux...
|
||||
| `/geo` | Audit GEO uniquement (IA) | Visibilité ChatGPT, Perplexity, Claude, Gemini… |
|
||||
| `/commit-change` | Commits bien structurés | Groupe les changements par unité logique |
|
||||
| `/gitflow` | Opérations de branches gitflow | Bootstrap main+develop, branche typée, merge dirigé |
|
||||
| `/release-candidate` | Couper une release versionnée (develop en avance sur main) | Finalise version.txt + CHANGELOG, merge develop→main, tag, push |
|
||||
| `/release-candidate` | Couper une release versionnée (develop en avance sur main) | Finalise version.txt + CHANGELOG, merge develop→main, tag, push (mode auto-push, tag sur ton feu vert ; mode push manuel : une commande `! git push --atomic` que tu lances) |
|
||||
| `/deploy` | Déployer via le runbook du projet | Instancie le delta depuis le dernier deploy, reprend à froid ; tu exécutes la checklist, Claude ne déploie jamais |
|
||||
| `/graphify` | Navigation codebase large-scope | Knowledge graph, pour tâches multi-fichiers |
|
||||
| `/skills-perso` | Lister ses skills personnels | Skills créés dans ~/.claude/skills/ |
|
||||
|
||||
@@ -40,6 +40,7 @@ bash ~/.claude/lib/gitflow.sh start <type> <name> # branch from the correct base
|
||||
bash ~/.claude/lib/gitflow.sh finish # directed merge of the CURRENT branch — HUMAN-GATED (below)
|
||||
bash ~/.claude/lib/gitflow.sh delete <branch> # delete a merged branch, local + origin copy — refuses main/develop + anything unmerged
|
||||
bash ~/.claude/lib/gitflow.sh protected-base [br] # rc 0 on main/develop — the shared predicate
|
||||
bash ~/.claude/lib/gitflow.sh push-mode # auto | manual | invalid on stdout, rc 0: the only way a skill reads gitflow.autopush; pushes nothing
|
||||
```
|
||||
|
||||
`finish` merges by the current branch's type:
|
||||
|
||||
@@ -145,7 +145,7 @@ local trace, and the brief had authorized it. What holds now, by tier:
|
||||
| `chmod`/`chown -R`, `sudo`/`doas`/`pkexec`, disk tools (`dd`, `mkfs`, `shred`…), `chattr` | `permissions.deny` | The user runs them by hand. |
|
||||
| Docker volume drops, `system prune`, `compose down -v`, `--privileged`, the docker socket, `-v /:` | `permissions.deny` | Promoted from `soft_deny`: no in-session clearance for data drops. |
|
||||
| Git history destruction (`push --delete`/`--mirror`/`:ref`/`--force-with-lease`, `branch -D`, `filter-branch`, `reflog expire`, `stash clear`/`drop`, `clean -f`), `--no-verify`, `core.hooksPath` | `permissions.deny` | A remote is the backup; nothing rewrites or deletes what it holds. |
|
||||
| Writing the human-only `gitflow.*` toggles: any `git … config` spelling, section remove/rename, `git -c`, the git config env overrides, Edit/Write of git config files | `permissions.deny` | Claude never flips the mode that binds it. Side effect: the trailing glob also matches the bare read, so Claude cannot read `gitflow.autopush` through `git config`; hooks and `lib/gitflow.sh` still do. |
|
||||
| Writing the human-only `gitflow.*` toggles: any `git … config` spelling, section remove/rename, `git -c`, the git config env overrides, Edit/Write of git config files | `permissions.deny` | Claude never flips the mode that binds it. Side effect: the trailing glob also matches the bare read, so Claude cannot read `gitflow.autopush` through `git config`; hooks and `lib/gitflow.sh` still do, and skills read it through `gitflow.sh push-mode`. |
|
||||
| Pushing in manual-push mode (`gitflow.autopush false`) | `hooks/push-guard.sh` (PreToolUse) + `autoMode.soft_deny` | `ask` is inert under auto mode. The hook denies the direct forms; the soft_deny covers scripted, aliased, subshell and sub-agent pushes, and a request in the turn does not clear it: the user types `! git push`. |
|
||||
| Destructive tool against a local path (variable, `~`, `..`, wildcard, outside cwd/tmp), even as a trace or a rehearsal a brief allows | `autoMode.hard_deny` | A pattern cannot express "the target resolves outside the project"; the classifier can. A sub-agent brief carries no user authority. |
|
||||
| `docker rm -f`, bind mount outside cwd; discarding uncommitted work | `autoMode.soft_deny` | Recoverable or user-intended in the turn. |
|
||||
@@ -191,8 +191,14 @@ reading the key or more than 20 directory tokens in one command refuses the
|
||||
push, in auto mode too. In manual mode it over-blocks any command where a
|
||||
`push` word follows a `git` token (`git stash push`, a grep for "git push").
|
||||
The misses listed in its header fall to an `autoMode.soft_deny` rule that no
|
||||
request in the turn clears. Skills that push on their own are not adapted
|
||||
yet.
|
||||
request in the turn clears. Skills read the mode through
|
||||
`bash ~/.claude/lib/gitflow.sh push-mode` (`auto`, `manual` or `invalid`,
|
||||
rc 0) and push nothing themselves, except the `/release-candidate` tag in
|
||||
auto-push mode on an explicit go. What they report as on origin or not
|
||||
pushed comes from `git rev-list --count origin/<br>..<br>` read afterwards,
|
||||
and a pending push is handed to the user as a complete `! git …` command.
|
||||
An invalid value is named, but the lib and the git hooks still push on it
|
||||
as auto; only push-guard fails closed on it.
|
||||
|
||||
## managed-settings.json (enterprise)
|
||||
|
||||
|
||||
Reference in New Issue
Block a user