Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
150 commits
Select commit Hold shift + click to select a range
6a55fa1
fix: remove dead 1inch IPFS token list and make fetching resilient
fernandomg Mar 30, 2026
3542546
feat: add useWalletStatus hook with tests
fernandomg Mar 30, 2026
63f94f3
refactor: WalletStatusVerifier uses useWalletStatus hook, remove HoC
fernandomg Mar 30, 2026
91357b8
refactor: TransactionButton internalizes wallet verification
fernandomg Mar 30, 2026
ba1d482
refactor: SignButton internalizes wallet verification
fernandomg Mar 30, 2026
544e17f
refactor: demo components use WalletStatusVerifier wrapper instead of…
fernandomg Mar 30, 2026
c9f54aa
chore: fix TypeDoc warnings for TransactionButton and SignButton
fernandomg Mar 30, 2026
2bbdfd4
fix: address Copilot review feedback
fernandomg Mar 30, 2026
b4607fc
fix: remove unused label prop from SignButtonProps
fernandomg Mar 31, 2026
6d08c28
feat: enforce useWeb3StatusConnected via WalletStatusVerifier context
fernandomg Mar 31, 2026
b6e5632
fix: prevent .env.local RPC values from leaking into test env
fernandomg Mar 31, 2026
a614bea
chore: bump pnpm to 10.33.0
fernandomg Mar 31, 2026
722dc65
chore: merge latest develop
fernandomg Mar 31, 2026
2ae1d9d
Merge pull request #427 from BootNodeDev/feat/303-hoc-to-hooks
fernandomg Apr 1, 2026
ee1fa02
Merge branch 'develop' into fix/token-list-ipfs-504
fernandomg Apr 1, 2026
ea2f1b6
docs: add SDLC sections to agent configuration files
gabitoesmiapodo Apr 1, 2026
64e1ff4
chore: add wip and release to commitlint allowed types
gabitoesmiapodo Apr 1, 2026
5198fbc
chore: add pull request template
gabitoesmiapodo Apr 1, 2026
85c2903
chore: add structured issue templates for bugs, features, epics, and …
gabitoesmiapodo Apr 1, 2026
3e3949d
chore: add issue creation skill for Claude Code
gabitoesmiapodo Apr 1, 2026
5a0d193
Merge pull request #428 from BootNodeDev/fix/token-list-ipfs-504
fernandomg Apr 1, 2026
b53b358
docs: add architecture overview and consolidate structural docs
gabitoesmiapodo Apr 1, 2026
9bec715
chore: sync hotfix and release commit types across all validators
gabitoesmiapodo Apr 1, 2026
296ef21
ci: add PR self-assignment workflow
gabitoesmiapodo Apr 1, 2026
7add947
Merge branch 'develop' into feat/add-sdlc
gabitoesmiapodo Apr 1, 2026
3a00be1
docs: update architecture.md reference from AGENTS.md to CLAUDE.md
gabitoesmiapodo Apr 1, 2026
03f85a5
docs: update bug template reference from AGENTS.md to CLAUDE.md
gabitoesmiapodo Apr 1, 2026
ead606d
docs: update feature template reference from AGENTS.md to CLAUDE.md
gabitoesmiapodo Apr 1, 2026
71ebfd6
docs: update epic template reference from AGENTS.md to CLAUDE.md
gabitoesmiapodo Apr 1, 2026
5d75522
docs: update issue skill reference from AGENTS.md to CLAUDE.md
gabitoesmiapodo Apr 1, 2026
f21234f
docs: update Node placeholder in bug template to 24.x
gabitoesmiapodo Apr 1, 2026
615e6d4
Merge pull request #430 from BootNodeDev/feat/add-sdlc
gabitoesmiapodo Apr 1, 2026
cdc596a
chore: update patch dependencies
gabitoesmiapodo Apr 1, 2026
0417756
chore: update minor dependencies
gabitoesmiapodo Apr 1, 2026
12126f3
chore: update typedoc-github-theme and uniswap token list
gabitoesmiapodo Apr 1, 2026
eadb01f
chore: update medium-risk dependencies
gabitoesmiapodo Apr 1, 2026
6886246
chore: update typescript to v6
gabitoesmiapodo Apr 1, 2026
5210922
chore: update zod to v4
gabitoesmiapodo Apr 2, 2026
ce05901
chore: update @graphql-codegen/cli to v6
gabitoesmiapodo Apr 2, 2026
6912547
chore: document pnpm override for graphql-codegen
gabitoesmiapodo Apr 2, 2026
9e3781d
chore: update vite to v8
gabitoesmiapodo Apr 2, 2026
d8f5355
chore: broaden manualChunks coverage for sub-scoped packages
gabitoesmiapodo Apr 2, 2026
a7c6ce1
chore: replace vite-tsconfig-paths plugin with native tsconfigPaths o…
gabitoesmiapodo Apr 2, 2026
be4df76
chore: replace @vitejs/plugin-react-swc with @vitejs/plugin-react
gabitoesmiapodo Apr 2, 2026
a8cb401
chore: fix biome 2 lint warnings
gabitoesmiapodo Apr 2, 2026
8dadc14
fix: restore fragment with suppression after noUselessFragments auto-fix
gabitoesmiapodo Apr 2, 2026
9b25bc3
docs: fix typedoc param warnings in suspenseWrapper and include Token…
gabitoesmiapodo Apr 2, 2026
29dc29f
refactor: use block-bodied callbacks for side-effect-only arrow funct…
gabitoesmiapodo Apr 2, 2026
7c2656d
chore: bump @uniswap/default-token-list 18.12.0 -> 18.13.0
gabitoesmiapodo Apr 6, 2026
f4b453a
Merge pull request #437 from BootNodeDev/chore/update-deps
gabitoesmiapodo Apr 6, 2026
8cc1bc7
chore: update medium-risk dependencies
gabitoesmiapodo Apr 1, 2026
b682be0
Merge pull request #439 from BootNodeDev/chore/update-medium-risk-deps
gabitoesmiapodo Apr 6, 2026
3f8631a
Merge branch 'develop' into chore/update-high-risk-deps
gabitoesmiapodo Apr 6, 2026
7d420b4
fix: resolve react-jazzicon CJS interop for Vite 8 and add WalletConn…
gabitoesmiapodo Apr 6, 2026
4e62713
fix: migrate from deprecated @tanstack/router-devtools to @tanstack/r…
gabitoesmiapodo Apr 6, 2026
00cf7bc
fix: use page origin for WalletConnect metadata URL
gabitoesmiapodo Apr 6, 2026
a399071
fix: skip Porto initialization on insecure origins
gabitoesmiapodo Apr 6, 2026
6212380
fix: provide buffer polyfill for @lifi/sdk browser compatibility
gabitoesmiapodo Apr 6, 2026
8387f3d
fix: prevent duplicate printAppInfo output in StrictMode
gabitoesmiapodo Apr 6, 2026
21a6156
Merge pull request #440 from BootNodeDev/chore/update-high-risk-deps
gabitoesmiapodo Apr 6, 2026
03154b9
chore: update ignore list
gabitoesmiapodo Apr 6, 2026
c8a7e99
fix: add flexDirection column to MenuContent to fix dropdown layout
gabitoesmiapodo Apr 6, 2026
8044665
fix: use CORS-friendly public RPCs as fallbacks when no PUBLIC_RPC_* …
gabitoesmiapodo Apr 6, 2026
7a0b481
docs: clarify which RPC vars get publicnode fallbacks in .env.example
gabitoesmiapodo Apr 6, 2026
3926e5f
docs: group RPC vars in .env.example by whether they have automatic f…
gabitoesmiapodo Apr 6, 2026
99dd367
docs: clarify unconfigured chains need to be added to networks.config…
gabitoesmiapodo Apr 6, 2026
03a4f4f
docs: clarify both RPC sections reference networks.config.ts
gabitoesmiapodo Apr 6, 2026
34c81d3
Merge pull request #444 from BootNodeDev/fix/443
gabitoesmiapodo Apr 7, 2026
a579bd0
Merge branch 'develop' into fix/441
gabitoesmiapodo Apr 7, 2026
bdf3c1d
test: add coverage for fetchTokenList('default') bundled token path
gabitoesmiapodo Apr 7, 2026
466dd00
Merge pull request #445 from BootNodeDev/fix/441
gabitoesmiapodo Apr 7, 2026
8856a10
docs: clarify non-EVM token filtering in useTokenLists
gabitoesmiapodo Apr 7, 2026
cf36482
test: tighten default token path tests per code review
gabitoesmiapodo Apr 7, 2026
74c0362
Merge branch 'develop' into chore/438
gabitoesmiapodo Apr 7, 2026
3b21251
Merge pull request #447 from BootNodeDev/chore/438
gabitoesmiapodo Apr 9, 2026
394219f
fix(token-input): format max value with thousand separators
gabitoesmiapodo Apr 9, 2026
80cbb18
fix(token-input): cast displayVal type for NumericFormat value prop
gabitoesmiapodo Apr 9, 2026
ec841b6
fix(token-input): use as any cast in test renderInput to match TokenA…
gabitoesmiapodo Apr 9, 2026
fdbe05a
fix(big-number-input): initialize displayValue from initial value prop
gabitoesmiapodo Apr 9, 2026
fdb5e09
test(big-number-input): add test for non-zero initial value with rend…
gabitoesmiapodo Apr 9, 2026
7bfa231
test(big-number-input): exclude inputRef from NumericFormat spread in…
gabitoesmiapodo Apr 9, 2026
7821c8a
fix(big-number-input): guard displayValue sync behind renderInput check
gabitoesmiapodo Apr 9, 2026
0a2a4ef
fix(big-number-input): skip displayValue updates on native input path
gabitoesmiapodo Apr 9, 2026
0ff495b
fix: destructure decimal part in TokenAmountField isAllowed validator
gabitoesmiapodo Apr 10, 2026
724469b
Merge pull request #450 from BootNodeDev/fix/295
gabitoesmiapodo Apr 10, 2026
b2d4034
Merge pull request #456 from BootNodeDev/fix/451
gabitoesmiapodo Apr 10, 2026
c3c99a5
fix: use error toast type in watchSignature catch block
gabitoesmiapodo Apr 10, 2026
1a86f58
test: use top-level import in SignButton tests
gabitoesmiapodo Apr 10, 2026
9e1d4e2
docs: sync architecture.md with current codebase
gabitoesmiapodo Apr 10, 2026
cc578ef
fix: type WalletStatusVerifier children as ReactNode instead of React…
gabitoesmiapodo Apr 10, 2026
23a5e8a
docs: fix useWeb3StatusConnected description in architecture.md
gabitoesmiapodo Apr 10, 2026
ff659a5
Merge pull request #460 from BootNodeDev/fix/454-wallet-status-verifi…
gabitoesmiapodo Apr 10, 2026
3cb4415
Merge pull request #458 from BootNodeDev/fix/455-signbutton-test-imports
gabitoesmiapodo Apr 10, 2026
425cfb3
Merge pull request #457 from BootNodeDev/fix/453
gabitoesmiapodo Apr 10, 2026
29e78be
Merge branch 'develop' into fix/452
gabitoesmiapodo Apr 10, 2026
891f992
docs: correct chain comparison reference in WalletStatusVerifier docs
gabitoesmiapodo Apr 10, 2026
528a331
Merge pull request #459 from BootNodeDev/fix/452
gabitoesmiapodo Apr 10, 2026
f31ea12
feat: add Sepolia to TokenInput demo network selector
gabitoesmiapodo Apr 20, 2026
c7c43b1
feat(token-select): add Sepolia support with AAVE faucet tokens and g…
gabitoesmiapodo Apr 20, 2026
c5d24f7
fix(token-select): address code review findings for Sepolia support
gabitoesmiapodo Apr 20, 2026
4325072
feat(token-input): default to multi token mode in demo
gabitoesmiapodo Apr 20, 2026
44fb397
fix(token-select): fix CloseButton layout and children render position
gabitoesmiapodo Apr 20, 2026
06104b6
fix(token-input): bind native balance client to selected token chain
gabitoesmiapodo Apr 20, 2026
9baf5fa
fix(token-select): map LI.FI native address to configured sentinel
gabitoesmiapodo Apr 20, 2026
0bc38ab
fix(token-input): drive USD "N/A" label from active chain, not token …
gabitoesmiapodo Apr 20, 2026
fb2660f
refactor: simplify token input and balance code
gabitoesmiapodo Apr 20, 2026
3cad9a9
fix(token-input): guard native balance query when wallet is disconnected
gabitoesmiapodo Apr 21, 2026
2af0235
Merge pull request #462 from BootNodeDev/feat/461
gabitoesmiapodo Apr 21, 2026
e8fcfcd
fix(token-input): display balance USD value and show spinner while lo…
gabitoesmiapodo Apr 21, 2026
373f72e
refactor(token-input): remove redundant testnet guard and unnecessary…
gabitoesmiapodo Apr 21, 2026
fa4a12f
fix(token-input): compare token addresses case-insensitively when res…
gabitoesmiapodo Apr 21, 2026
24715bf
refactor(use-tokens): expose dedicated isLoadingPrices signal
gabitoesmiapodo Apr 21, 2026
3035958
docs(token-input): document priceUSD and isLoadingPrice return fields
gabitoesmiapodo Apr 21, 2026
5d76641
Merge pull request #463 from BootNodeDev/fix/393
gabitoesmiapodo Apr 21, 2026
32cdc6c
feat(token-logo): render chain icons for native tokens
gabitoesmiapodo Apr 21, 2026
9b23e83
Merge branch 'develop' into fix/393
gabitoesmiapodo Apr 21, 2026
7253982
test(token-logo): assert no svg in unmapped-chain fallback test
gabitoesmiapodo Apr 21, 2026
0454a80
refactor(token-logo): apply code-review fixes
gabitoesmiapodo Apr 21, 2026
9ae8e55
docs(token-logo): correct native-token detection reference in JSDoc
gabitoesmiapodo Apr 21, 2026
505e6ef
refactor(token-logo): type native icon map as Partial to model unmapp…
gabitoesmiapodo Apr 21, 2026
bec0209
Merge pull request #464 from BootNodeDev/feat/164
gabitoesmiapodo Apr 21, 2026
940e33f
fix(token-lists): drop tokens whose chainId is absent from viem/chains
gabitoesmiapodo Apr 21, 2026
c7ee0ad
refactor(token-lists): replace supportedChainIds Set with shared chai…
gabitoesmiapodo Apr 21, 2026
72059eb
fix(token-lists): annotate chainsById key as number to satisfy tsc
gabitoesmiapodo Apr 21, 2026
fc65ac9
fix(token-lists): preserve first-wins semantics in chainsById and dro…
gabitoesmiapodo Apr 21, 2026
6e2d2a6
fix: pair logger.timeEnd for 'updating tokens cache' in useTokens
gabitoesmiapodo Apr 21, 2026
35b4548
Merge pull request #470 from BootNodeDev/fix/465
gabitoesmiapodo Apr 21, 2026
defa556
Merge branch 'develop' into fix/467
gabitoesmiapodo Apr 21, 2026
1422fd9
Merge pull request #471 from BootNodeDev/fix/467
gabitoesmiapodo Apr 21, 2026
922dacc
fix(use-tokens): route LI.FI RPC calls through configured transports
gabitoesmiapodo Apr 21, 2026
7103b43
Merge branch 'develop' into fix/469
gabitoesmiapodo Apr 21, 2026
5341cf6
fix(use-tokens): route LI.FI RPC calls through configured transports
gabitoesmiapodo Apr 21, 2026
ebf6a48
Merge pull request #473 from BootNodeDev/fix/469
gabitoesmiapodo Apr 21, 2026
fb803fe
chore: sync SDLC files with bootnode-sdlc starter-kit
gabitoesmiapodo Apr 21, 2026
8615ab3
fix(issue-template): update Node version placeholder to 24.x
gabitoesmiapodo Apr 21, 2026
d1c6ed6
fix(skill): move inline comment above line continuation in issue crea…
gabitoesmiapodo Apr 21, 2026
3465e8e
Merge pull request #474 from BootNodeDev/chore/472
gabitoesmiapodo Apr 21, 2026
165c167
feat(token-select): sort by positive balance by default when wallet c…
gabitoesmiapodo Apr 21, 2026
ebb18fb
refactor(wallet): expose web3Status from useWalletStatus to avoid dou…
gabitoesmiapodo Apr 21, 2026
f1a8adc
fix: address normalisation in multicall path and complete web3Status …
gabitoesmiapodo Apr 21, 2026
9f5b773
test(transaction-button): replace web3Status undefined cast with vali…
gabitoesmiapodo Apr 21, 2026
d8c5ae2
test(sign-button): replace web3Status undefined cast with valid stub
gabitoesmiapodo Apr 21, 2026
0897b15
fix(token-select): decouple sortByBalance from balance fetching
gabitoesmiapodo Apr 21, 2026
ae04e6c
Merge pull request #475 from BootNodeDev/feat/466
gabitoesmiapodo Apr 21, 2026
333beff
fix(header): remove fixed height from logo to preserve aspect ratio
gabitoesmiapodo Apr 21, 2026
a8947fa
fix(menu): remove trailing divider from last menu item
gabitoesmiapodo Apr 21, 2026
f16a652
fix(menu): suppress border on last item hover and active states
gabitoesmiapodo Apr 21, 2026
cf2752e
Merge pull request #478 from BootNodeDev/fix/476-logo-stretched
gabitoesmiapodo Apr 21, 2026
e170d51
Merge pull request #479 from BootNodeDev/fix/477-token-select-last-di…
gabitoesmiapodo Apr 21, 2026
f7d0de0
release: bump version to 2.5.0
gabitoesmiapodo Apr 21, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
203 changes: 203 additions & 0 deletions .claude/skills/create-pr/SKILL.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,203 @@
---
name: sdlc:create-pr
description: Use when creating a pull request -- reads the PR template, auto-fills from git context and linked issue, confirms with the user, then creates via gh CLI.
---

