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 +30 -0
- package/package.json +1 -1
- package/templates/commands/bug.md +79 -3
- package/templates/commands/git.md +82 -6
- package/templates/commands/now.md +83 -7
- package/templates/commands/ship.md +265 -39
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,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
|
-
|
|
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
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
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
|
|
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
|
|
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
|
|
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:
|
|
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:
|
|
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
|
-
|
|
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
|
-
🚀
|
|
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
|
-
|
|
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
|
-
|
|
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" |
|
|
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:
|
|
402
|
+
### Example 1: Successful Ship with PR
|
|
201
403
|
```
|
|
202
|
-
/p:ship "
|
|
404
|
+
/p:ship "add user auth"
|
|
203
405
|
|
|
204
|
-
Pre-flight:
|
|
406
|
+
Pre-flight: Medium changes (87 lines in 5 files)
|
|
205
407
|
Quality: Lint ✅ | Tests ✅
|
|
206
|
-
Review:
|
|
408
|
+
Review: Passed
|
|
207
409
|
|
|
208
|
-
|
|
209
|
-
|
|
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
|
-
|
|
213
|
-
```
|
|
214
|
-
/p:ship "add auth"
|
|
415
|
+
🚀 PR Ready: add user auth
|
|
215
416
|
|
|
216
|
-
|
|
417
|
+
Version: 1.2.0 → 1.3.0
|
|
418
|
+
Changes: medium (87 lines in 5 files)
|
|
217
419
|
Quality: Lint ✅ | Tests ✅
|
|
218
|
-
|
|
420
|
+
CI: ✅ Passed
|
|
219
421
|
|
|
220
|
-
|
|
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
|
-
|
|
424
|
+
Next steps:
|
|
425
|
+
1. Request review from team
|
|
426
|
+
2. Merge when approved
|
|
228
427
|
```
|
|
229
428
|
|
|
230
|
-
### Example
|
|
429
|
+
### Example 2: Ship with CI Failure
|
|
231
430
|
```
|
|
232
|
-
/p:ship "
|
|
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:
|
|
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
|
-
|
|
239
|
-
|
|
240
|
-
- [95%] Hardcoded credentials detected
|
|
241
|
-
File: scripts/deploy.sh:12
|
|
466
|
+
🚀 PR Created: work in progress
|
|
467
|
+
CI: ⏳ Still running
|
|
242
468
|
|
|
243
|
-
|
|
469
|
+
📎 PR: https://github.com/user/repo/pull/44
|
|
244
470
|
```
|
|
245
471
|
|
|
246
472
|
## References
|