prjct-cli 0.22.0 → 0.23.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.
package/CHANGELOG.md CHANGED
@@ -1,5 +1,35 @@
1
1
  # Changelog
2
2
 
3
+ ## [0.23.0] - 2025-12-28
4
+
5
+ ### Feature: Branch + PR Workflow
6
+
7
+ Integrated git branch management and PR-based shipping workflow.
8
+
9
+ **Branch Management:**
10
+ - `/p:now` auto-creates feature branches when on main/master
11
+ - `/p:bug` auto-creates bug branches with proper naming
12
+ - Handles uncommitted changes (stash/commit/abort prompts)
13
+ - Tracks branch info in state.json
14
+
15
+ **Protected Branch Validation:**
16
+ - `/p:git` blocks commits/pushes to main/master
17
+ - Validates current branch matches expected task branch
18
+ - Clear error messages with recovery instructions
19
+
20
+ **PR-Based Shipping (`/p:ship`):**
21
+ - Creates PR via `gh` CLI instead of direct push
22
+ - Generates PR description with quality metrics
23
+ - Waits for CI checks (up to 10 min)
24
+ - Records CI status (passed/failed/timeout)
25
+ - Supports `--draft` flag for WIP PRs
26
+
27
+ **Template Updates:**
28
+ - `templates/commands/bug.md` - Branch creation + stashing
29
+ - `templates/commands/git.md` - Protected branch checks
30
+ - `templates/commands/now.md` - Feature branch workflow
31
+ - `templates/commands/ship.md` - Full PR lifecycle
32
+
3
33
  ## [0.20.1] - 2025-12-26
4
34
 
5
35
  ### Refactor: Type Consolidation
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "prjct-cli",
3
- "version": "0.22.0",
3
+ "version": "0.23.0",
4
4
  "description": "Built for Claude - Ship fast, track progress, stay focused. Developer momentum tool for indie hackers.",
5
5
  "main": "core/index.ts",
