diff --git a/.agents/skills/cleanup-workspaces/SKILL.md b/.agents/skills/cleanup-workspaces/SKILL.md new file mode 100644 index 0000000..dfc051a --- /dev/null +++ b/.agents/skills/cleanup-workspaces/SKILL.md @@ -0,0 +1,65 @@ +--- +name: 'cleanup-workspaces' +description: 'Use when the user wants to clean up stale or merged git worktrees under ~/.workspace (e.g. after PRs are merged and their remote branches deleted). Prunes workspaces whose remote branch is gone. Companion to pick-issue-to-pr.' +--- + +# Cleanup Workspaces + +Remove git worktrees under `~/.workspace///` whose upstream branch has been deleted on the remote (typically because the PR was merged). Companion to the `pick-issue-to-pr` skill, which creates those workspaces. + +## Workflow + +### 1. Discover workspaces + +Scan `~/.workspace/` for `//` directories. Group them by their main repository (the worktree's common git dir). For each distinct repository, run the steps below once. + +`git worktree list` from any checkout of a repo lists all its worktrees with paths and branches — use it to get the authoritative list rather than relying on directory names alone. + +### 2. Prune remote-tracking refs + +For each repository: + +```bash +git fetch --prune origin +``` + +This deletes remote-tracking refs for branches that no longer exist on the remote. + +### 3. Identify workspaces whose branch is gone + +A workspace branch is a cleanup candidate when its upstream is gone: + +```bash +git branch -vv +``` + +Branches whose upstream was pruned show `: gone]` in the output. Cross-check that the branch is actually merged or its PR is closed before removing — prefer `: gone]` (branch deleted on remote) as the signal, since that means the PR was merged or the branch was deleted intentionally. + +Optionally confirm via the GitHub MCP / `gh` that the associated PR is merged/closed when in doubt. + +### 4. Remove the workspace and its branch + +For each confirmed candidate: + +```bash +git worktree remove "" # add --force only if it refuses due to untracked/modified files +git branch -D "" # the now-dangling local branch +``` + +Then tidy administrative files: + +```bash +git worktree prune +``` + +Also remove now-empty `/` parent directories under `~/.workspace/`. + +### 5. Report + +List what was removed and what was kept (and why, e.g. uncommitted changes blocking removal). **Never** force-remove a workspace that has uncommitted or unpushed work without explicitly flagging it to the user and getting confirmation. + +## Safety + +- Only ever operate inside `~/.workspace/`. +- Do not remove the main working checkout, only linked worktrees. +- A workspace with uncommitted/unpushed changes is surfaced to the user, never silently force-removed. diff --git a/.agents/skills/pick-issue-to-pr/SKILL.md b/.agents/skills/pick-issue-to-pr/SKILL.md new file mode 100644 index 0000000..cb94f26 --- /dev/null +++ b/.agents/skills/pick-issue-to-pr/SKILL.md @@ -0,0 +1,119 @@ +--- +name: 'pick-issue-to-pr' +description: 'Use when the user wants to pick a GitHub issue to work on from a list. Lists open issues (the ones already assigned to the current user first), lets the user choose one, self-assigns it, creates an isolated workspace, runs setup, clarifies the issue one question at a time, plans (one approval checkpoint), implements, opens a draft PR, and folds every later change — including review feedback — into a single amended commit.' +--- + +# Pick Issue to PR + +Take a GitHub issue from a pick-list all the way to a draft pull request, working in an isolated workspace and keeping the branch at a **single commit**. + +## Tooling + +Prefer the **GitHub MCP** tools (`mcp__github__*`). If they are not available in the session, fall back to the `gh` CLI for the equivalent operations. Use `git` directly for all local repository operations (fetch, worktree, commit, push). + +Derive `owner`/`repo` from the `origin` remote: `git remote get-url origin` (handles both `git@github.com:OWNER/REPO.git` and `https://github.com/OWNER/REPO.git`). + +## Workflow + +### 1. List the issues and let the user choose + +Resolve the current user first — assignment is **relative to whoever runs the skill**, never hard-coded: + +- `mcp__github__get_me` (or `gh api user --jq .login`). + +List the **open** issues of the current repo, then present them **sorted so the issues already assigned to the current user come first**, the rest after: + +- `mcp__github__list_issues` with `state: open` (or `gh issue list --state open --json number,title,assignees,labels`). + +Show the list (number, title, assignees, labels) and ask the user which one they want to work on. **Do not pick for them.** Wait for the choice before continuing. + +### 2. Self-assign the chosen issue + +Assign the issue to the current user resolved in step 1: + +- `mcp__github__issue_write` (method `update`, add the current login to `assignees`), or `gh issue edit --add-assignee @me`. + +This is always the user running the skill — if someone else runs it, it assigns to them. + +### 3. Create an isolated workspace linked to the issue + +The workspace is a git worktree based on the **latest remote default branch**, not the local checkout. + +```bash +git fetch origin +DEFAULT=$(git symbolic-ref --quiet --short refs/remotes/origin/HEAD 2>/dev/null | sed 's@^origin/@@') +DEFAULT=${DEFAULT:-main} +``` + +- Parse `/` from the origin URL (e.g. `ippontech/ui` -> group `ippontech`, project `ui`). +- Branch name linked to the issue: `-` (e.g. `12-fix-badge-contrast`). If recent history suggests another scheme, match it. +- Path: `~/.workspace///`. + +```bash +WT="$HOME/.workspace///" +git worktree add -b "" "$WT" "origin/$DEFAULT" +``` + +If the branch already exists, reuse it: `git worktree add "$WT" ""`. Do all subsequent work with that worktree as the working directory. + +### 4. Run setup in the workspace + +From the workspace root (only if a `mise.toml` exists there): + +```bash +mise trust && mise install && mise setup +``` + +If the project doesn't use mise, run the project's documented install/setup instead. + +### 5. Clarify the issue — one question at a time + +Read the full issue (`mcp__github__issue_read` get + comments + labels) and the relevant code, then question the user to remove ambiguity: + +- Ask **exactly one question per turn** and wait for the answer before the next. +- Stop asking once you have enough to write a confident plan. +- The user may decide to **complete the issue itself**. When they do, update the issue on GitHub (`mcp__github__issue_write` / `gh issue edit`) so the issue stays the source of truth. + +### 6. Propose a plan — REQUIRED CHECKPOINT + +Build a concrete plan from the issue, the answers, and a look at the code. Present it and **wait for approval**. This is the only mandatory stop before implementation. + +### 7. Implement + +Implement the change following the approved plan and the repo's own conventions (read CLAUDE.md / AGENTS.md and neighbouring code). Keep the diff scoped to the issue. + +### 8. Commit once, push, open a draft PR + +The branch must hold **exactly one commit**. + +- Detect the repo's commit convention (recent `git log --oneline -20`, any commitlint config). Reference the issue in the commit. +- Create the single commit, then: + +```bash +git push -u origin +``` + +- Open a **draft** PR targeting `$DEFAULT` with a body that closes the issue (`mcp__github__create_pull_request` with `draft: true`, or `gh pr create --draft --base "$DEFAULT" --body "Closes #"`). + +Report the PR URL. + +### 9. Fold reviews into the single commit + +When reviews arrive (read them: `mcp__github__pull_request_read` get_review_comments, or `gh pr view --comments`) or the user asks for changes: + +- Apply the changes, then **amend the existing commit** — never add a second commit: + +```bash +git commit --amend --no-edit # or adjust the message if the scope changed +git push --force-with-lease +``` + +- Reply to the review threads where useful. + +Repeat until the PR is approved. **The branch ends with a single commit, always.** + +## Notes + +- Never push directly to the default branch. +- One issue = one branch = one workspace = one PR = one commit. +- The worktree stays under `~/.workspace/...` until the branch is merged; it can be cleaned up afterwards with `git worktree remove`.