# /sdlc:create-pr

Create a well-structured GitHub pull request by reading the repo's PR template and filling it from context.

**Core principle:** Templates own the format. Context owns the content. User owns the final word.

## Template Location

Read `.github/PULL_REQUEST_TEMPLATE.md` relative to the project root on every invocation. This path is fixed -- do not search for it.

## Core Pattern

1. **Gather** -- Collect all inputs silently. Ask only when auto-derivation fails.
2. **Draft** -- Fill every template section from the gathered context.
3. **Confirm** -- Show the full draft. Wait for explicit approval. Iterate.
4. **Create** -- Run `gh pr create` with `--body-file`. Report the URL.

## Step 1: Gather

**Auto-derive (no user interaction):**

- Read `.github/PULL_REQUEST_TEMPLATE.md`
- Run `git diff <base>...HEAD` -- the branch diff
- Run `git log <base>..HEAD --oneline` -- the commit history
- Extract issue number from branch name (pattern: `type/NNN-description`, e.g., `feat/17-add-skill` → `#17`)
- If issue number found, run `gh issue view NNN --json title,body,labels` and extract acceptance criteria from the body

**Ask when needed (use multiple-choice where possible):**

| Question | When | Options |
|----------|------|---------|
| "Which issue does this PR close?" | Branch name has no issue number | List of recent open issues (via `gh issue list --state open --limit 5 --json number,title`) + "None" + Other |
| "PR type?" | Always; pre-select "Ready for review" | "Ready for review" / "Draft" |
| "Base branch?" | Always; **must be asked even when auto-detected** -- the auto-detected value is the pre-selected default, not a reason to skip | Branch we branched from (auto-detected via `git merge-base` against known remote branches; pre-selected as default) / `develop` (if present in remote) / `main` / Other |
| "Who should review this PR?" | Always; multi-select | All reviewers returned by script (see below), in order, plus "Other" as the last option |
| "Who should this PR be assigned to?" | Always; pre-select "Me" | "Me" (resolved via `gh api user --jq '.login'`) / "Nobody" (default if "Me" feels presumptuous) / Other |
| "Which checklist items have you completed?" | Always; multi-select; zero selections is valid (means none completed yet) | "Self-reviewed my own diff" / "Tests added or updated" / "Docs updated (if applicable)" / "No unrelated changes bundled in" |
| "Will you add screenshots to this PR?" | Always | "Yes, I'll add them after creation" / "No" (default) |

