diff --git a/CLAUDE.md b/CLAUDE.md index e22a848..170fcd6 100644 --- a/CLAUDE.md +++ b/CLAUDE.md @@ -77,6 +77,25 @@ Enforced by commitlint (`wagoid/commitlint-github-action@v5`). Violations block - Required checks: `Lint (ubuntu)`, `Test (ubuntu-latest)`, `Test (macos-latest)`, `Test (windows-latest)` - No force pushes, no deletion; `enforce_admins: false` (owner can bypass) +## AI workflow — standing orders (do not re-ask) + +When the user says **"start the next issue"** (or any equivalent — "work on the next one", "what's next", "pick up the next issue"), treat the following as the **default, no-clarification-needed workflow**: + +1. **Identify the next issue.** Run `gh issue list --state open --limit 30`. Pick the lowest-numbered open issue that is not a meta-tracking issue, unless the user says otherwise. If only meta-issues remain (e.g. Phase 6 cross-platform polish — issue #16), split the meta-issue into focused sub-issues first (one per concern, one PR each), then start the first sub-issue. +2. **Always pass the issue number through `issue-workflow.sh`.** Use `./scripts/issue-workflow.sh start ` to branch, and `./scripts/issue-workflow.sh pr-body ` to render the PR body. The body includes `Closes #` — **do not edit this out**. The `Closes` keyword is what auto-closes the issue when the PR is merged. +3. **Verify the linkage before merging.** After `gh pr create`, run `gh pr view --json body | grep -E 'Closes|Fixes' #'` to confirm the PR body references the issue. If it does not, edit the PR body via `gh pr edit --body-file ` before merging. **Do not squash-merge a PR that is not linked to its source issue.** +4. **Merge with admin override when needed.** This repo's `enforce_admins: false` means solo-author merges need `--admin`. The conventional sequence is: + ```bash + gh pr merge --squash --delete-branch --admin \ + --body "Closes #. Squash-merged per CONTRIBUTING.md." + git checkout main && git pull --ff-only origin main + git remote prune origin # clean up the deleted feature branch's tracking ref + ``` +5. **Verify the issue auto-closed.** After the merge, run `gh issue view --json state --jq .state` and confirm `CLOSED`. If still `OPEN`, add the issue close manually with `gh issue close -c "Closed by "`. +6. **Then recurse.** Re-run `gh issue list --state open --limit 30`. If another issue is queued, ask the user to confirm continuation or proceed (if the user already said "keep going", just proceed). + +The `make next-issue` target wraps steps 1 and 2 for humans. AI sessions should drive the same script directly. + ## Phase status | Phase | Status | Branch / PR | diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 8b1099a..73c28b4 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -81,6 +81,11 @@ config.manager= explicitly, or omit the key for auto-detect. 5. **Squash-merge with the source branch deleted** — same as PRs #1–#10. 6. **No force-pushes after review.** Force-pushes during authoring are fine (use `--force-with-lease`). +7. **Every PR must reference its source issue in the body** — use + `Closes #N` (closing the issue on merge) or `Refs #N` (linked but + not auto-closed). The `scripts/issue-workflow.sh pr-body` template + fills this in automatically from the issue number; do not strip it. + A PR without an issue reference will be sent back for revision. ## Local development diff --git a/Makefile b/Makefile index 2d416c4..52ea000 100644 --- a/Makefile +++ b/Makefile @@ -92,4 +92,51 @@ deps: ## Print key Go module versions @grep -E '(cobra|huh|bubbletea|lipgloss|semver|gjson|yaml)' go.mod .PHONY: verify -verify: ci build ## Full pre-commit verification (CI + build) \ No newline at end of file +verify: ci build ## Full pre-commit verification (CI + build) + +# Drive a single GitHub issue from branch → PR → merge. +# Usage: make next-issue ISSUE=16 +# Requires: gh authed for dipto0321/nodeup, conventional-commits commit on HEAD, +# clean working tree. See scripts/issue-workflow.sh and [redacted].md +# ("AI workflow — standing orders") for the full sequence. +.PHONY: next-issue +next-issue: ## Drive the next open issue end-to-end (branch → PR → squash-merge) + @if [ -z "$(ISSUE)" ]; then \ + echo "usage: make next-issue ISSUE="; \ + exit 1; \ + fi + ./scripts/issue-workflow.sh start $(ISSUE) + @echo "" + @echo "Now: edit code, then commit with a conventional-commits subject." + @echo "When CI is green and you're ready to merge, run:" + @echo " make finish-pr ISSUE=$(ISSUE)" + +# Squash-merge the PR linked to ISSUE. Use after the branch is pushed +# and CI is green. Uses --admin because branch protection requires 1 +# approving review but enforce_admins is disabled for solo author work. +# Usage: make finish-pr ISSUE=16 PR=23 (PR auto-detected if omitted) +.PHONY: finish-pr +finish-pr: ## Squash-merge the PR for ISSUE and verify the issue auto-closes + @if [ -z "$(ISSUE)" ]; then \ + echo "usage: make finish-pr ISSUE= [PR=]"; \ + exit 1; \ + fi + @PR="$${PR:-$(shell gh pr list --state open --json number,headRefName --jq '.[] | select(.headRefName|test("$(ISSUE)")) | .number' | head -1)}"; \ + if [ -z "$$PR" ]; then \ + echo "no open PR found for issue $(ISSUE). Run \`make next-issue ISSUE=$(ISSUE)\` first."; \ + exit 1; \ + fi; \ + echo "==> squash-merging PR #$$PR with admin override (closes #$(ISSUE))"; \ + gh pr merge "$$PR" --squash --delete-branch --admin \ + --body "Closes #$(ISSUE). Squash-merged per CONTRIBUTING.md."; \ + echo "==> syncing local main"; \ + git checkout main && git pull --ff-only origin main; \ + git remote prune origin; \ + echo "==> verifying issue #$(ISSUE) auto-closed"; \ + STATE=$$(gh issue view $(ISSUE) --json state --jq .state); \ + if [ "$$STATE" = "CLOSED" ]; then \ + echo "✓ issue #$(ISSUE) is CLOSED"; \ + else \ + echo "warning: issue #$(ISSUE) is still $$STATE — closing manually"; \ + gh issue close $(ISSUE) -c "Closed by PR #$$PR. Squash-merged per CONTRIBUTING.md."; \ + fi \ No newline at end of file