6
6
  "bin": {
@@ -1,5 +1,5 @@
1
1
  ---
2
- allowed-tools: [Read, Write, Bash, Task, Glob]
2
+ allowed-tools: [Read, Write, Bash, Task, Glob, AskUserQuestion]
3
3
  description: 'Report bug with auto-priority and auto-start'
4
4
  architecture: 'Write-Through (JSON → MD → Events)'
5
5
  storage-layer: true
@@ -129,6 +129,73 @@ GENERATE: {sessionId} = UUID v4
129
129
  bun -e "console.log(crypto.randomUUID())" 2>/dev/null || node -e "console.log(require('crypto').randomUUID())"
130
130
  ```
131
131
 
132
+ ### Step 5.5: Create Bug Branch
133
+
134
+ #### Check Current Branch
135
+ BASH: `git branch --show-current`
136
+ SET: {currentBranch} = result
137
+
138
+ IF {currentBranch} == "main" OR {currentBranch} == "master":
139
+ OUTPUT: "Creating bug branch..."
140
+
141
+ #### Handle Uncommitted Changes
142
+ BASH: `git status --porcelain`
143
+ SET: {hasChanges} = (result not empty)
144
+
145
+ IF {hasChanges}:
146
+ IF {severity} == "critical" OR {severity} == "high":
147
+ # Auto-stash for urgent bugs
148
+ BASH: `git stash push -m "prjct: stashed for urgent bug fix"`
149
+ SET: {stashedChanges} = true
150
+ OUTPUT: "Stashed changes for urgent bug fix"
151
+ ELSE:
152
+ USE AskUserQuestion:
153
+ ```
154
+ question: "Uncommitted changes detected. How to proceed?"
155
+ header: "Git Changes"
156
+ options:
157
+ - label: "Stash changes"
158
+ description: "Temporarily save changes, create branch, then continue"
159
+ - label: "Commit first"
160
+ description: "Commit current changes before switching"
161
+ - label: "Abort"
162
+ description: "Cancel and queue bug for later"
163
+ ```
164
+
165
+ IF choice == "Stash changes":
166
+ BASH: `git stash push -m "prjct: stashed for {description}"`
167
+ SET: {stashedChanges} = true
168
+ ELSE IF choice == "Commit first":
169
+ OUTPUT: "Commit your changes first, then run /p:bug again"
170
+ STOP
171
+ ELSE:
172
+ SET: {laterFlag} = true
173
+ SET: {autoStarted} = false
174
+ → Skip to Step 6
175
+
176
+ #### Create Bug Branch
177
+ SET: {bugSlug} = slugify({description})
178
+ LIMIT: {bugSlug} to 50 characters, lowercase, replace spaces with hyphens
179
+ SET: {branchName} = "bug/{bugSlug}"
180
+
181
+ BASH: `git checkout -b {branchName}`
182
+ IF command fails (branch exists):
183
+ BASH: `git checkout {branchName}`
184
+ IF still fails:
185
+ OUTPUT: "Failed to create/checkout branch: {branchName}"
186
+ SET: {laterFlag} = true
187
+ SET: {autoStarted} = false
188
+ → Skip to Step 6
189
+
190
+ SET: {branchCreated} = true
191
+ SET: {baseBranch} = {currentBranch}
192
+ OUTPUT: "✅ Created branch: {branchName}"
193
+
194
+ ELSE:
195
+ SET: {branchName} = {currentBranch}
196
+ SET: {branchCreated} = false
197
+ SET: {baseBranch} = null
198
+
132
199
  ### Update state.json
133
200
  ```json
134
201
  {
@@ -139,7 +206,13 @@ bun -e "console.log(crypto.randomUUID())" 2>/dev/null || node -e "console.log(re
139
206
  "startedAt": "{now}",
140
207
  "sessionId": "{sessionId}",
141
208
  "type": "bug",
142
- "priority": "{severity}"
209
+ "priority": "{severity}",
210
+ "branch": {
211
+ "name": "{branchName}",
212
+ "createdByPrjct": {branchCreated},
213
+ "baseBranch": "{baseBranch}",
214
+ "createdAt": "{now}"
215
+ }
143
216
  },
144
217
  "previousTask": {existing previousTask if any},
145
218
  "lastUpdated": "{now}"
@@ -156,6 +229,7 @@ WRITE: `{statePath}`
156
229
  Priority: {severity}
157
230
  Started: {now}
158
231
  Session: {sessionId}
232
+ Branch: {branchName}
159
233
  ```
160
234
  WRITE: `{nowContextPath}`
161
235
 
@@ -221,7 +295,7 @@ ELSE:
221
295
  ```
222
296
  🐛 [{severity}] {description}
223
297
 
224
- Started working on fix
298
+ Branch: {branchName}
225
299
  Session: {sessionId}
226
300
 
227
301
  /p:done when fixed
@@ -312,4 +386,6 @@ Start later: /p:now "🐛 payment not processing"
312
386
  | Error | Response | Action |
313
387
  |-------|----------|--------|
314
388
  | No project | "No prjct project" | STOP |
389
+ | On protected branch with changes | Ask/auto-stash for urgent | WAIT |
390
+ | Branch creation fails | Queue bug for later | CONTINUE |
315
391
  | Write fails | Log warning | CONTINUE |
@@ -31,16 +31,64 @@ Reads from **Storage (JSON)** as source of truth.
31
31
 
32
32
  ## Flow: commit
33
33
 
34
- 1. Read: `storage/state.json` → get task context
35
- 2. Git: `add .` stage changes
36
- 3. Create: commit message with prjct metadata
37
- 4. Commit: with message
38
- 5. Log: `memory/events.jsonl`
34
+ ### Step 1: Validate Branch
35
+ READ: `.prjct/prjct.config.json` → extract `projectId`
36
+ SET: `{globalPath}` = `~/.prjct-cli/projects/{projectId}`
37
+
38
+ READ: `{globalPath}/storage/state.json`
39
+ IF currentTask AND currentTask.branch:
40
+ SET: {expectedBranch} = currentTask.branch.name
41
+ ELSE:
42
+ SET: {expectedBranch} = null
43
+
44
+ BASH: `git branch --show-current`
45
+ SET: {currentBranch} = result
46
+
47
+ IF {currentBranch} == "main" OR {currentBranch} == "master":
48
+ OUTPUT:
49
+ ```
50
+ ⚠️ Cannot commit on protected branch: {currentBranch}
51
+
52
+ Start a task first with /p:now "task name" to create a feature branch.
53
+ ```
54
+ STOP
55
+
56
+ IF {expectedBranch} AND {currentBranch} != {expectedBranch}:
57
+ OUTPUT:
58
+ ```
59
+ ⚠️ Branch mismatch
60
+
61
+ Current: {currentBranch}
62
+ Expected: {expectedBranch}
63
+
64
+ Switch to the correct branch: git checkout {expectedBranch}
65
+ ```
66
+ STOP
67
+
68
+ ### Step 2: Stage and Commit
69
+ 1. Git: `add .` → stage changes
70
+ 2. Create: commit message with prjct metadata
71
+ 3. Commit: with message
72
+ 4. Log: `memory/events.jsonl`
39
73
 
40
74
  ## Flow: push
41
75
 
76
+ ### Step 1: Check Protected Branch
77
+ BASH: `git branch --show-current`
78
+ SET: {currentBranch} = result
79
+
80
+ IF {currentBranch} == "main" OR {currentBranch} == "master":
81
+ OUTPUT:
82
+ ```
83
+ ⚠️ Cannot push directly to protected branch: {currentBranch}
84
+
85
+ Use /p:ship to create a Pull Request instead.
86
+ ```
87
+ STOP
88
+
89
+ ### Step 2: Push
42
90
  1. Git: `status` → verify clean
43
- 2. Git: `push` with branch tracking
91
+ 2. Git: `push -u origin {currentBranch}` with branch tracking
44
92
  3. Handle: errors (upstream, conflicts)
45
93
 
46
94
  ## Flow: sync
@@ -63,10 +111,38 @@ Co-Authored-By: @{github_dev}
63
111
 
64
112
  ## Response
65
113
 
114
+ ### Success
66
115
  ```
67
116
  ✅ Git {operation}
68
117
 
118
+ Branch: {currentBranch}
69
119
  {operation_details}
70
120
 
71
121
  /p:ship | /p:status
72
122
  ```
123
+
124
+ ### Protected Branch Block
125
+ ```
126
+ ⚠️ Cannot {operation} on protected branch: {currentBranch}
127
+
128
+ Use /p:ship to create a Pull Request instead.
129
+ ```
130
+
131
+ ### Branch Mismatch
132
+ ```
133
+ ⚠️ Branch mismatch
134
+
135
+ Current: {currentBranch}
136
+ Expected: {expectedBranch}
137
+
138
+ Switch to the correct branch: git checkout {expectedBranch}
139
+ ```
140
+
141
+ ## Error Handling
142
+
143
+ | Error | Response | Action |
144
+ |-------|----------|--------|
145
+ | On protected branch | "Cannot {op} on protected branch" | STOP |
146
+ | Branch mismatch | Show expected vs current | STOP |
147
+ | Push fails | "Push failed. Try: git pull --rebase" | STOP |
148
+ | Conflicts | Show conflicted files | STOP |
@@ -1,5 +1,5 @@
1
1
  ---
2
- allowed-tools: [Read, Write, Bash]
2
+ allowed-tools: [Read, Write, Bash, AskUserQuestion]
3
3
  description: 'Set or show current task with session tracking'
4
4
  ---
5
5
 
@@ -61,6 +61,72 @@ IF currentTask.description == task:
61
61
  OUTPUT: "🎯 Continuing: {task}"
62
62
  STOP
63
63
 
64
+ ### Step 2.5: Git Branch Management
65
+
66
+ #### 2.5.1 Check Current Branch
67
+ BASH: `git branch --show-current`
68
+ SET: {currentBranch} = result
69
+
70
+ #### 2.5.2 Block Protected Branches
71
+ IF {currentBranch} == "main" OR {currentBranch} == "master":
72
+ OUTPUT:
73
+ ```
74
+ ⚠️ Cannot work on protected branch: {currentBranch}
75
+
76
+ Creating feature branch for your task...
77
+ ```
78
+
79
+ #### 2.5.3 Handle Uncommitted Changes
80
+ BASH: `git status --porcelain`
81
+ SET: {hasChanges} = (result not empty)
82
+
83
+ IF {hasChanges}:
84
+ USE AskUserQuestion:
85
+ ```
86
+ question: "Uncommitted changes detected. How to proceed?"
87
+ header: "Git Changes"
88
+ options:
89
+ - label: "Stash changes"
90
+ description: "Temporarily save changes, create branch, then continue"
91
+ - label: "Commit first"
92
+ description: "Commit current changes before switching"
93
+ - label: "Abort"
94
+ description: "Cancel and keep working on current branch"
95
+ ```
96
+
97
+ IF choice == "Stash changes":
98
+ BASH: `git stash push -m "prjct: stashed for {task}"`
99
+ SET: {stashedChanges} = true
100
+ ELSE IF choice == "Commit first":
101
+ OUTPUT: "Commit your changes first, then run /p:now again"
102
+ STOP
103
+ ELSE:
104
+ OUTPUT: "Aborted. Staying on {currentBranch}"
105
+ STOP
106
+
107
+ #### 2.5.4 Create Feature Branch
108
+ SET: {taskSlug} = slugify({task})
109
+ LIMIT: {taskSlug} to 50 characters, lowercase, replace spaces with hyphens
110
+
111
+ SET: {taskType} = "feature" (or "bug" if task contains bug keywords)
112
+ SET: {branchName} = "{taskType}/{taskSlug}"
113
+
114
+ BASH: `git checkout -b {branchName}`
115
+ IF command fails (branch exists):
116
+ BASH: `git checkout {branchName}`
117
+ IF still fails:
118
+ OUTPUT: "Failed to create/checkout branch: {branchName}"
119
+ STOP
120
+
121
+ SET: {branchCreated} = true
122
+ SET: {baseBranch} = {currentBranch}
123
+ OUTPUT: "✅ Created branch: {branchName}"
124
+
125
+ ELSE:
126
+ SET: {branchName} = {currentBranch}
127
+ SET: {branchCreated} = false
128
+ SET: {baseBranch} = null
129
+
64
130
  ### Step 3: Create New Task
65
131
  GET timestamp: `bun -e "console.log(new Date().toISOString())" 2>/dev/null || node -e "console.log(new Date().toISOString())"`
66
132
  GET uuid: `bun -e "console.log(crypto.randomUUID())" 2>/dev/null || node -e "console.log(require('crypto').randomUUID())"`
@@ -83,7 +149,13 @@ WRITE to `{globalPath}/storage/state.json`:
83
149
  "startedAt": "{startedAt}",
84
150
  "sessionId": "{sessionId}",
85
151
  "estimate": "{estimate}",
86
- "estimateSeconds": {estimateSeconds}
152
+ "estimateSeconds": {estimateSeconds},
153
+ "branch": {
154
+ "name": "{branchName}",
155
+ "createdByPrjct": {branchCreated},
156
+ "baseBranch": "{baseBranch}",
157
+ "createdAt": "{startedAt}"
158
+ }
87
159
  },