### Helper scripts

**IMPORTANT:** Do NOT run `bash .claude/skills/create-pr/*.sh` directly -- that path only works for project-local installs. Always use the commands below, which resolve the script location first.

Auto-detect base branch:

```bash
if [[ -f .claude/skills/create-pr/get-base-branch.sh ]]; then bash .claude/skills/create-pr/get-base-branch.sh; elif [[ -f "$HOME/.claude/skills/create-pr/get-base-branch.sh" ]]; then bash "$HOME/.claude/skills/create-pr/get-base-branch.sh"; fi
```

It outputs the branch name (e.g., `main`, `develop`) whose merge-base with HEAD is most recent -- i.e., the branch we most likely forked from. Present it as the pre-selected default in the base branch question.

Fetch recent reviewers:

```bash
if [[ -f .claude/skills/create-pr/get-reviewers.sh ]]; then bash .claude/skills/create-pr/get-reviewers.sh; elif [[ -f "$HOME/.claude/skills/create-pr/get-reviewers.sh" ]]; then bash "$HOME/.claude/skills/create-pr/get-reviewers.sh"; fi
```

It outputs up to 4 reviewer logins, one per line, ordered most-recent-first (excludes the current user; falls back to alphabetical collaborators for new repos). Show every login the script returns as an option, in the exact order returned. Add "Other" as the last option. Do not add a "Skip" or "None" option -- if the user wants no reviewers, they select only "Other" and leave it empty.

