Add agentws worktree-management binary
agentws manages per-branch git worktrees for the unkin-agent user: it clones repos into the source root (~/src/prodenv/<repo>) so branches are visible in Ben's main checkout, and creates isolated worktrees under the worktree root (~/.cache/agentws/<repo>__<branch>). - New internal/agent/git.go: small, testable git helpers shelling out to the git binary (clone/fetch/worktree add/remove/list/prune, branch + config ops, porcelain parsing, path sanitizing). No go-git dependency. - New cmd/agentws: new / list / rm / clean / token / credential subcommands. Auth uses an ephemeral git credential helper (agentws credential get) so the ~1h Gitea token is never persisted in a remote URL or config; per-worktree config keeps the shared checkout's identity untouched. - Wire agentws into Makefile, scripts/build-rpm.sh, packaging/nfpm.yaml (binary + bash/zsh/fish completions), .woodpecker/release.yaml (cross-compile + assets) and .gitignore. - Tests: table tests for parsing/sanitizing/dir-naming, a real temp-git repo for the worktree lifecycle, and hermetic cmd tests (bad input + credential-helper host guard) that never touch the network. - Document agentws in README.md and AGENTS.md.
This commit is contained in:
@@ -1,13 +1,15 @@
|
||||
# agent-tools
|
||||
|
||||
Two small Gitea-automation CLIs, shipped together in one RPM (`agent-tools`).
|
||||
Both act as the **`unkin-agent`** user by minting a scoped Gitea token from
|
||||
Vault, so automated PRs and comments are attributed to the agent — not to
|
||||
whoever happens to run the command.
|
||||
Small Gitea-automation CLIs, shipped together in one RPM (`agent-tools`). They
|
||||
act as the **`unkin-agent`** user by minting a scoped Gitea token from Vault, so
|
||||
automated PRs, comments and pushes are attributed to the agent — not to whoever
|
||||
happens to run the command.
|
||||
|
||||
- **`agentpr`** — create pull requests and post PR comments as `unkin-agent`.
|
||||
- **`watchpr`** — poll one or more PRs and exit when one changes in a way worth
|
||||
acting on.
|
||||
- **`agentws`** — manage per-branch git worktrees for `unkin-agent`, cloning
|
||||
into Ben's source checkout and isolating agent work under the XDG cache.
|
||||
|
||||
## How it gets a token
|
||||
|
||||
@@ -23,6 +25,9 @@ Everything is configured by environment variables, all with defaults:
|
||||
| `AGENT_APPROLE_ROLE_ID` | built-in default | AppRole role_id (overridable) |
|
||||
| `GITEA_URL` | `https://git.unkin.net` | Gitea base URL |
|
||||
| `AGENT_LOGIN` | `unkin-agent` | login whose comments `watchpr` ignores |
|
||||
| `AGENTWS_SRC_ROOT` | `~/src/prodenv` | source-of-truth checkout root (`agentws`) |
|
||||
| `AGENTWS_ROOT` | `~/.cache/agentws` | worktree root (`agentws`) |
|
||||
| `AGENTWS_OWNER` | `unkin` | Gitea org that owns the repos (`agentws`) |
|
||||
|
||||
## agentpr
|
||||
|
||||
@@ -67,10 +72,59 @@ watchpr --once --json unkin/argocd-apps#42
|
||||
On a meaningful change `watchpr` prints the reason and the PR's current state,
|
||||
then exits 0. Use `--json` for machine-readable output.
|
||||
|
||||
## agentws
|
||||
|
||||
`agentws` gives an agent an isolated git worktree per branch without disturbing
|
||||
Ben's shared checkouts. Repos are cloned into the **source root**
|
||||
(`~/src/prodenv/<repo>`) so branches created here are visible in the main
|
||||
checkout too; the worktrees themselves live under the **worktree root**
|
||||
(`~/.cache/agentws/<repo>__<branch>`).
|
||||
|
||||
```bash
|
||||
# Clone unkin/argocd-apps into ~/src/prodenv if missing, then add a worktree for
|
||||
# a new branch off the remote default branch. Prints the worktree path.
|
||||
agentws new argocd-apps --branch benvin/my-change
|
||||
|
||||
# Branch off a specific base instead of the remote default
|
||||
agentws new argocd-apps --branch benvin/hotfix --from release-1.2
|
||||
|
||||
# List managed worktrees (repo, branch, path)
|
||||
agentws list
|
||||
|
||||
# Remove a worktree (by path or branch); refreshes the source repo afterwards
|
||||
agentws rm benvin/my-change
|
||||
agentws rm ~/.cache/agentws/argocd-apps__benvin-my-change --delete-branch
|
||||
|
||||
# Remove every managed worktree and prune each source repo
|
||||
agentws clean
|
||||
|
||||
# Print a fresh unkin-agent Gitea token
|
||||
agentws token
|
||||
```
|
||||
|
||||
### Auth / credential-helper design
|
||||
|
||||
Gitea tokens minted from Vault are short-lived (~1h), so `agentws` never
|
||||
persists one in a remote URL or in git config. Instead it wires itself as an
|
||||
**ephemeral git credential helper**:
|
||||
|
||||
- `agentws token` prints a fresh token to stdout (handy for scripts).
|
||||
- `agentws credential get` speaks the git credential protocol on stdin and, for
|
||||
the configured Gitea host only, emits `username=unkin-agent` +
|
||||
`password=<fresh token>`.
|
||||
|
||||
`agentws new` sets this up per worktree without touching the shared checkout: it
|
||||
enables `extensions.worktreeConfig` on the repo once, then writes
|
||||
`user.name` / `user.email` and `credential.helper = !<agentws> credential` to
|
||||
the **per-worktree** config. Clone/fetch use the same helper via a transient
|
||||
`-c credential.helper=...`; the shared `origin` URL is left clean. On worktree
|
||||
removal `agentws` fetches in `~/src/prodenv/<repo>` so its default branch stays
|
||||
current.
|
||||
|
||||
## Build & package
|
||||
|
||||
```bash
|
||||
make build # -> dist/agentpr, dist/watchpr
|
||||
make build # -> dist/agentpr, dist/watchpr, dist/agentws
|
||||
make test # go test -race ./...
|
||||
make rpm # build + package dist/agent-tools-<version>-1.x86_64.rpm
|
||||
```
|
||||
|
||||
Reference in New Issue
Block a user