88
160
  "lastUpdated": "{startedAt}"
89
161
  }
@@ -98,6 +170,7 @@ WRITE: `{globalPath}/context/now.md`:
98
170
 
99
171
  Started: {startedAt}
100
172
  Session: {sessionId}
173
+ Branch: {branchName}
101
174
  ```
102
175
 
103
176
  ### Step 6: Log Events
@@ -106,23 +179,24 @@ APPEND to `{globalPath}/memory/events.jsonl`
106
179
 
107
180
  ### Step 7: Output
108
181
 
109
- WITH estimate:
182
+ WITH branch created:
110
183
  ```
111
184
  🎯 {task}
112
185
 
186
+ Branch: {branchName}
113
187
  Session: {sessionId}
114
- Estimate: {estimate}
188
+ {IF estimate: Estimate: {estimate}}
115
189
 
116
190
  /p:done when finished | /p:pause to take a break
117
191
  ```
118
192
 
119
- WITHOUT estimate:
193
+ WITHOUT branch created (already on feature branch):
120
194
  ```
121
195
  🎯 {task}
122
196
 
197
+ Branch: {branchName} (existing)
123
198
  Session: {sessionId}
124
-
125
- 💡 Tip: Add estimate next time with /p:now "task" 2h
199
+ {IF estimate: Estimate: {estimate}}
126
200
 