Do not add labels to the PR. Labels are managed separately.

## Step 2: Draft

### PR Title

Conventional commit format: `type(scope): subject` or `type: subject`.

Allowed types: `feat`, `fix`, `docs`, `test`, `ci`, `refactor`, `perf`, `chore`, `revert`, `wip`, `build`, `style`, `release`.

<!-- Standard Conventional Commits prefixes only, matching the types documented in CLAUDE.md. Projects adopting this starter kit can extend this list to suit their conventions. -->

- Derive from branch name and commit history
- Scope is optional
- Subject: lowercase, imperative mood, no trailing period

### PR Body

Fill every section in template order. Strip all HTML comments (`<!-- ... -->`).

#### Summary

First line: `Closes #`

If no linked issue, first line: `No related issue. <one sentence motivation>`

Followed by 1-3 sentences synthesizing commits and issue description, focused on *why* not *what*. If no issue is linked, derive from commits and branch name only.

#### Changes

Bullet list. Each bullet = one discrete change from the diff or commit messages.

#### Acceptance criteria

- **Issue has AC:** Mirror as checkboxes. Check off items the diff demonstrates are fulfilled.
- **Issue has no AC, or no issue:** Suggest AC based on the changes made. Present as unchecked checkboxes.
- **AC diverged from issue:** Note it explicitly. Example: "Note: criterion X was moved to #M" or "Added: Y discovered during implementation."

