# 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 -- DONE `gitctl repo delete ` is implemented. It removes a repo from all three places it lives, the inverse of `repo create`: - gitolite stanza -> client `remove_stanza` (inverse of `add_stanza`), commit + push (needs the SSH key / card, like create). PUSHED FIRST so gitolite stops serving the repo before its bytes move. - cgit block -> helper verb `delete-repo`, `remove_repo_block` (inverse of `insert_repo_block`); deletes the repo.url/path/owner block + its spacer blanks, leaves the section header. Backed up by write_cgitrc_lines, sync after. - bare repo -> `trash_repo` MOVES it to `TRASH_DIR` (`/var/lib/gitolite3/trash`, outside REPO_BASE, timestamped name) instead of rm, with a `.trashinfo` breadcrumb. shutil.move, with a realpath check that the source is one level under REPO_BASE (defense in depth on top of validate_url). The helper exposes ONE verb (`delete-repo`) doing cgit-block removal + move + .trashinfo. Always confirms (the global `-y` is deliberately NOT read by cmd_delete). Idempotent: a piece already gone is skipped, not an error. Partial failure (push ok, helper fails, or commit ok but push fails) is resumable by re-running, same as create. Self-tests: remove_repo_block and remove_stanza both pinned by an insert/add-then-remove round-trip plus middle/last/missing cases; trash_repo and do_delete_repo exercised on temp dirs. FUTURE (not built, YAGNI): a `gc-trash --older-than ` prune verb for cron. The timestamped TRASH_DIR layout already supports it. ## 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 Done as part of items 1-3: both SKILL.md files updated (delete + `-y` limit), self-test coverage for every new helper verb, completion actions for `list` and `delete`, README and CLAUDE.md brought current. ## Remaining 1. Repo-name bash completion -- DONE. `desc`, `delete`, and `add-remote` complete repo NAMES at the name position from `gitctl repo list` (first field, header dropped), one ssh call, only at that position so a stray Tab never hits the network. `-y` before the subcommand is handled. 2. Stray sync-script echo -- DONE. The `No changes.` / `Wrote N change(s).` lines come from the server sync script, passed through over ssh. Rather than hide them, `call_helper` now prefixes every passthrough line with `server: ` (`_server_prefixed`), so they read clearly as remote output instead of interleaved local noise. 3. FUTURE / YAGNI: `gc-trash --older-than ` helper verb to prune `TRASH_DIR` entries past a retention window, runnable from cron. The timestamped trash layout already supports it. It would be the ONLY real `rm -rf` in the tool, so it needs hard guards (realpath-under-TRASH_DIR check, no symlink follow, validated timestamp parse) and a dry-run default. Do not build until trash actually accumulates and space needs reclaiming.