127
201
  /p:done when finished | /p:pause to take a break
128
202
  ```
@@ -133,6 +207,8 @@ Session: {sessionId}
133
207
  |-------|----------|--------|
134
208
  | No project | "No prjct project" | STOP |
135
209
  | Active task exists | Show options | STOP |
210
+ | On protected branch with changes | Ask: stash/commit/abort | WAIT |
211
+ | Branch creation fails | "Failed to create branch" | STOP |
136
212
  | Write fails | "Failed to create session" | STOP |
137
213
 
138
214
  ## References
@@ -1,19 +1,20 @@
1
1
  ---
2
- allowed-tools: [Read, Write, Bash, Glob, Grep]
3
- description: 'Ship feature with automated workflow'
2
+ allowed-tools: [Read, Write, Bash, Glob, Grep, AskUserQuestion]
3
+ description: 'Ship feature with automated PR workflow'
4
4
  ---
5
5
 
6
6
  # /p:ship - Ship Feature
7
7
 
8
- Ship completed work with pre-flight checks, code review, and quality gates.
8
+ Ship completed work with pre-flight checks, code review, PR creation, and CI verification.
9
9
 
10
10
  ## Usage
11
11
  ```
12
- /p:ship [feature] [--blocking] [--skip-review]
12
+ /p:ship [feature] [--blocking] [--skip-review] [--draft]
13
13
  ```
14
14
  - `feature`: Name of the feature being shipped (required)
15
15
  - `--blocking`: Abort if any check fails
16
16
  - `--skip-review`: Skip code review (for trivial changes)
17
+ - `--draft`: Create PR as draft
17
18
 
18
19
  ## Flow
19
20
 
@@ -135,14 +136,171 @@ UPDATE version file with new version
135
136
  BASH: `git log --oneline -20 --pretty=format:"- %s"`
136
137
  INSERT new entry in CHANGELOG.md
137
138
 
138
- ### Step 7: Git Commit & Push
139
+ ### Step 7: Create Pull Request
140
+
141
+ #### 7.1 Check gh CLI
142
+ BASH: `which gh 2>/dev/null`
143
+ IF result empty:
144
+ OUTPUT:
145
+ ```
146
+ ⚠️ GitHub CLI (gh) not installed
147
+
148
+ Install: https://cli.github.com/
149
+ Or: brew install gh
150
+
151
+ After installing, run: gh auth login
152
+ ```
153
+ STOP
154
+
155
+ #### 7.2 Check Authentication
156
+ BASH: `gh auth status 2>&1`
157
+ IF not authenticated:
158
+ OUTPUT: "Run `gh auth login` to authenticate with GitHub"
159
+ STOP
160
+
161
+ #### 7.3 Get Branch Info
162
+ READ: `{globalPath}/storage/state.json`
163
+ IF currentTask AND currentTask.branch:
164
+ SET: {branchName} = currentTask.branch.name
165
+ SET: {baseBranch} = currentTask.branch.baseBranch OR "main"
166
+ ELSE:
167
+ BASH: `git branch --show-current`
168
+ SET: {branchName} = result
169
+ SET: {baseBranch} = "main"
170
+
171
+ IF {branchName} == "main" OR {branchName} == "master":
172
+ OUTPUT:
173
+ ```
174
+ ⚠️ Cannot ship from protected branch: {branchName}
175
+
176
+ Create a feature branch first with /p:now "task name"
177
+ ```
178
+ STOP
179
+
180
+ #### 7.4 Commit Changes
139
181
  BASH: `git add .`
140
- BASH: `git commit -m "feat: Ship {feature} v{newVersion}
182
+ BASH: `git commit -m "feat: {feature}
183
+
184
+ {code review summary if any issues were found}
141
185
 
142
186
  🤖 Generated with [p/](https://www.prjct.app/)
143
187
  Designed for [Claude](https://www.anthropic.com/claude)
144
188
  "`