#### Test plan

Two subsections, always present:

##### Automated tests
List test files added/modified in the diff and the command to run them. If none: `No automated tests added.`

##### Manual verification
If the change has user-facing or integration behavior, list manual steps. If purely internal: `No manual steps required.`

#### Breaking changes

If breaking changes detected (API changes, removed exports, schema changes): describe what breaks and migration steps.

If none: `None.`

#### Checklist

Render all four items based on the user's selections from the Gather step:

- Items selected by the user → `- [x] <item>`
- Items not selected → `- [ ] <item>`

The four items, in order:

1. Self-reviewed my own diff
2. Tests added or updated
3. Docs updated (if applicable)
4. No unrelated changes bundled in

#### Screenshots

Based on the Step 1 answer:

- "Yes": `To be added after PR creation.` (remind user to attach via GitHub UI)
- "No" (default): `None.`

**The section is always present.**

## Step 3: Confirm

Show to the user:
- PR title
- Complete body (all sections, no HTML comments)
- Target base branch
- The exact `gh pr create` command that will run

Wait for explicit approval. Accept edits to any section. Loop until approved.

## Step 4: Create

```bash
BODY_FILE=$(mktemp /tmp/gh_pr_body_XXXXXX)

# Replace the placeholder below with the actual drafted PR body:
cat > "$BODY_FILE" << 'EOF'
{{PR_BODY}}
EOF

gh pr create \
--title "<title>" \
--base "<base-branch>" \
--body-file "$BODY_FILE" \
[--reviewer <handle> ...] \
[--assignee <handle>]
```

