prjct-cli 0.12.2 → 0.13.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 +43 -0
- package/CLAUDE.md +18 -6
- package/core/data/index.ts +19 -5
- package/core/data/md-base-manager.ts +203 -0
- package/core/data/md-queue-manager.ts +179 -0
- package/core/data/md-state-manager.ts +133 -0
- package/core/serializers/index.ts +20 -0
- package/core/serializers/queue-serializer.ts +210 -0
- package/core/serializers/state-serializer.ts +136 -0
- package/core/utils/file-helper.ts +12 -0
- package/package.json +1 -1
- package/packages/web/app/api/projects/[id]/stats/route.ts +6 -29
- package/packages/web/app/page.tsx +1 -6
- package/packages/web/app/project/[id]/page.tsx +34 -1
- package/packages/web/app/project/[id]/stats/page.tsx +11 -5
- package/packages/web/app/settings/page.tsx +2 -221
- package/packages/web/components/BlockersCard/BlockersCard.tsx +67 -0
- package/packages/web/components/BlockersCard/BlockersCard.types.ts +11 -0
- package/packages/web/components/BlockersCard/index.ts +2 -0
- package/packages/web/components/CommandButton/CommandButton.tsx +10 -3
- package/packages/web/lib/projects.ts +28 -27
- package/packages/web/lib/services/projects.server.ts +25 -21
- package/packages/web/lib/services/stats.server.ts +355 -57
- package/packages/web/package.json +0 -2
- package/templates/commands/decision.md +226 -0
- package/templates/commands/done.md +100 -68
- package/templates/commands/feature.md +102 -103
- package/templates/commands/idea.md +41 -38
- package/templates/commands/now.md +94 -33
- package/templates/commands/pause.md +90 -30
- package/templates/commands/ship.md +179 -74
- package/templates/commands/sync.md +324 -200
- package/packages/web/app/api/migrate/route.ts +0 -46
- package/packages/web/app/api/settings/route.ts +0 -97
- package/packages/web/app/api/v2/projects/[id]/unified/route.ts +0 -57
- package/packages/web/components/MigrationGate/MigrationGate.tsx +0 -304
- package/packages/web/components/MigrationGate/index.ts +0 -1
- package/packages/web/lib/json-loader.ts +0 -630
- package/packages/web/lib/services/migration.server.ts +0 -580
|
@@ -2,26 +2,38 @@
|
|
|
2
2
|
allowed-tools: [Read, Write, Bash]
|
|
3
3
|
description: 'Set or show current task with session tracking'
|
|
4
4
|
timestamp-rule: 'GetTimestamp() for ALL timestamps'
|
|
5
|
-
architecture: '
|
|
5
|
+
architecture: 'MD-first - MD files are source of truth'
|
|
6
6
|
---
|
|
7
7
|
|
|
8
8
|
# /p:now - Current Task with Session Tracking
|
|
9
9
|
|
|
10
|
-
## Architecture:
|
|
10
|
+
## Architecture: MD-First
|
|
11
11
|
|
|
12
|
-
**Source of Truth**: `
|
|
13
|
-
**Generated View**: `views/now.md` (auto-generated, do not edit directly)
|
|
12
|
+
**Source of Truth**: `core/now.md`
|
|
14
13
|
|
|
15
|
-
|
|
14
|
+
MD files are the source of truth. Write directly to MD files.
|
|
16
15
|
|
|
17
16
|
## Context Variables
|
|
18
17
|
- `{projectId}`: From `.prjct/prjct.config.json`
|
|
19
18
|
- `{globalPath}`: `~/.prjct-cli/projects/{projectId}`
|
|
20
|
-
- `{
|
|
21
|
-
- `{statePath}`: `{dataPath}/state.json`
|
|
19
|
+
- `{nowPath}`: `{globalPath}/core/now.md`
|
|
22
20
|
- `{sessionPath}`: `{globalPath}/sessions/current.json`
|
|
23
21
|
- `{memoryPath}`: `{globalPath}/memory/context.jsonl`
|
|
24
22
|
- `{task}`: User-provided task (optional)
|
|
23
|
+
- `{estimate}`: User-provided time estimate (optional, e.g., "2h", "30m", "1d")
|
|
24
|
+
|
|
25
|
+
## Estimate Format
|
|
26
|
+
|
|
27
|
+
Estimates use simple duration format:
|
|
28
|
+
- `30m` - 30 minutes
|
|
29
|
+
- `2h` - 2 hours
|
|
30
|
+
- `1d` - 1 day (8 hours)
|
|
31
|
+
- `2h30m` - 2 hours 30 minutes
|
|
32
|
+
|
|
33
|
+
If no estimate provided, gently remind:
|
|
34
|
+
```
|
|
35
|
+
💡 Tip: Add estimate next time with /p:now "task" 2h
|
|
36
|
+
```
|
|
25
37
|
|
|
26
38
|
## Step 1: Read Config
|
|
27
39
|
|
|
@@ -34,14 +46,17 @@ IF file not found:
|
|
|
34
46
|
|
|
35
47
|
## Step 2: Check Current State
|
|
36
48
|
|
|
37
|
-
### Read
|
|
38
|
-
READ: `{
|
|
49
|
+
### Read now.md (source of truth)
|
|
50
|
+
READ: `{nowPath}`
|
|
39
51
|
|
|
40
|
-
IF file exists:
|
|
41
|
-
PARSE
|
|
42
|
-
|
|
52
|
+
IF file exists AND has content:
|
|
53
|
+
PARSE MD format:
|
|
54
|
+
- Look for `**Task description**` (bold text = current task)
|
|
55
|
+
- Look for `Started: {timestamp}`
|
|
56
|
+
- Look for `Session: {sessionId}`
|
|
57
|
+
EXTRACT: {currentTask}, {startedAt}, {sessionId}
|
|
43
58
|
|
|
44
|
-
### Check for active session (
|
|
59
|
+
### Check for active session (for detailed tracking)
|
|
45
60
|
READ: `{sessionPath}`
|
|
46
61
|
|
|
47
62
|
IF file exists:
|
|
@@ -104,23 +119,30 @@ IF {task} is provided:
|
|
|
104
119
|
GENERATE: {sessionId} = "sess_" + 8 random alphanumeric chars
|
|
105
120
|
SET: {startedAt} = GetTimestamp()
|
|
106
121
|
|
|
107
|
-
### Write
|
|
108
|
-
READ: `{statePath}` (or create default if not exists)
|
|
122
|
+
### Write now.md (SOURCE OF TRUTH)
|
|
109
123
|
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
{
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
}
|
|
124
|
+
WRITE: `{nowPath}`
|
|
125
|
+
|
|
126
|
+
IF {estimate} provided:
|
|
127
|
+
```markdown
|
|
128
|
+
# NOW
|
|
129
|
+
|
|
130
|
+
**{task}**
|
|
131
|
+
|
|
132
|
+
Started: {startedAt}
|
|
133
|
+
Session: {sessionId}
|
|
134
|
+
Estimate: {estimate}
|
|
121
135
|
```
|
|
122
136
|
|
|
123
|
-
|
|
137
|
+
ELSE (no estimate):
|
|
138
|
+
```markdown
|
|
139
|
+
# NOW
|
|
140
|
+
|
|
141
|
+
**{task}**
|
|
142
|
+
|
|
143
|
+
Started: {startedAt}
|
|
144
|
+
Session: {sessionId}
|
|
145
|
+
```
|
|
124
146
|
|
|
125
147
|
### Create session JSON (for detailed tracking)
|
|
126
148
|
WRITE: `{sessionPath}`
|
|
@@ -135,6 +157,8 @@ IF {task} is provided:
|
|
|
135
157
|
"pausedAt": null,
|
|
136
158
|
"completedAt": null,
|
|
137
159
|
"duration": 0,
|
|
160
|
+
"estimate": "{estimate OR null}",
|
|
161
|
+
"estimateSeconds": {estimateInSeconds OR null},
|
|
138
162
|
"metrics": {
|
|
139
163
|
"filesChanged": 0,
|
|
140
164
|
"linesAdded": 0,
|
|
@@ -148,26 +172,48 @@ IF {task} is provided:
|
|
|
148
172
|
}
|
|
149
173
|
```
|
|
150
174
|
|
|
151
|
-
###
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
175
|
+
### Convert estimate to seconds
|
|
176
|
+
IF {estimate} provided:
|
|
177
|
+
- "30m" → 1800 seconds
|
|
178
|
+
- "2h" → 7200 seconds
|
|
179
|
+
- "1d" → 28800 seconds (8 hours)
|
|
180
|
+
- "2h30m" → 9000 seconds
|
|
155
181
|
|
|
156
182
|
### Log to memory
|
|
157
183
|
APPEND to: `{memoryPath}`
|
|
158
184
|
Single line (JSONL):
|
|
185
|
+
|
|
186
|
+
IF {estimate} provided:
|
|
187
|
+
```json
|
|
188
|
+
{"timestamp":"{startedAt}","action":"session_started","sessionId":"{sessionId}","task":"{task}","estimate":"{estimate}","estimateSeconds":{estimateInSeconds}}
|
|
189
|
+
```
|
|
190
|
+
|
|
191
|
+
ELSE:
|
|
159
192
|
```json
|
|
160
193
|
{"timestamp":"{startedAt}","action":"session_started","sessionId":"{sessionId}","task":"{task}"}
|
|
161
194
|
```
|
|
162
195
|
|
|
163
196
|
## Output
|
|
164
197
|
|
|
165
|
-
SUCCESS (new task):
|
|
198
|
+
SUCCESS (new task with estimate):
|
|
166
199
|
```
|
|
167
200
|
🎯 {task}
|
|
168
201
|
|
|
169
202
|
Session: {sessionId}
|
|
170
203
|
Started: now
|
|
204
|
+
Estimate: {estimate}
|
|
205
|
+
|
|
206
|
+
/p:done when finished | /p:pause to take a break
|
|
207
|
+
```
|
|
208
|
+
|
|
209
|
+
SUCCESS (new task without estimate):
|
|
210
|
+
```
|
|
211
|
+
🎯 {task}
|
|
212
|
+
|
|
213
|
+
Session: {sessionId}
|
|
214
|
+
Started: now
|
|
215
|
+
|
|
216
|
+
💡 Tip: Add estimate next time with /p:now "task" 2h
|
|
171
217
|
|
|
172
218
|
/p:done when finished | /p:pause to take a break
|
|
173
219
|
```
|
|
@@ -195,7 +241,7 @@ Status: active
|
|
|
195
241
|
/p:done to complete | /p:pause to pause
|
|
196
242
|
```
|
|
197
243
|
|
|
198
|
-
### Example 2: Start New Task
|
|
244
|
+
### Example 2: Start New Task (without estimate)
|
|
199
245
|
```
|
|
200
246
|
User: /p:now "Add login form"
|
|
201
247
|
Output:
|
|
@@ -204,6 +250,21 @@ Output:
|
|
|
204
250
|
Session: sess_xyz98765
|
|
205
251
|
Started: now
|
|
206
252
|
|
|
253
|
+
💡 Tip: Add estimate next time with /p:now "task" 2h
|
|
254
|
+
|
|
255
|
+
/p:done when finished | /p:pause to take a break
|
|
256
|
+
```
|
|
257
|
+
|
|
258
|
+
### Example 2b: Start New Task (with estimate)
|
|
259
|
+
```
|
|
260
|
+
User: /p:now "Add login form" 2h
|
|
261
|
+
Output:
|
|
262
|
+
🎯 Add login form
|
|
263
|
+
|
|
264
|
+
Session: sess_xyz98765
|
|
265
|
+
Started: now
|
|
266
|
+
Estimate: 2h
|
|
267
|
+
|
|
207
268
|
/p:done when finished | /p:pause to take a break
|
|
208
269
|
```
|
|
209
270
|
|
|
@@ -1,17 +1,43 @@
|
|
|
1
1
|
---
|
|
2
2
|
allowed-tools: [Read, Write, Bash]
|
|
3
|
-
description: 'Pause current session'
|
|
3
|
+
description: 'Pause current session with reason'
|
|
4
4
|
timestamp-rule: 'GetTimestamp() for all timestamps'
|
|
5
|
+
architecture: 'MD-first - MD files are source of truth'
|
|
5
6
|
---
|
|
6
7
|
|
|
7
8
|
# /p:pause - Pause Current Session
|
|
8
9
|
|
|
10
|
+
## Architecture: MD-First
|
|
11
|
+
|
|
12
|
+
**Source of Truth**: `core/now.md`, `sessions/current.json`
|
|
13
|
+
|
|
9
14
|
## Context Variables
|
|
10
15
|
- `{projectId}`: From `.prjct/prjct.config.json`
|
|
11
16
|
- `{globalPath}`: `~/.prjct-cli/projects/{projectId}`
|
|
12
17
|
- `{sessionPath}`: `{globalPath}/sessions/current.json`
|
|
13
18
|
- `{nowPath}`: `{globalPath}/core/now.md`
|
|
14
19
|
- `{memoryPath}`: `{globalPath}/memory/context.jsonl`
|
|
20
|
+
- `{reason}`: User-provided reason (optional)
|
|
21
|
+
|
|
22
|
+
## Pause Reasons
|
|
23
|
+
|
|
24
|
+
When pausing, capture WHY to enable blocker tracking:
|
|
25
|
+
|
|
26
|
+
| Reason | Meaning | Dashboard Impact |
|
|
27
|
+
|--------|---------|------------------|
|
|
28
|
+
| `blocked` | Waiting on external dependency | Shows in Blockers list |
|
|
29
|
+
| `switch` | Switching to higher priority task | Context switch metric |
|
|
30
|
+
| `break` | Taking a break | Normal pause |
|
|
31
|
+
| `research` | Need to investigate more | Research time tracked |
|
|
32
|
+
|
|
33
|
+
If no reason provided, ask:
|
|
34
|
+
```
|
|
35
|
+
Why are you pausing?
|
|
36
|
+
1. blocked - Waiting on something external
|
|
37
|
+
2. switch - Starting a different task
|
|
38
|
+
3. break - Taking a break
|
|
39
|
+
4. research - Need to investigate
|
|
40
|
+
```
|
|
15
41
|
|
|
16
42
|
## Step 1: Read Config
|
|
17
43
|
|
|
@@ -40,6 +66,7 @@ IF {session.status} == "paused":
|
|
|
40
66
|
|
|
41
67
|
Paused: {elapsed} ago
|
|
42
68
|
Duration so far: {session.duration}
|
|
69
|
+
Reason: {session.pauseReason}
|
|
43
70
|
|
|
44
71
|
/p:resume to continue | /p:done to complete
|
|
45
72
|
```
|
|
@@ -49,7 +76,17 @@ IF {session.status} != "active":
|
|
|
49
76
|
OUTPUT: "⚠️ No active session to pause."
|
|
50
77
|
STOP
|
|
51
78
|
|
|
52
|
-
## Step 3:
|
|
79
|
+
## Step 3: Get Pause Reason
|
|
80
|
+
|
|
81
|
+
IF {reason} not provided:
|
|
82
|
+
ASK user to select reason (blocked, switch, break, research)
|
|
83
|
+
OR auto-detect "break" as default
|
|
84
|
+
|
|
85
|
+
IF {reason} == "blocked":
|
|
86
|
+
ASK for blocker note: "What's blocking you?"
|
|
87
|
+
SET: {blockerNote} = user response
|
|
88
|
+
|
|
89
|
+
## Step 4: Calculate Duration So Far
|
|
53
90
|
|
|
54
91
|
SET: {now} = GetTimestamp()
|
|
55
92
|
|
|
@@ -60,7 +97,7 @@ For each event in {session.timeline}:
|
|
|
60
97
|
SET: {duration} = total active seconds
|
|
61
98
|
SET: {durationFormatted} = format as "Xh Ym" or "Xm"
|
|
62
99
|
|
|
63
|
-
## Step
|
|
100
|
+
## Step 5: Update Session
|
|
64
101
|
|
|
65
102
|
UPDATE {session}:
|
|
66
103
|
```json
|
|
@@ -71,12 +108,14 @@ UPDATE {session}:
|
|
|
71
108
|
"status": "paused",
|
|
72
109
|
"startedAt": "{session.startedAt}",
|
|
73
110
|
"pausedAt": "{now}",
|
|
111
|
+
"pauseReason": "{reason}",
|
|
112
|
+
"pauseNote": "{blockerNote}",
|
|
74
113
|
"completedAt": null,
|
|
75
114
|
"duration": {duration},
|
|
76
115
|
"metrics": {session.metrics},
|
|
77
116
|
"timeline": [
|
|
78
117
|
...{session.timeline},
|
|
79
|
-
{"type": "pause", "at": "{now}"}
|
|
118
|
+
{"type": "pause", "at": "{now}", "reason": "{reason}", "note": "{blockerNote}"}
|
|
80
119
|
]
|
|
81
120
|
}
|
|
82
121
|
```
|
|
@@ -84,7 +123,7 @@ UPDATE {session}:
|
|
|
84
123
|
WRITE: `{sessionPath}`
|
|
85
124
|
Content: Updated session JSON
|
|
86
125
|
|
|
87
|
-
## Step
|
|
126
|
+
## Step 6: Update now.md (SOURCE OF TRUTH)
|
|
88
127
|
|
|
89
128
|
WRITE: `{nowPath}`
|
|
90
129
|
Content:
|
|
@@ -96,16 +135,18 @@ Content:
|
|
|
96
135
|
Started: {session.startedAt}
|
|
97
136
|
Paused: {now}
|
|
98
137
|
Duration: {durationFormatted}
|
|
138
|
+
Reason: {reason}
|
|
99
139
|
Session: {session.id}
|
|
140
|
+
{IF blockerNote: Note: {blockerNote}}
|
|
100
141
|
```
|
|
101
142
|
|
|
102
|
-
## Step
|
|
143
|
+
## Step 7: Log to Memory
|
|
103
144
|
|
|
104
145
|
APPEND to: `{memoryPath}`
|
|
105
146
|
|
|
106
147
|
Single line (JSONL):
|
|
107
148
|
```json
|
|
108
|
-
{"timestamp":"{now}","action":"session_paused","sessionId":"{session.id}","task":"{session.task}","duration":{duration}}
|
|
149
|
+
{"timestamp":"{now}","action":"session_paused","sessionId":"{session.id}","task":"{session.task}","duration":{duration},"reason":"{reason}","note":"{blockerNote}"}
|
|
109
150
|
```
|
|
110
151
|
|
|
111
152
|
## Output
|
|
@@ -116,6 +157,8 @@ SUCCESS:
|
|
|
116
157
|
|
|
117
158
|
Session: {session.id}
|
|
118
159
|
Active time: {durationFormatted}
|
|
160
|
+
Reason: {reason}
|
|
161
|
+
{IF blockerNote: Note: {blockerNote}}
|
|
119
162
|
|
|
120
163
|
Next:
|
|
121
164
|
• /p:resume - Continue this task
|
|
@@ -134,22 +177,27 @@ Next:
|
|
|
134
177
|
|
|
135
178
|
## Examples
|
|
136
179
|
|
|
137
|
-
### Example 1: Pause
|
|
138
|
-
**
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
"status": "active",
|
|
144
|
-
"startedAt": "2025-12-07T10:00:00.000Z",
|
|
145
|
-
"timeline": [
|
|
146
|
-
{"type": "start", "at": "2025-12-07T10:00:00.000Z"}
|
|
147
|
-
]
|
|
148
|
-
}
|
|
180
|
+
### Example 1: Pause with Blocked Reason
|
|
181
|
+
**Input:** `/p:pause blocked`
|
|
182
|
+
**Prompt:** "What's blocking you?"
|
|
183
|
+
**User:** "Waiting for API credentials from vendor"
|
|
184
|
+
|
|
185
|
+
**Output:**
|
|
149
186
|
```
|
|
187
|
+
⏸️ Paused: implement auth
|
|
150
188
|
|
|
151
|
-
|
|
152
|
-
|
|
189
|
+
Session: sess_abc12345
|
|
190
|
+
Active time: 2h 30m
|
|
191
|
+
Reason: blocked
|
|
192
|
+
Note: Waiting for API credentials from vendor
|
|
193
|
+
|
|
194
|
+
Next:
|
|
195
|
+
• /p:resume - Continue this task
|
|
196
|
+
• /p:now <task> - Start different task
|
|
197
|
+
```
|
|
198
|
+
|
|
199
|
+
### Example 2: Quick Break
|
|
200
|
+
**Input:** `/p:pause break`
|
|
153
201
|
|
|
154
202
|
**Output:**
|
|
155
203
|
```
|
|
@@ -157,26 +205,38 @@ Next:
|
|
|
157
205
|
|
|
158
206
|
Session: sess_abc12345
|
|
159
207
|
Active time: 2h 30m
|
|
208
|
+
Reason: break
|
|
160
209
|
|
|
161
210
|
Next:
|
|
162
211
|
• /p:resume - Continue this task
|
|
163
|
-
• /p:now <task> - Start different task
|
|
164
|
-
• /p:done - Complete without resuming
|
|
165
212
|
```
|
|
166
213
|
|
|
167
|
-
### Example
|
|
214
|
+
### Example 3: Context Switch
|
|
215
|
+
**Input:** `/p:pause switch`
|
|
216
|
+
|
|
168
217
|
**Output:**
|
|
169
218
|
```
|
|
170
|
-
⏸️
|
|
219
|
+
⏸️ Paused: implement auth
|
|
171
220
|
|
|
172
|
-
|
|
173
|
-
|
|
221
|
+
Session: sess_abc12345
|
|
222
|
+
Active time: 2h 30m
|
|
223
|
+
Reason: switch
|
|
174
224
|
|
|
175
|
-
|
|
225
|
+
Next:
|
|
226
|
+
• /p:now <task> - Start the urgent task
|
|
176
227
|
```
|
|
177
228
|
|
|
178
|
-
### Example
|
|
229
|
+
### Example 4: No Reason (Interactive)
|
|
230
|
+
**Input:** `/p:pause`
|
|
231
|
+
|
|
179
232
|
**Output:**
|
|
180
233
|
```
|
|
181
|
-
|
|
234
|
+
Why are you pausing?
|
|
235
|
+
|
|
236
|
+
1. blocked - Waiting on something external
|
|
237
|
+
2. switch - Starting a different task
|
|
238
|
+
3. break - Taking a break
|
|
239
|
+
4. research - Need to investigate
|
|
240
|
+
|
|
241
|
+
Select [1-4]:
|
|
182
242
|
```
|