145
- BASH: `git push`
189
+
190
+ #### 7.5 Push Branch
191
+ BASH: `git push -u origin {branchName}`
192
+ IF push fails:
193
+ OUTPUT: "Push failed. Check your git credentials or try: git pull --rebase"
194
+ STOP
195
+
196
+ #### 7.6 Create Pull Request
197
+ SET: {prTitle} = "feat: {feature}"
198
+ SET: {prBody} = """
199
+ ## Summary
200
+ {feature description}
201
+
202
+ ## Changes
203
+ - {totalLines} lines changed in {filesChanged} files
204
+ - Type: {changeType}
205
+
206
+ ## Quality Checks
207
+ - Lint: {lintStatus}
208
+ - Tests: {testStatus}
209
+ - Review: {reviewStatus}
210
+
211
+ {IF issues found:}
212
+ ### Review Notes
213
+ {list of issues found during code review}
214
+ {END IF}
215
+
216
+ ---
217
+ 🤖 Generated with [p/](https://www.prjct.app/)
218
+ Designed for [Claude](https://www.anthropic.com/claude)
219
+ """
220
+
221
+ IF `--draft`:
222
+ SET: {draftFlag} = "--draft"
223
+ ELSE:
224
+ SET: {draftFlag} = ""
225
+
226
+ BASH: `gh pr create --title "{prTitle}" --base {baseBranch} {draftFlag} --body "$(cat <<'EOF'
227
+ {prBody}
228
+ EOF
229
+ )"`
230
+
231
+ IF command fails:
232
+ # PR might already exist
233
+ BASH: `gh pr view --json url,number`
234
+ IF exists:
235
+ EXTRACT: {prUrl}, {prNumber}
236
+ OUTPUT: "PR already exists: {prUrl}"
237
+ ELSE:
238
+ OUTPUT: "Failed to create PR. Check gh auth status."
239
+ STOP
240
+ ELSE:
241
+ EXTRACT: {prUrl} from output
242
+ EXTRACT: {prNumber} from output
243
+
244
+ OUTPUT: "📎 PR created: {prUrl}"
245
+
246
+ #### 7.7 Wait for CI Checks
247
+ OUTPUT: "Waiting for CI checks..."
248
+
249
+ SET: {maxWaitTime} = 600 # 10 minutes
250
+ SET: {checkInterval} = 30 # 30 seconds
251
+ SET: {elapsed} = 0
252
+
253
+ LOOP:
254
+ BASH: `gh pr checks {prNumber} --json name,state,conclusion 2>/dev/null || echo "[]"`
255
+ PARSE: {ciChecks}
256
+
257
+ IF {ciChecks} is empty OR all checks have conclusion:
258
+ # All checks completed
259
+ SET: {failedChecks} = checks where conclusion != "success" AND conclusion != "skipped"
260
+
261
+ IF {failedChecks}.length > 0:
262
+ SET: {ciStatus} = "failed"
263
+ OUTPUT:
264
+ ```
265
+ ❌ CI checks failed:
266
+ {FOR each failed check:}
267
+ - {name}: {conclusion}
268
+ {END FOR}
269
+
270
+ Fix issues and push again. PR: {prUrl}
271
+ ```
272
+ → Continue to Step 8 (don't stop, just record the failure)
273
+ ELSE:
274
+ SET: {ciStatus} = "passed"
275
+ OUTPUT: "✅ All CI checks passed"
276
+ BREAK
277
+
278
+ SET: {pendingCount} = checks where state == "pending" OR state == "queued"
279
+ OUTPUT: "⏳ Waiting for {pendingCount} CI checks..."
280
+
281
+ WAIT: {checkInterval} seconds
282
+ SET: {elapsed} = {elapsed} + {checkInterval}
283
+
284
+ IF {elapsed} >= {maxWaitTime}:
285
+ SET: {ciStatus} = "timeout"
286
+ OUTPUT: "⏰ CI still running after 10 minutes. Check PR: {prUrl}"
287
+ BREAK
288
+
289
+ #### 7.8 Update State with PR Info
290
+ READ: `{globalPath}/storage/state.json`
291
+ IF currentTask:
292
+ UPDATE currentTask.branch:
293
+ ```json
294
+ {
295
+ "branch": {
296
+ ...existing,
297
+ "prUrl": "{prUrl}",
298
+ "prNumber": {prNumber},
299
+ "ciStatus": "{ciStatus}"
300
+ }
301
+ }
302
+ ```
303
+ WRITE: `{globalPath}/storage/state.json`
146
304
 
147
305
  ### Step 8: Update Storage
148
306
  GET timestamp: `bun -e "console.log(new Date().toISOString())" 2>/dev/null || node -e "console.log(new Date().toISOString())"`
@@ -157,7 +315,11 @@ PREPEND new ship object:
157
315
  "version": "{newVersion}",
158
316
  "shippedAt": "{timestamp}",
159
317
  "lint": "{lintStatus}",
160
- "tests": "{testStatus}"
318
+ "tests": "{testStatus}",
319
+ "branch": "{branchName}",
320
+ "prUrl": "{prUrl}",
321
+ "prNumber": {prNumber},
322
+ "ciStatus": "{ciStatus}"
161
323
  }