Add `--draft` if user selected "Draft" in Step 1. Add one `--reviewer <handle>` flag per reviewer selected in Step 1; if "Other" was selected, use the handle the user provided. Add `--assignee <handle>` using the resolved login if "Me" or "Other" was selected; omit if "Nobody".

After reporting the PR URL: if the user selected "Yes" for screenshots in Step 1, remind them to attach screenshots via the GitHub UI.

## Edge Cases

### Branch is behind base
Present options:
1. **Continue as-is** -- create the PR and note it's behind
2. **Rebase onto base** -- run `git rebase <base>`; if conflicts, help resolve
3. **Merge base in** -- run `git merge <base>`; if conflicts, help resolve
4. **Abort** -- stop; do not create the PR

### No commits ahead of base
Stop. "No commits ahead of `<base>`. Nothing to create a PR from."

## Common Mistakes

- **Reconstructing the template from memory** -- read `.github/PULL_REQUEST_TEMPLATE.md` every time.
- **Generating an ad-hoc format** -- every section from the template must appear, in template order.
- **Creating before confirmation** -- never run `gh pr create` without explicit user approval.
- **Leaving HTML comments** -- strip all `<!-- ... -->` from the output.
- **Silently omitting `Closes #`** -- if no issue, say so explicitly on the first line.
- **Deleting empty sections** -- Breaking changes and Screenshots are always present; use `None.`
- **Ignoring AC divergence** -- note explicitly when PR criteria differ from the issue's.
- **Skipping the base-branch question** -- always present it. Auto-detection provides the default, not the answer.

