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.
Files changed (39) hide show
  1. package/CHANGELOG.md +43 -0
  2. package/CLAUDE.md +18 -6
  3. package/core/data/index.ts +19 -5
  4. package/core/data/md-base-manager.ts +203 -0
  5. package/core/data/md-queue-manager.ts +179 -0
  6. package/core/data/md-state-manager.ts +133 -0
  7. package/core/serializers/index.ts +20 -0
  8. package/core/serializers/queue-serializer.ts +210 -0
  9. package/core/serializers/state-serializer.ts +136 -0
  10. package/core/utils/file-helper.ts +12 -0
  11. package/package.json +1 -1
  12. package/packages/web/app/api/projects/[id]/stats/route.ts +6 -29
  13. package/packages/web/app/page.tsx +1 -6
  14. package/packages/web/app/project/[id]/page.tsx +34 -1
  15. package/packages/web/app/project/[id]/stats/page.tsx +11 -5
  16. package/packages/web/app/settings/page.tsx +2 -221
  17. package/packages/web/components/BlockersCard/BlockersCard.tsx +67 -0
  18. package/packages/web/components/BlockersCard/BlockersCard.types.ts +11 -0
  19. package/packages/web/components/BlockersCard/index.ts +2 -0
  20. package/packages/web/components/CommandButton/CommandButton.tsx +10 -3
  21. package/packages/web/lib/projects.ts +28 -27
  22. package/packages/web/lib/services/projects.server.ts +25 -21
  23. package/packages/web/lib/services/stats.server.ts +355 -57
  24. package/packages/web/package.json +0 -2
  25. package/templates/commands/decision.md +226 -0
  26. package/templates/commands/done.md +100 -68
  27. package/templates/commands/feature.md +102 -103
  28. package/templates/commands/idea.md +41 -38
  29. package/templates/commands/now.md +94 -33
  30. package/templates/commands/pause.md +90 -30
  31. package/templates/commands/ship.md +179 -74
  32. package/templates/commands/sync.md +324 -200
  33. package/packages/web/app/api/migrate/route.ts +0 -46
  34. package/packages/web/app/api/settings/route.ts +0 -97
  35. package/packages/web/app/api/v2/projects/[id]/unified/route.ts +0 -57
  36. package/packages/web/components/MigrationGate/MigrationGate.tsx +0 -304
  37. package/packages/web/components/MigrationGate/index.ts +0 -1
  38. package/packages/web/lib/json-loader.ts +0 -630
  39. 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: 'JSON-first - Write to data/*.json, views are generated'
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: JSON-First
10
+ ## Architecture: MD-First
11
11
 
12
- **Source of Truth**: `data/state.json`
13
- **Generated View**: `views/now.md` (auto-generated, do not edit directly)
12
+ **Source of Truth**: `core/now.md`
14
13
 
15
- All writes go to JSON. After writing, run `prjct generate-views --project={projectId}` to regenerate MD views.
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
- - `{dataPath}`: `{globalPath}/data`
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 state.json (source of truth)
38
- READ: `{statePath}`
49
+ ### Read now.md (source of truth)
50
+ READ: `{nowPath}`
39
51
 
40
- IF file exists:
41
- PARSE as JSON
42
- EXTRACT: {currentTask} from state.currentTask
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 (legacy support)
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 state.json (SOURCE OF TRUTH)
108
- READ: `{statePath}` (or create default if not exists)
122
+ ### Write now.md (SOURCE OF TRUTH)
109
123
 
110
- UPDATE state.json:
111
- ```json
112
- {
113
- "currentTask": {
114
- "id": "task_{8_random_chars}",
115
- "description": "{task}",
116
- "startedAt": "{startedAt}",
117
- "sessionId": "{sessionId}"
118
- },
119
- "lastUpdated": "{startedAt}"
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
- WRITE: `{statePath}`
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
- ### Generate views (auto-regenerate MD from JSON)
152
- BASH: `cd {projectRoot} && npx prjct-generate-views --project={projectId}`
153
-
154
- Note: This regenerates views/now.md from data/state.json automatically.
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: Calculate Duration So Far
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 4: Update Session
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 5: Update Legacy now.md
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 6: Log to Memory
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 Active Session
138
- **Session:**
139
- ```json
140
- {
141
- "id": "sess_abc12345",
142
- "task": "implement auth",
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
- **Current time:** 12:30 PM
152
- **Duration:** 2h 30m
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 2: Already Paused
214
+ ### Example 3: Context Switch
215
+ **Input:** `/p:pause switch`
216
+
168
217
  **Output:**
169
218
  ```
170
- ⏸️ Already paused: implement auth
219
+ ⏸️ Paused: implement auth
171
220
 
172
- Paused: 15m ago
173
- Duration so far: 2h 30m
221
+ Session: sess_abc12345
222
+ Active time: 2h 30m
223
+ Reason: switch
174
224
 
175
- /p:resume to continue | /p:done to complete
225
+ Next:
226
+ • /p:now <task> - Start the urgent task
176
227
  ```
177
228
 
178
- ### Example 3: No Active Session
229
+ ### Example 4: No Reason (Interactive)
230
+ **Input:** `/p:pause`
231
+
179
232
  **Output:**
180
233
  ```
181
- ⚠️ No active session to pause. Use /p:now to start one.
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
  ```