162
324
  ```
163
325
  WRITE: `{globalPath}/storage/shipped.json`
@@ -172,15 +334,49 @@ Log to memory:
172
334
  APPEND to `{globalPath}/memory/events.jsonl`
173
335
 
174
336
  ### Step 9: Output
337
+
338
+ IF {ciStatus} == "passed":
175
339
  ```
176
- 🚀 Shipped: {feature}
340
+ 🚀 PR Ready: {feature}
177
341
 
178
342
  Version: {oldVersion} → {newVersion}
179
343
  Changes: {changeType} ({totalLines} lines in {filesChanged} files)
180
344
  Quality: Lint {lintStatus} | Tests {testStatus}
181
- Review: {reviewStatus}
345
+ CI: ✅ Passed
346
+
347
+ 📎 PR: {prUrl}
348
+
349
+ Next steps:
350
+ 1. Request review from team
351
+ 2. Merge when approved
352
+
353
+ /p:done to close task | /p:next for more work
354
+ ```
182
355
 
183
- Next: /p:feature | /p:recap
356
+ IF {ciStatus} == "failed":
357
+ ```
358
+ ⚠️ PR Created (CI Failed): {feature}
359
+
360
+ Version: {oldVersion} → {newVersion}
361
+ Quality: Lint {lintStatus} | Tests {testStatus}
362
+ CI: ❌ Failed
363
+
364
+ 📎 PR: {prUrl}
365
+
366
+ Fix CI issues and push again.
367
+ ```
368
+
369
+ IF {ciStatus} == "timeout":
370
+ ```
371
+ 🚀 PR Created: {feature}
372
+
373
+ Version: {oldVersion} → {newVersion}
374
+ Quality: Lint {lintStatus} | Tests {testStatus}
375
+ CI: ⏳ Still running
376
+
377
+ 📎 PR: {prUrl}
378
+
379
+ Check CI status on GitHub.
184
380
  ```
185
381
 
186
382
  ## Error Handling
@@ -189,58 +385,88 @@ Next: /p:feature | /p:recap
189
385
  |-------|----------|--------|
190
386
  | No git repo | "Not a git repository" | STOP |
191
387
  | No changes | "No changes to ship" | STOP |
388
+ | On protected branch | "Cannot ship from main/master" | STOP |
389
+ | gh CLI not installed | Show install instructions | STOP |
390
+ | gh not authenticated | "Run gh auth login" | STOP |
192
391
  | Lint/test fails (blocking) | "Quality checks failed" | STOP |
193
392
  | Lint/test fails (non-blocking) | Show warning | CONTINUE |
194
393
  | Code review finds issues (blocking) | "Fix issues before shipping" | STOP |
195
394
  | Code review finds issues (non-blocking) | Prompt to continue | ASK |
196
- | Push fails | "Push failed. Try: git pull --rebase" | CONTINUE |
395
+ | Push fails | "Push failed. Try: git pull --rebase" | STOP |
396
+ | PR creation fails | Check if PR exists | CONTINUE |
397
+ | CI fails | Show failed checks, record in storage | CONTINUE |
398
+ | CI timeout | Show PR URL, continue | CONTINUE |
197
399
 
198
400
  ## Examples
199
401
 
200
- ### Example 1: Trivial Change (auto-skip review)
402
+ ### Example 1: Successful Ship with PR
201
403
  ```