## Installation

This skill includes helper scripts alongside `SKILL.md`. When installing or updating, copy (or symlink) the **entire `create-pr/` directory** -- not just `SKILL.md`. All files in this directory are required:

- `SKILL.md` -- skill definition
- `get-base-branch.sh` -- auto-detects the base branch
- `get-reviewers.sh` -- fetches recent reviewer logins
60 changes: 60 additions & 0 deletions .claude/skills/create-pr/get-base-branch.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
#!/usr/bin/env bash
set -euo pipefail

# Find the base branch: the most likely target for a pull request.
#
# Strategy: pick the remote branch whose merge-base with HEAD is most recent
# (i.e., the branch we most likely forked from). This works even when the
# base branch has advanced past the fork point.
#
# 1. Check well-known stable branches first (main, master, develop, staging).
# Among those that exist, pick the one with the closest merge-base to HEAD.
# 2. If none match, fall back to any remote branch with the closest merge-base.

current=$(git rev-parse --abbrev-ref HEAD)

# Priority 1: well-known base branches -- pick closest merge-base
best_branch=""
best_ts=0

for candidate in main master develop staging; do
ref="origin/$candidate"
git rev-parse --verify "$ref" >/dev/null 2>&1 || continue
[[ "$candidate" == "$current" ]] && continue
mb=$(git merge-base HEAD "$ref" 2>/dev/null) || continue
ts=$(git log -1 --format=%ct "$mb" 2>/dev/null) || continue
[[ -n "$ts" ]] || continue
if (( ts > best_ts )); then
best_ts=$ts
best_branch=$candidate
fi
done

if [[ -n "$best_branch" ]]; then
echo "$best_branch"
exit 0
fi

# Priority 2: any other remote branch, pick closest merge-base
best_branch=""
best_ts=0

while IFS= read -r ref; do
branch="${ref#origin/}"
[[ "$branch" == "HEAD" ]] && continue
[[ "$branch" == "$current" ]] && continue
mb=$(git merge-base HEAD "$ref" 2>/dev/null) || continue
ts=$(git log -1 --format=%ct "$mb" 2>/dev/null) || continue
[[ -n "$ts" ]] || continue
if (( ts > best_ts )); then
best_ts=$ts
best_branch=$branch
fi
done < <(git for-each-ref --format='%(refname:short)' refs/remotes/origin/)

if [[ -z "$best_branch" ]]; then
echo "No base branch found" >&2
exit 1
fi

echo "$best_branch"
34 changes: 34 additions & 0 deletions .claude/skills/create-pr/get-reviewers.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
#!/usr/bin/env bash
set -euo pipefail

me=$(gh api user --jq '.login' 2>/dev/null) || true

