# gitctl TODO Planned features. Each note captures the non-obvious bits so the work does not re-discover them. Keep the hard rules from CLAUDE.md (stdlib only, single-file scripts, single-writer repo.desc, idempotent, no em dashes, work on master). ## 1. delete repo `gitctl repo delete ` - remove a repo from all three places it lives. Touches three writers, so it is the inverse of `repo create`: - gitolite.conf stanza -> client edits the admin clone, pushes (needs the SSH key / card, like create). - cgit block in /etc/cgitrc -> new helper verb, the inverse of `insert_repo_block`: find the repo's `repo.url=` line and delete its block up to the next `repo.url=`, `section=`, banner, or EOF. Back up first (write_cgitrc_lines already does). Run sync after. - the bare repo on disk -> gitolite does NOT delete it when the stanza goes away. The helper does NOT rm it. Instead it MOVES the repo to a trash dir (see below), so deletion is reversible and you review before anything is really gone. Trash dir (the chosen design, not rm -rf): - New constant `TRASH_DIR`, OUTSIDE `REPO_BASE` so gitolite and cgit never see it (e.g. `/var/lib/gitolite3/trash`). git-writable. - Delete = `mv REPO_BASE/.git TRASH_DIR/.git.`. Atomic within one filesystem; if TRASH_DIR is on a different mount, fall back to copy+remove or just require same-fs. - validate_url first; double-check the resolved source path is under REPO_BASE before moving (defense in depth, even though validate_url blocks `..`/`/`). - Leave a note for the user: print where it went and that it needs manual review/removal. Optionally drop a short TRASH_DIR/README or a per-entry `.trashinfo` (origin path, timestamp, who) so a later cleanup tool has context. - FUTURE: a helper verb like `gc-trash --older-than ` that prunes TRASH_DIR entries past a retention window, runnable from cron. The move-based design makes this trivial later; do not build it now (YAGNI), just keep TRASH_DIR layout cron-friendly (timestamp in the name). Design notes: - DESTRUCTIVE (even as a move - it disappears from the live tree). Always confirm, show what will be removed and where it goes. The `-y` flag from item 3 must NOT bypass the delete confirmation (or gate it behind a separate, louder opt-in). Deleting is not the same as auto-confirming an additive diff. - Idempotent-ish: if the repo is already gone from a given place, skip that step and report, do not error. - Recoverable: the bare repo sits in TRASH_DIR until you remove it; the cgitrc backup covers the cgit block. Nothing is irreversibly destroyed by gitctl. - Order: remove cgit block + move bare repo via helper first, then the gitolite stanza push? Or stanza first? Decide and document - partial failure (push fails after the move) should leave a clear, resumable state like create does. ## 2. list repos -- DONE `gitctl repo list` is implemented. It lists EVERY bare repo on disk (the full set, public and private), not just the cgit-exposed ones, because cgit auto-discovery is off and private repos are not in cgitrc. Source of truth is `REPO_BASE/*.git`, not cgitrc; cgitrc membership only tags a repo PUB vs PRIV and supplies its section. Description comes from each repo's `description` file (truncated 60). Client renders a table, green public / dim private on a TTY. Helper verb `list-repos`; primitive `list_repos()` + `repo_sections_from()` (the latter dedupes the old `find_repo_section`). Self-tests cover both the cgitrc parse and a temp-FS scan. Still open from the original plan: extend bash completion to complete repo NAMES (for `desc` / `delete` / `add-remote`) now that a list verb exists. The `repo list` action itself is already in completion. ## 3. `-y` / `--yes` flag -- DONE `-y` / `--yes` is implemented as a GLOBAL flag (on the top-level parser), so it goes before the subcommand: `gitctl -y repo create ...`. Today the only y/N it skips is the phase-1 push confirmation in `repo create`; the diff is still printed and an "auto-confirmed" note shown. It does NOT bypass SSH key auth (password / smartcard touch), so creation is never fully unattended. Section auto-create was already silent, so behavior stays consistent. Hard wall for delete (item 1): `-y` must NEVER be honored by a destructive delete. The flag help says so, this note records it, and the global -y comment in the client points at item 1. When delete is built, it reads its own confirmation and ignores `a.yes`. Bash completion offers `-y`/`--yes` at the top level and transparently skips a leading `-y` when resolving group/action. ## Cross-cutting - Bash completion: once `repo list` exists, complete repo names for `desc`, `delete`, `add-remote` (like `--section` is completed today). One ssh call, only when completing a repo-name argument. - Skill: update both SKILL.md files (repo skills/gitctl + ~/.claude) to mention delete (and its destructive, confirm-always nature) and `-y`'s real limit. - Tests: each new helper verb gets self-test coverage (cgit block removal is the risky one - mirror the insert tests: first/middle/last/missing).