202
- /p:ship "fix typo"
404
+ /p:ship "add user auth"
203
405
 
204
- Pre-flight: Trivial changes (3 lines in 1 file)
406
+ Pre-flight: Medium changes (87 lines in 5 files)
205
407
  Quality: Lint ✅ | Tests ✅
206
- Review: Skipped (trivial)
408
+ Review: Passed
207
409
 
208
- 🚀 Shipped: fix typo
209
- Version: 1.2.0 1.2.1
210
- ```
410
+ 📎 PR created: https://github.com/user/repo/pull/42
411
+ Waiting for CI checks...
412
+ ⏳ Waiting for 3 CI checks...
413
+ ✅ All CI checks passed
211
414
 
212
- ### Example 2: Medium Change (with review)
213
- ```
214
- /p:ship "add auth"
415
+ 🚀 PR Ready: add user auth
215
416
 
216
- Pre-flight: Medium changes (87 lines in 5 files)
417
+ Version: 1.2.0 1.3.0
418
+ Changes: medium (87 lines in 5 files)
217
419
  Quality: Lint ✅ | Tests ✅
218
- Review: Running...
420
+ CI: ✅ Passed
219
421
 
220
- ## Code Review Results
221
- Found 2 issues (confidence >= 70%):
222
- - [85%] Missing error handling in OAuth callback
223
- File: src/auth/oauth.ts:67
224
- - [72%] Token not validated before use
225
- File: src/auth/validate.ts:23
422
+ 📎 PR: https://github.com/user/repo/pull/42
226
423
 