# Attempt: recent PR reviewers sorted by most-recent-first
reviewers=$(
gh pr list --state all --limit 20 --json reviews \
--jq "
[ .[].reviews[]
| { login: .author.login, ts: .submittedAt }
]
| sort_by(.ts) | reverse
| map(.login)
| map(select(. != \"$me\"))
| reduce .[] as \$x (
{ seen: {}, out: [] };
if .seen[\$x] then . else { seen: (.seen | .[\$x] = true), out: (.out + [\$x]) } end
)
| .out[:4]
| .[]
" 2>/dev/null || true
)

if [[ -n "$reviewers" ]]; then
echo "$reviewers"
exit 0
fi

# Fallback: collaborators (alphabetical, excluding self)
repo=$(gh repo view --json nameWithOwner -q .nameWithOwner 2>/dev/null) || exit 0
gh api "/repos/$repo/collaborators" \
--jq "[ .[].login | select(. != \"$me\") ] | sort | .[:4] | .[]" \
2>/dev/null || true
87 changes: 87 additions & 0 deletions .claude/skills/issue/SKILL.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,87 @@
---
name: sdlc:issue
description: Use when creating a GitHub issue from a brief -- bug, feature, epic, or spike -- against the repo's GitHub issue templates via gh CLI.
---

# /sdlc:issue

Create a well-structured GitHub issue using the repo's own templates and `gh` CLI.

**Core principle:** Templates own the format. Skill owns the behavior.

## Core Pattern

1. **Classify** -- Determine type from brief: bug / feature / epic / spike. If unclear, ask once.
2. **Read** -- Load `.github/ISSUE_TEMPLATE/<type>.yml`. Extract all fields, required vs optional, and label. Do this every time -- never reconstruct from memory.
3. **Interview** -- Ask only for missing required fields. If the brief already covers a field, don't re-ask. Scale ceremony to issue weight.
4. **Draft** -- Build title and body. Sections follow template field order using `label` as heading. Omit empty optional fields.
5. **Confirm** -- Show full draft including labels. Wait for explicit approval. Iterate until approved.
6. **Create** -- Write body to temp file, run `gh issue create` with all labels, report issue URL.

## Title Format

Issue titles must be **natural language, sentence case** (code terms and command names retain their canonical casing) -- no conventional commit prefixes, no scope tags.

Conventional commit format (`type(scope): subject`) is for **commits and PR titles only**. It is not appropriate for issue titles, which appear in GitHub's issue list and must be scannable at a glance.

**Good:**
- `Issue skill defaults to conventional commit format for titles`
- `mktemp fails with .md suffix`
- `Add natural language title guidance to issue skill`

**Bad:**
- `fix(skills): mktemp fails with .md suffix`
- `fix: issue skill defaults to conventional commit format`
- `feat(issue): add title guidance`

Rule: if a reader has to mentally strip a prefix to understand the title, the title is wrong.

## Template Map

| Type | File | Type label | Additional labels |
|---------|-----------------|---------------|---------------------------|
| Bug | `1-bug.yml` | `bug` | `priority: <level>` |
| Feature | `2-feature.yml` | `enhancement` | `priority: <level>` |
| Epic | `3-epic.yml` | `epic` | `priority: <level>` |
| Spike | `4-spike.yml` | `spike` | -- |

## Labels

Priority is applied as a label, not a form dropdown. See the Label Conventions section in `CLAUDE.md` for the full table and descriptions.

- Bugs, features, and epics each get a `priority: <level>` label.
- Spikes don't carry priority.
- If the brief doesn't specify a level, ask once using a numbered list -- never default silently:

1. Critical
2. High
3. Medium
4. Low

## gh Command

```bash
BODY_FILE=$(mktemp /tmp/gh_issue_body_XXXXXX)

cat > "$BODY_FILE" << 'EOF'
<body>
EOF

gh issue create \
--title "<title>" \
--label "<type-label>" \
# omit the next label for spikes
--label "<priority-label>" \
--body-file "$BODY_FILE"
```

Multiple `--label` flags can be chained. The type label is always present. The priority label is added for bugs, features, and epics -- omit it for spikes.

Optional flags: `--assignee "<username>"`, `--milestone "<name>"`, `--project "<name>"`

## Common Mistakes

- **Skipping the template read** -- Field names and order come from the YAML, not assumptions. Read it every time.
- **Pre-emptively asking for optional fields** -- Required fields are the floor. Let the user volunteer the rest.
- **Creating before confirmation** -- Never run `gh` without explicit approval. Always show the full draft first.
- **Omitting priority labels** -- Form dropdowns do not survive `gh` CLI creation. Always apply these as labels.
Loading
Loading