prjct-cli 0.12.2 → 0.13.1

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 (40) 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/next-env.d.ts +1 -1
  25. package/packages/web/package.json +0 -4
  26. package/templates/commands/decision.md +226 -0
  27. package/templates/commands/done.md +100 -68
  28. package/templates/commands/feature.md +102 -103
  29. package/templates/commands/idea.md +41 -38
  30. package/templates/commands/now.md +94 -33
  31. package/templates/commands/pause.md +90 -30
  32. package/templates/commands/ship.md +179 -74
  33. package/templates/commands/sync.md +324 -200
  34. package/packages/web/app/api/migrate/route.ts +0 -46
  35. package/packages/web/app/api/settings/route.ts +0 -97
  36. package/packages/web/app/api/v2/projects/[id]/unified/route.ts +0 -57
  37. package/packages/web/components/MigrationGate/MigrationGate.tsx +0 -304
  38. package/packages/web/components/MigrationGate/index.ts +0 -1
  39. package/packages/web/lib/json-loader.ts +0 -630
  40. package/packages/web/lib/services/migration.server.ts +0 -580
@@ -2,15 +2,16 @@
2
2
  allowed-tools: [Read, Write, Bash, Task, Glob]
3
3
  description: 'Value analysis + roadmap + task breakdown + auto-start'
4
4
  timestamp-rule: 'GetTimestamp() and GetDate() 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:feature - Add Feature to Roadmap
9
9
 
10
- ## Architecture: JSON-First
10
+ ## Architecture: MD-First
11
11
 
12
- **Source of Truth**: `data/roadmap.json`, `data/queue.json`, `data/state.json`
13
- **Generated Views**: `views/roadmap.md`, `views/next.md`, `views/now.md` (auto-generated)
12
+ **Source of Truth**: `planning/roadmap.md`, `core/next.md`, `core/now.md`
13
+
14
+ MD files are the source of truth. Write directly to MD files.
14
15
 
15
16
  ## Agent Delegation (REQUIRED)
16
17
 
