@telelabsai/ship 1.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,41 @@
1
+ ---
2
+ name: git-ops
3
+ description: "Use this agent for git operations that produce verbose output (large diffs, long logs, merge conflicts). Keeps git output isolated from main session context. Spawns when committing many files, creating PRs, or resolving conflicts."
4
+ model: sonnet
5
+ tools: Bash, Read, Glob, Grep
6
+ ---
7
+
8
+ You are a git operations specialist. Execute cleanly and report concisely.
9
+
10
+ Activate `ship-version` skill by reading `.claude/skills/ship-version/SKILL.md` and its references.
11
+
12
+ ## Rules
13
+ - Use conventional commits: type(scope): description
14
+ - If ticket ID provided (--ticket or --jira) → add `Refs: <ID>` as commit footer
15
+ - Never force push to main/master/production
16
+ - Never commit .env, credentials, secrets, API keys
17
+ - Stage specific files, never `git add .`
18
+ - Never amend unless explicitly asked
19
+ - Never skip pre-commit hooks
20
+ - Show diff summary before committing
21
+ - Always confirm destructive operations with user
22
+
23
+ ## Workflow
24
+ 1. Run `git status` + `git diff --stat`
25
+ 2. Scan for secrets in staged changes
26
+ 3. Stage files (ask user or follow instructions)
27
+ 4. Build conventional commit message
28
+ 5. Commit and verify
29
+ 6. Report back concisely
30
+
31
+ ## Output Format
32
+ ```
33
+ staged: N files (+X/-Y lines)
34
+ security: passed
35
+ commit: HASH type(scope): description
36
+ ticket: ID (if provided)
37
+ ```
38
+
39
+ **Status:** DONE | DONE_WITH_CONCERNS | BLOCKED | NEEDS_CONTEXT
40
+ **Summary:** [1-2 sentences]
41
+ **Concerns/Blockers:** [if any]
@@ -0,0 +1,66 @@
1
+ /**
2
+ * PreToolUse hook — blocks dangerous git operations before they execute.
3
+ *
4
+ * Exit 0 = allow the tool call
5
+ * Exit 2 = block the tool call (stdout = reason shown to Claude)
6
+ */
7
+
8
+ const fs = require('fs');
9
+
10
+ let input;
11
+ try {
12
+ input = JSON.parse(fs.readFileSync('/dev/stdin', 'utf8'));
13
+ } catch {
14
+ process.exit(0); // can't parse → allow
15
+ }
16
+
17
+ const cmd = (input.tool_input && input.tool_input.command) || '';
18
+
19
+ // --- Block force push ---
20
+ if (/push\s+.*(-f|--force)(?!\S)/.test(cmd) && !cmd.includes('--force-with-lease')) {
21
+ console.log('BLOCKED: Force push is not allowed. Use --force-with-lease if absolutely necessary.');
22
+ process.exit(2);
23
+ }
24
+
25
+ // --- Block push to protected branches without confirmation ---
26
+ const protectedPush = /push\s+.*\b(main|master|production|prod)\b/.test(cmd);
27
+ if (protectedPush && !cmd.includes('--force-with-lease')) {
28
+ // Allow regular push to main, but block force variants
29
+ // The rule file handles the "ask user" part for regular pushes
30
+ }
31
+
32
+ // --- Block staging sensitive files ---
33
+ const sensitivePatterns = [
34
+ /git\s+add\s+.*\.env(?!\.\w*example)/,
35
+ /git\s+add\s+.*credentials/,
36
+ /git\s+add\s+.*\.pem/,
37
+ /git\s+add\s+.*\.key/,
38
+ /git\s+add\s+.*secrets?\./,
39
+ ];
40
+
41
+ for (const pattern of sensitivePatterns) {
42
+ if (pattern.test(cmd)) {
43
+ console.log('BLOCKED: Cannot stage sensitive files (.env, credentials, keys). Add to .gitignore instead.');
44
+ process.exit(2);
45
+ }
46
+ }
47
+
48
+ // --- Block git add -A / git add . (encourage specific staging) ---
49
+ if (/git\s+add\s+(-A|--all|\.)(\s|$)/.test(cmd)) {
50
+ console.log('BLOCKED: Use specific file names instead of "git add ." or "git add -A" to avoid staging secrets or unwanted files.');
51
+ process.exit(2);
52
+ }
53
+
54
+ // --- Block destructive resets without warning ---
55
+ if (/git\s+reset\s+--hard/.test(cmd)) {
56
+ console.log('BLOCKED: "git reset --hard" discards all uncommitted changes. Ask the user to confirm first.');
57
+ process.exit(2);
58
+ }
59
+
60
+ // --- Block branch deletion of protected branches ---
61
+ if (/git\s+branch\s+.*-[dD]\s+.*(main|master|production|prod)/.test(cmd)) {
62
+ console.log('BLOCKED: Cannot delete protected branches (main, master, production).');
63
+ process.exit(2);
64
+ }
65
+
66
+ process.exit(0);
@@ -0,0 +1,17 @@
1
+ # Git Conventions
2
+
3
+ ## Commit Format
4
+ ```
5
+ type(scope): description
6
+
7
+ Refs: TICKET-ID ← only if provided by user via --ticket or --jira
8
+ ```
9
+
10
+ ## Types
11
+ feat | fix | refactor | test | docs | chore | perf | style | ci | build
12
+
13
+ ## Rules
14
+ - Under 72 chars, present tense, imperative, no period
15
+ - No AI attribution in commits
16
+ - Never commit .env or secrets
17
+ - Stage specific files, not `git add .`
@@ -0,0 +1,16 @@
1
+ {
2
+ "$schema": "https://json.schemastore.org/claude-code-settings.json",
3
+ "hooks": {
4
+ "PreToolUse": [
5
+ {
6
+ "matcher": "Bash",
7
+ "hooks": [
8
+ {
9
+ "type": "command",
10
+ "command": "node .claude/hooks/git-safety.cjs"
11
+ }
12
+ ]
13
+ }
14
+ ]
15
+ }
16
+ }
@@ -0,0 +1,118 @@
1
+ ---
2
+ name: ship-version
3
+ description: "Git version control with conventional commits and optional ticket tracking (Jira, Trello, ClickUp, Linear, GitHub Issues, etc). Use for committing, pushing, branching, PRs, diffs, and changelogs."
4
+ argument-hint: "<commit|push|pr|branch|diff|changelog> [--ticket ID] [--type feat|fix|refactor|test|docs|chore] [message]"
5
+ ---
6
+
7
+ # ship-version — Git Version Control
8
+
9
+ ## Sub-commands
10
+
11
+ | Command | Description |
12
+ |---------|-------------|
13
+ | `commit` | Stage and commit with conventional format |
14
+ | `push` | Push current branch to remote |
15
+ | `pr` | Create pull request |
16
+ | `branch` | Create and switch to new branch |
17
+ | `diff` | Show clean change summary |
18
+ | `changelog` | Generate changelog from commits between versions |
19
+
20
+ ## Default (No Arguments)
21
+
22
+ If invoked without arguments, use `AskUserQuestion` to present available operations.
23
+
24
+ ## Arguments
25
+
26
+ - `commit [--ticket ID] [--type TYPE] [message]` — Stage + commit
27
+ - `push` — Push to remote
28
+ - `pr [--ticket ID] [title]` — Create PR via `gh`
29
+ - `branch <name>` — Create + switch branch
30
+ - `diff [--staged] [--pr] [ref1..ref2]` — Show changes
31
+ - `changelog [from-tag] [to-tag]` — Generate changelog
32
+
33
+ ## Ticket Integration (optional)
34
+
35
+ The `--ticket` flag accepts any project management ticket ID. Auto-detected format:
36
+
37
+ | Tool | Example | Auto-detected pattern |
38
+ |------|---------|----------------------|
39
+ | Jira | `--ticket PROJ-123` | `[A-Z]+-\d+` |
40
+ | Trello | `--ticket #abc123` | Trello short ID |
41
+ | ClickUp | `--ticket CU-abc123` | `CU-` prefix |
42
+ | Linear | `--ticket ENG-123` | `[A-Z]+-\d+` |
43
+ | GitHub Issues | `--ticket #42` | `#\d+` |
44
+ | Shortcut | `--ticket sc-12345` | `sc-` prefix |
45
+ | Asana | `--ticket 1234567890` | Numeric ID |
46
+ | Custom | `--ticket ANYTHING` | Any string |
47
+
48
+ Multiple tickets supported: `--ticket PROJ-42 --ticket #15`
49
+
50
+ Legacy alias: `--jira` works as shorthand for `--ticket`
51
+
52
+ ## Quick Reference
53
+
54
+ | Task | Reference |
55
+ |------|-----------|
56
+ | Commit workflow | `references/workflow-commit.md` |
57
+ | Push workflow | `references/workflow-push.md` |
58
+ | PR workflow | `references/workflow-pr.md` |
59
+ | Diff workflow | `references/workflow-diff.md` |
60
+ | Changelog workflow | `references/workflow-changelog.md` |
61
+ | Commit format | `references/commit-standards.md` |
62
+ | Safety | `references/safety-protocols.md` |
63
+
64
+ ## Commit Format
65
+
66
+ ```
67
+ type(scope): description
68
+
69
+ [optional body]
70
+
71
+ [optional: Refs: TICKET-ID]
72
+ ```
73
+
74
+ ## Core Workflow
75
+
76
+ ### Step 1: Analyze
77
+ ```bash
78
+ git status && git diff --stat
79
+ ```
80
+
81
+ ### Step 2: Security Scan
82
+ ```bash
83
+ git diff --cached | grep -iE "(api[_-]?key|token|password|secret|credential)"
84
+ ```
85
+ If secrets found → STOP, warn user, suggest `.gitignore`.
86
+
87
+ ### Step 3: Stage
88
+ - Ask user what to stage (never `git add .` blindly)
89
+ - Stage specific files by name
90
+
91
+ ### Step 4: Build Commit Message
92
+ 1. Auto-detect type from diff (unless `--type` provided)
93
+ 2. Auto-detect scope from file paths
94
+ 3. Use user message if provided, else generate from diff
95
+ 4. If `--ticket` (or `--jira`) → append `Refs: <TICKET-ID>` as footer
96
+ 5. Show full message to user for confirmation
97
+
98
+ ### Step 5: Commit
99
+ ```bash
100
+ git commit -m "type(scope): description"
101
+ ```
102
+
103
+ ## Output Format
104
+ ```
105
+ staged: N files (+X/-Y lines)
106
+ security: passed
107
+ commit: HASH type(scope): description
108
+ ticket: PROJ-123 (if provided)
109
+ ```
110
+
111
+ ## Error Handling
112
+
113
+ | Error | Action |
114
+ |-------|--------|
115
+ | Secrets detected | Block commit, show files |
116
+ | No changes | Exit cleanly |
117
+ | Push rejected | Suggest `git pull --rebase` |
118
+ | Merge conflicts | Suggest manual resolution |
@@ -0,0 +1,97 @@
1
+ # Commit Standards
2
+
3
+ ## Format
4
+
5
+ ```
6
+ type(scope): description
7
+
8
+ [optional body]
9
+
10
+ [optional: Refs: TICKET-ID]
11
+ ```
12
+
13
+ ## Types (priority order)
14
+
15
+ | Type | When to use |
16
+ |------|-------------|
17
+ | `feat` | New feature or capability |
18
+ | `fix` | Bug fix |
19
+ | `refactor` | Restructure without behavior change |
20
+ | `test` | Adding or updating tests |
21
+ | `docs` | Documentation only |
22
+ | `chore` | Maintenance, deps, config |
23
+ | `perf` | Performance improvement |
24
+ | `style` | Formatting, no logic change |
25
+ | `ci` | CI/CD pipeline changes |
26
+ | `build` | Build system changes |
27
+
28
+ ## Rules
29
+
30
+ - Under 72 characters for subject line
31
+ - Present tense, imperative mood ("add" not "added")
32
+ - No period at end
33
+ - Scope is optional but recommended
34
+ - Focus on WHAT changed, not HOW
35
+ - No AI attribution (no "Generated with Claude", no "Co-Authored-By: Claude")
36
+
37
+ ## Ticket Integration (optional)
38
+
39
+ When `--ticket` flag is provided, append footer with the ticket ID.
40
+ Accepts any format: Jira (`PROJ-42`), Trello (`#abc`), ClickUp (`CU-abc`), Linear (`ENG-123`), GitHub Issues (`#42`), Shortcut (`sc-123`), Asana (numeric), or any custom string.
41
+
42
+ Legacy alias: `--jira` works as shorthand for `--ticket`.
43
+
44
+ ```
45
+ feat(auth): add login validation
46
+
47
+ Implement email format check and password strength meter.
48
+
49
+ Refs: PROJ-42
50
+ ```
51
+
52
+ Multiple tickets supported:
53
+
54
+ ```
55
+ Refs: PROJ-42, #15, CU-abc123
56
+ ```
57
+
58
+ ## Auto-detect Type from Diff
59
+
60
+ | Signal | Type |
61
+ |--------|------|
62
+ | New files, new exports | `feat` |
63
+ | Changed conditionals, error paths | `fix` |
64
+ | Moved/renamed, same behavior | `refactor` |
65
+ | `*.test.*`, `*.spec.*` files only | `test` |
66
+ | `*.md`, comments only | `docs` |
67
+ | `package.json`, config files only | `chore` |
68
+
69
+ ## Auto-detect Scope from Paths
70
+
71
+ | Path pattern | Scope |
72
+ |-------------|-------|
73
+ | `src/api/*`, `src/routes/*` | `api` |
74
+ | `src/components/*`, `src/ui/*` | `ui` |
75
+ | `src/db/*`, `src/models/*` | `db` |
76
+ | `src/auth/*` | `auth` |
77
+ | `src/utils/*`, `src/lib/*` | `utils` |
78
+ | Multiple directories | Omit scope |
79
+
80
+ ## Good Examples
81
+
82
+ ```
83
+ feat(auth): add login validation
84
+ fix(api): resolve query timeout on large datasets
85
+ refactor(utils): simplify date parsing logic
86
+ test(auth): add coverage for expired token edge case
87
+ chore: update dependencies to latest patch versions
88
+ ```
89
+
90
+ ## Bad Examples
91
+
92
+ ```
93
+ Updated files (not descriptive)
94
+ feat(auth): added login using bcrypt (past tense, describes HOW)
95
+ Fix bug (not specific)
96
+ WIP (not a commit message)
97
+ ```
@@ -0,0 +1,41 @@
1
+ # Safety Protocols
2
+
3
+ ## Secret Detection
4
+
5
+ ### Scan Command
6
+ ```bash
7
+ git diff --cached | grep -iE "(AKIA|api[_-]?key|token|password|secret|credential|private[_-]?key|mongodb://|postgres://|mysql://|redis://|-----BEGIN)"
8
+ ```
9
+
10
+ ### Patterns
11
+
12
+ | Category | Pattern |
13
+ |----------|---------|
14
+ | API Keys | `api[_-]?key`, `apiKey` |
15
+ | AWS | `AKIA[0-9A-Z]{16}` |
16
+ | Tokens | `token`, `auth_token`, `jwt` |
17
+ | Passwords | `password`, `passwd`, `pwd` |
18
+ | Private Keys | `-----BEGIN PRIVATE KEY-----` |
19
+ | DB URLs | `mongodb://`, `postgres://`, `mysql://` |
20
+ | OAuth | `client_secret`, `oauth_token` |
21
+
22
+ ### Dangerous Files
23
+ - `.env`, `.env.*` (except `.env.example`)
24
+ - `*.key`, `*.pem`, `*.p12`
25
+ - `credentials.json`, `secrets.json`
26
+
27
+ ### On Detection
28
+ 1. BLOCK commit
29
+ 2. Show matching lines
30
+ 3. Suggest `.gitignore` or env variables
31
+ 4. Offer to unstage: `git reset HEAD <file>`
32
+
33
+ ## Branch Protection
34
+
35
+ ### Never Force Push To
36
+ - `main`, `master`, `production`, `prod`, `release/*`
37
+
38
+ ### Never Without Confirmation
39
+ - Push to `main`/`master`
40
+ - Delete remote branches
41
+ - Rebase published branches
@@ -0,0 +1,95 @@
1
+ # Changelog Workflow
2
+
3
+ ## Modes
4
+
5
+ ### Auto-detect latest versions
6
+ If no tags provided:
7
+ ```bash
8
+ git tag --sort=-v:refname | head -5
9
+ ```
10
+ Pick the two most recent tags. If only one tag → changelog from that tag to HEAD.
11
+ If no tags → changelog from first commit to HEAD.
12
+
13
+ ### Specific range
14
+ ```
15
+ /lab:version changelog v1.0.0 v2.0.0
16
+ /lab:version changelog v1.0.0 # from v1.0.0 to HEAD
17
+ ```
18
+
19
+ ## Steps
20
+
21
+ ### 1. Get Commits
22
+ ```bash
23
+ git log <from>..<to> --pretty=format:"%h %s" --no-merges
24
+ ```
25
+
26
+ ### 2. Group by Type
27
+
28
+ Parse conventional commit prefixes and group:
29
+
30
+ ```markdown
31
+ ## [v2.0.0] - 2026-03-30
32
+
33
+ ### Features
34
+ - add user authentication (#42) — abc1234
35
+ - add dashboard widgets — def5678
36
+
37
+ ### Bug Fixes
38
+ - resolve login timeout on slow networks — 123abcd
39
+ - fix null check in payment flow — 456efgh
40
+
41
+ ### Refactoring
42
+ - simplify date utility functions — 789ijkl
43
+
44
+ ### Tests
45
+ - add coverage for auth edge cases — mno3456
46
+
47
+ ### Other
48
+ - update dependencies — pqr7890
49
+ ```
50
+
51
+ ### 3. Type Mapping
52
+
53
+ | Prefix | Section |
54
+ |--------|---------|
55
+ | `feat` | Features |
56
+ | `fix` | Bug Fixes |
57
+ | `refactor` | Refactoring |
58
+ | `perf` | Performance |
59
+ | `test` | Tests |
60
+ | `docs` | Documentation |
61
+ | `chore`, `build`, `ci`, `style` | Other |
62
+
63
+ ### 4. Enrich (optional)
64
+
65
+ If `Refs:` found in commit footers, append ticket IDs (any tool — Jira, Trello, ClickUp, etc.):
66
+ ```
67
+ - add user authentication (PROJ-42) — abc1234
68
+ - fix payment timeout (#15, CU-xyz) — def5678
69
+ ```
70
+
71
+ ### 5. Stats Summary
72
+
73
+ Append at bottom:
74
+ ```
75
+ ### Stats
76
+ - Commits: N
77
+ - Contributors: N
78
+ - Files changed: N
79
+ - Lines: +X / -Y
80
+ ```
81
+
82
+ ## Output
83
+
84
+ Print changelog to terminal. If user wants to save:
85
+ ```bash
86
+ # Prepend to existing CHANGELOG.md or create new
87
+ ```
88
+
89
+ ## Full Changelog (no tags)
90
+
91
+ If user just runs `/lab:version changelog` with no tags and no existing tags:
92
+ ```bash
93
+ git log --pretty=format:"%h %s" --no-merges
94
+ ```
95
+ Group all commits as `## [Unreleased]`.
@@ -0,0 +1,77 @@
1
+ # Commit Workflow
2
+
3
+ ## Step-by-step
4
+
5
+ ### 1. Check State
6
+ ```bash
7
+ git status
8
+ git diff --stat
9
+ ```
10
+ If nothing to commit → tell user and stop.
11
+
12
+ ### 2. Security Scan
13
+ ```bash
14
+ git diff --cached | grep -iE "(AKIA|api[_-]?key|token|password|secret|credential|private[_-]?key|mongodb://|postgres://|mysql://|redis://|-----BEGIN)"
15
+ ```
16
+
17
+ Files to always warn about:
18
+ - `.env`, `.env.*` (except `.env.example`)
19
+ - `*.key`, `*.pem`, `*.p12`
20
+ - `credentials.json`, `secrets.json`
21
+
22
+ If detected → BLOCK, show matches, suggest `.gitignore`.
23
+
24
+ ### 3. Stage Files
25
+ - Show user the list of changed files
26
+ - Ask what to stage (or accept their instruction)
27
+ - Stage specific files: `git add <file1> <file2>`
28
+ - NEVER use `git add .` or `git add -A`
29
+
30
+ ### 4. Determine Commit Type
31
+ Priority: user `--type` flag > auto-detection from diff
32
+
33
+ Auto-detection logic:
34
+ 1. Read `git diff --cached --name-only`
35
+ 2. Read `git diff --cached` for content changes
36
+ 3. Match against type rules in commit-standards.md
37
+
38
+ ### 5. Determine Scope
39
+ 1. Extract directories from changed files
40
+ 2. If all in one area → use as scope
41
+ 3. If multiple areas → omit scope
42
+
43
+ ### 6. Build Message
44
+ - If user provided message → use as description
45
+ - If `--jira` provided → add `Refs: <ID>` footer
46
+ - Show full message to user for confirmation
47
+
48
+ ### 7. Commit
49
+ ```bash
50
+ git commit -m "$(cat <<'EOF'
51
+ type(scope): description
52
+
53
+ Optional body.
54
+
55
+ Refs: JIRA-ID
56
+ EOF
57
+ )"
58
+ ```
59
+
60
+ ### 8. Verify
61
+ ```bash
62
+ git log --oneline -1
63
+ git status
64
+ ```
65
+
66
+ ## Split Decision
67
+
68
+ **Split into multiple commits if:**
69
+ - Different types mixed (feat + fix)
70
+ - Multiple unrelated scopes
71
+ - Config/deps + code mixed
72
+ - More than 10 unrelated files
73
+
74
+ **Single commit if:**
75
+ - Same type and scope
76
+ - 3 or fewer files
77
+ - Under 50 lines changed
@@ -0,0 +1,74 @@
1
+ # Diff Workflow
2
+
3
+ ## Modes
4
+
5
+ ### Default — Working changes
6
+ Show unstaged + staged changes:
7
+ ```bash
8
+ git diff --stat
9
+ git diff --cached --stat
10
+ ```
11
+
12
+ ### `--staged` — Staged only
13
+ ```bash
14
+ git diff --cached --stat
15
+ git diff --cached
16
+ ```
17
+
18
+ ### `--pr` — What a PR would contain
19
+ ```bash
20
+ git log main..HEAD --oneline
21
+ git diff main..HEAD --stat
22
+ git diff main..HEAD
23
+ ```
24
+
25
+ ### `ref1..ref2` — Compare between refs (branches, tags, commits)
26
+ ```bash
27
+ git diff <ref1>..<ref2> --stat
28
+ git diff <ref1>..<ref2>
29
+ ```
30
+
31
+ Examples:
32
+ ```
33
+ /lab:version diff v1.0.0..v2.0.0 # between tags
34
+ /lab:version diff main..feature/auth # between branches
35
+ /lab:version diff abc123..def456 # between commits
36
+ ```
37
+
38
+ ## Output Format
39
+
40
+ Present a clean summary:
41
+
42
+ ```
43
+ ## Changes: <context>
44
+
45
+ ### Stats
46
+ - Files changed: N
47
+ - Insertions: +X
48
+ - Deletions: -Y
49
+
50
+ ### Files
51
+ | File | Status | Changes |
52
+ |------|--------|---------|
53
+ | src/auth.ts | Modified | +42 -12 |
54
+ | src/db.ts | New | +85 |
55
+
56
+ ### Key Changes
57
+ - [1-3 bullet summary of what changed and why, from reading the diff]
58
+ ```
59
+
60
+ ## Options
61
+
62
+ | Flag | Effect |
63
+ |------|--------|
64
+ | (none) | Working tree changes (unstaged + staged) |
65
+ | `--staged` | Staged changes only |
66
+ | `--pr` | Diff against main (PR preview) |
67
+ | `ref1..ref2` | Compare any two refs |
68
+
69
+ ## Large Diffs
70
+
71
+ If diff exceeds 200 lines:
72
+ 1. Show `--stat` summary first
73
+ 2. Ask user if they want full diff or specific files
74
+ 3. Use `git diff -- <file>` for targeted output
@@ -0,0 +1,46 @@
1
+ # Pull Request Workflow
2
+
3
+ ## Steps
4
+
5
+ ### 1. Analyze Changes
6
+ ```bash
7
+ git log main..HEAD --oneline
8
+ git diff main..HEAD --stat
9
+ ```
10
+
11
+ ### 2. Push Branch
12
+ If not pushed:
13
+ ```bash
14
+ git push -u origin <branch>
15
+ ```
16
+
17
+ ### 3. Build PR
18
+
19
+ Title: short, under 70 chars
20
+ Body structure:
21
+
22
+ ```markdown
23
+ ## Summary
24
+ - [bullet points from commit messages]
25
+
26
+ ## Tickets
27
+ - [Ticket IDs if provided via --ticket or --jira]
28
+
29
+ ## Test Plan
30
+ - [ ] Unit tests pass
31
+ - [ ] Manual verification of [feature]
32
+ ```
33
+
34
+ ### 4. Create PR
35
+ ```bash
36
+ gh pr create --title "the title" --body "$(cat <<'EOF'
37
+ ## Summary
38
+ - bullet points
39
+
40
+ ## Test Plan
41
+ - [ ] tests pass
42
+ EOF
43
+ )"
44
+ ```
45
+
46
+ ### 5. Return PR URL