227
- Continue with ship? (y/n)
424
+ Next steps:
425
+ 1. Request review from team
426
+ 2. Merge when approved
228
427
  ```
229
428
 
230
- ### Example 3: Blocking Mode
429
+ ### Example 2: Ship with CI Failure
231
430
  ```
232
- /p:ship "deploy script" --blocking
431
+ /p:ship "fix login bug"
233
432
 
234
433
  Pre-flight: Small changes (28 lines in 2 files)
235
434
  Quality: Lint ✅ | Tests ✅
236
- Review: Running...
435
+ Review: Passed
436
+
437
+ 📎 PR created: https://github.com/user/repo/pull/43
438
+ Waiting for CI checks...
439
+
440
+ ❌ CI checks failed:
441
+ - build: failure
442
+ - test: failure
443
+
444
+ ⚠️ PR Created (CI Failed): fix login bug
445
+
446
+ 📎 PR: https://github.com/user/repo/pull/43
447
+
448
+ Fix CI issues and push again.
449
+ ```
450
+
451
+ ### Example 3: Blocked on Protected Branch
452
+ ```
453
+ /p:ship "new feature"
454
+
455
+ ⚠️ Cannot ship from protected branch: main
456
+
457
+ Create a feature branch first with /p:now "task name"
458
+ ```
459
+
460
+ ### Example 4: Draft PR
461
+ ```
462
+ /p:ship "work in progress" --draft
463
+
464
+ 📎 PR created (draft): https://github.com/user/repo/pull/44
237
465
 
238
- ## Code Review Results
239
- Found 1 issue (confidence >= 70%):
240
- - [95%] Hardcoded credentials detected
241
- File: scripts/deploy.sh:12
466
+ 🚀 PR Created: work in progress
467
+ CI: Still running
242
468
 
243
- Fix issues before shipping.
469
+ 📎 PR: https://github.com/user/repo/pull/44
244
470
  ```
245
471
 
246
472
  ## References