@@ -52,10 +53,9 @@ Task(
52
53
  ## Context Variables
53
54
  - `{projectId}`: From `.prjct/prjct.config.json`
54
55
  - `{globalPath}`: `~/.prjct-cli/projects/{projectId}`
55
- - `{dataPath}`: `{globalPath}/data`
56
- - `{roadmapPath}`: `{dataPath}/roadmap.json`
57
- - `{queuePath}`: `{dataPath}/queue.json`
58
- - `{statePath}`: `{dataPath}/state.json`
56
+ - `{roadmapPath}`: `{globalPath}/planning/roadmap.md`
57
+ - `{nextPath}`: `{globalPath}/core/next.md`
58
+ - `{nowPath}`: `{globalPath}/core/now.md`
59
59
  - `{memoryPath}`: `{globalPath}/memory/context.jsonl`
60
60
  - `{feature}`: User-provided feature description
61
61
 
@@ -149,138 +149,137 @@ For feature "add user authentication":
149
149
 
150
150
  GENERATE: {tasks} = list of task descriptions
151
151
 
152
- ## Step 5: Update Roadmap (JSON)
152
+ ## Step 5: Update Roadmap (MD)
153
153
 
154
154
  READ: `{roadmapPath}` (or create default if not exists)
155
155
 
156
156
  Default structure:
157
- ```json
158
- {
159
- "features": [],
160
- "backlog": [],
161
- "lastUpdated": ""
162
- }
157
+ ```markdown
158
+ # Roadmap
159
+
160
+ ## Active
161
+
162
+ _No active features_
163
+
164
+ ## Planned
165
+
166
+ _No planned features_
167
+
168
+ ## Shipped
169
+
170
+ _Nothing shipped yet_
163
171
  ```
164
172
 
165
173
  ### Generate Feature ID
166
174
  GENERATE: {featureId} = "feat_" + 8 random alphanumeric chars
167
175
  SET: {now} = GetTimestamp()
168
176
 
169
- ### Create Feature Entry
170
- ```json
171
- {
172
- "id": "{featureId}",
173
- "name": "{feature}",
174
- "impact": "{impact}",
175
- "effort": "{effort}",
176
- "status": "active",
177
- "progress": 0,
178
- "tasks": [
179
- {
180
- "id": "task_{8_random}",
181
- "description": "{task1}",
182
- "completed": false,
183
- "createdAt": "{now}"
184
- },
185
- {
186
- "id": "task_{8_random}",
187
- "description": "{task2}",
188
- "completed": false,
189
- "createdAt": "{now}"
190
- }
191
- ...
192
- ],
193
- "createdAt": "{now}"
194
- }
195
- ```
177
+ ### Update roadmap.md
196
178
 
197
- ### Update roadmap.json
198
- ```json
199
- {
200
- "features": [
201
- {new feature entry},
202
- ...existing features
203
- ],
204
- "backlog": [...existing],
205
- "lastUpdated": "{now}"
206
- }
179
+ Parse existing content and add new feature under "## Active" section:
180
+
181
+ ```markdown
182
+ # Roadmap
183
+
184
+ ## Active
185
+
186
+ ### {feature}
187
+ - **ID**: {featureId}
188
+ - **Impact**: {impact}
189
+ - **Effort**: {effort}
190
+ - **Started**: {now}
191
+ - **Tasks**:
192
+ - [ ] {task1}
193
+ - [ ] {task2}
194
+ - [ ] {task3}
195
+ ...
196
+
197
+ {...existing active features}
198
+
199
+ ## Planned
200
+
201
+ {...existing planned features}
202
+
203
+ ## Shipped
204
+
205
+ {...existing shipped features}
207
206
  ```
208
207
 
209
208
  WRITE: `{roadmapPath}`
210
209
 
211
- ## Step 6: Update Priority Queue (JSON)
210
+ ## Step 6: Update Priority Queue (MD)
212
211
 
213
- READ: `{queuePath}` (or create default if not exists)
212
+ READ: `{nextPath}` (or create default if not exists)
214
213
 
215
214
  Default structure:
216
- ```json
217
- {
218
- "tasks": [],
219
- "lastUpdated": ""
220
- }
215
+ ```markdown
216
+ # Next
217
+
218
+ ## High Priority
219
+
220
+ _No high priority tasks_
221
+
222
+ ## Normal Priority
223
+
224
+ _No tasks in queue_
225
+
226
+ ## Low Priority
227
+
228
+ _No low priority tasks_
221
229
  ```
222
230
 
223
231
  ### Add Tasks to Queue
224
- For each task in {tasks}:
225
- ```json
226
- {
227
- "id": "task_{8_random}",
228
- "description": "{task}",
229
- "priority": "medium",
230
- "featureId": "{featureId}",
231
- "completed": false,
232
- "createdAt": "{now}"
233
- }
234
- ```
235
232
 
236
- ### Update queue.json
237
- ```json
238
- {
239
- "tasks": [
240
- ...new tasks,
241
- ...existing tasks
242
- ],
243
- "lastUpdated": "{now}"
244
- }
233
+ For each task in {tasks}, add to appropriate priority section:
234
+
235
+ ```markdown
236
+ # Next
237
+
238
+ ## High Priority
239
+
240
+ {if high priority tasks}
241
+
242
+ ## Normal Priority
243
+
244
+ - [ ] {task1} @{featureId}
245
+ - [ ] {task2} @{featureId}
246
+ ...
247
+
248
+ {...existing tasks}
249
+
250
+ ## Low Priority
251
+
252
+ {...existing low priority tasks}
245
253
  ```
246
254
 
247
- WRITE: `{queuePath}`
255
+ WRITE: `{nextPath}`
248
256
 
249
- ## Step 7: Auto-Start First Task (JSON)
257
+ ## Step 7: Auto-Start First Task (MD)
250
258
 
251
- READ: `{statePath}` (or create default)
259
+ READ: `{nowPath}`
252
260
 
253
- IF currentTask is null:
261
+ IF file is empty OR contains "_No active task_":
254
262
  ### Start First Task
255
263
  {firstTask} = first item from {tasks}
256
264
  GENERATE: {sessionId} = "sess_" + 8 random alphanumeric chars
257
265
 
258
- ### Update state.json
259
- ```json
260
- {
261
- "currentTask": {
262
- "id": "task_{8_random}",
263
- "description": "{firstTask}",
264
- "startedAt": "{now}",
265
- "sessionId": "{sessionId}",
266
- "featureId": "{featureId}"
267
- },
268
- "lastUpdated": "{now}"
269
- }
266
+ ### Update now.md
267
+ ```markdown
268
+ # NOW
269
+
270
+ **{firstTask}**
271
+
272
+ Started: {now}
273
+ Session: {sessionId}
274
+ Feature: {featureId}
270
275
  ```
271
276
 
272
- WRITE: `{statePath}`
277
+ WRITE: `{nowPath}`
273
278
  {autoStarted} = true
274
279
  ELSE:
275
280
  {autoStarted} = false
276
281
 
277
- ## Step 8: Generate Views
278
-
279
- BASH: `cd {projectRoot} && npx prjct-generate-views --project={projectId}`
280
-
281
- Note: This regenerates views/roadmap.md, views/next.md, views/now.md from JSON automatically.
282
-
283
- ## Step 9: Log to Memory
282
+ ## Step 8: Log to Memory
284
283
 
285
284
  GET: {date} = GetDate()
286
285
  EXTRACT: {yearMonth} = YYYY-MM from {date}
@@ -2,21 +2,21 @@
2
2
  allowed-tools: [Read, Write, Bash, GetTimestamp, GetDate]
3
3
  description: 'Quick idea capture'
4
4
  timestamp-rule: 'GetTimestamp() and GetDate() for timestamps'
5
- architecture: 'JSON-first - Write to data/ideas.json, views are generated'
5
+ architecture: 'MD-first - MD files are source of truth'
6
6
  ---
7
7
 
8
8
  # /p:idea - Quick Idea Capture
9
9
 
10
- ## Architecture: JSON-First
10
+ ## Architecture: MD-First
11
11
 
12
- **Source of Truth**: `data/ideas.json`
13
- **Generated View**: `views/ideas.md` (auto-generated)
12
+ **Source of Truth**: `planning/ideas.md`
13
+
14
+ MD files are the source of truth. Write directly to MD files.
14
15
 
15
16
  ## Context Variables
16
17
  - `{projectId}`: From `.prjct/prjct.config.json`
17
18
  - `{globalPath}`: `~/.prjct-cli/projects/{projectId}`
18
- - `{dataPath}`: `{globalPath}/data`
19
- - `{ideasPath}`: `{dataPath}/ideas.json`
19
+ - `{ideasPath}`: `{globalPath}/planning/ideas.md`
20
20
  - `{memoryPath}`: `{globalPath}/memory/context.jsonl`
21
21
  - `{text}`: User-provided idea text
22
22
 
@@ -34,50 +34,53 @@ IF file not found:
34
34
  READ: `{ideasPath}` (or create default if not exists)
35
35
 
36
36
  Default structure:
37
- ```json
38
- {
39
- "ideas": [],
40
- "lastUpdated": ""
41
- }
37
+ ```markdown
38
+ # Ideas
39
+
40
+ ## Pending
41
+
42
+ _No ideas yet_
43
+
44
+ ## Implemented
45
+
46
+ _Nothing implemented yet_
42
47
  ```
43
48
 
44
- ## Step 3: Add New Idea (JSON)
49
+ ## Step 3: Add New Idea (MD)
45
50
 
46
51
  GENERATE: {ideaId} = "idea_" + 8 random alphanumeric chars
47
52
  SET: {now} = GetTimestamp()
48
53
 
49
54
  ### Analyze idea for tags
50
55
  Based on {text}, detect tags:
51
- - If mentions UI/design → add "ui" tag
52
- - If mentions performance → add "perf" tag
53
- - If mentions bug/fix → add "bug" tag
54
- - If mentions API/backend → add "api" tag
56
+ - If mentions UI/design → add `#ui` tag
57
+ - If mentions performance → add `#perf` tag
58
+ - If mentions bug/fix → add `#bug` tag
59
+ - If mentions API/backend → add `#api` tag
55
60
 
56
- ### Update ideas.json
57
- ```json
58
- {
59
- "ideas": [
60
- {
61
- "id": "{ideaId}",
62
- "text": "{text}",
63
- "priority": "medium",
64
- "status": "pending",
65
- "tags": [{detected_tags}],
66
- "createdAt": "{now}"
67
- },
68
- ...existing ideas
69
- ],
70
- "lastUpdated": "{now}"
71
- }
72
- ```
61
+ ### Update ideas.md
73
62
 
74
- WRITE: `{ideasPath}`
63
+ Parse existing content and add new idea under "## Pending" section:
64
+
65
+ ```markdown
66
+ # Ideas
67
+
68
+ ## Pending
69
+
70
+ - **{text}** #{detected_tags}
71
+ - ID: {ideaId}
72
+ - Added: {now}
75
73
 
76
- ## Step 4: Generate Views
74
+ {...existing pending ideas}
77
75
 
78
- BASH: `cd {projectRoot} && npx prjct-generate-views --project={projectId}`
76
+ ## Implemented
77
+
78
+ {...existing implemented ideas}
79
+ ```
80
+
81
+ WRITE: `{ideasPath}`
79
82
 
80
- ## Step 5: Log to Memory
83
+ ## Step 4: Log to Memory
81
84
 
82
85
  APPEND to: `{memoryPath}`
83
86
  ```json
@@ -86,4 +89,4 @@ APPEND to: `{memoryPath}`
86
89
 
87
90
  ## Response
88
91
 
89
- `💡 {text} | Saved | Start: /p:feature "{text}"`
92
+ `💡 {text} | Saved | Start: /p:feature "{text}"`
@@ -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