prjct-cli 0.13.3 → 0.15.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 (195) hide show
  1. package/CHANGELOG.md +122 -0
  2. package/bin/prjct +10 -13
  3. package/core/agentic/memory-system/semantic-memories.ts +2 -1
  4. package/core/agentic/plan-mode/plan-mode.ts +2 -1
  5. package/core/agentic/prompt-builder.ts +22 -43
  6. package/core/agentic/services.ts +5 -5
  7. package/core/agentic/smart-context.ts +7 -2
  8. package/core/command-registry/core-commands.ts +54 -29
  9. package/core/command-registry/optional-commands.ts +64 -0
  10. package/core/command-registry/setup-commands.ts +18 -3
  11. package/core/commands/analysis.ts +21 -68
  12. package/core/commands/analytics.ts +247 -213
  13. package/core/commands/base.ts +1 -1
  14. package/core/commands/index.ts +41 -36
  15. package/core/commands/maintenance.ts +300 -31
  16. package/core/commands/planning.ts +233 -22
  17. package/core/commands/setup.ts +3 -8
  18. package/core/commands/shipping.ts +14 -18
  19. package/core/commands/types.ts +8 -6
  20. package/core/commands/workflow.ts +105 -100
  21. package/core/context/generator.ts +317 -0
  22. package/core/context-sync.ts +7 -350
  23. package/core/data/index.ts +13 -32
  24. package/core/data/md-ideas-manager.ts +155 -0
  25. package/core/data/md-queue-manager.ts +4 -3
  26. package/core/data/md-shipped-manager.ts +90 -0
  27. package/core/data/md-state-manager.ts +11 -7
  28. package/core/domain/agent-generator.ts +23 -63
  29. package/core/events/index.ts +143 -0
  30. package/core/index.ts +17 -14
  31. package/core/infrastructure/capability-installer.ts +13 -149
  32. package/core/infrastructure/migrator/project-scanner.ts +2 -1
  33. package/core/infrastructure/path-manager.ts +4 -6
  34. package/core/infrastructure/setup.ts +3 -0
  35. package/core/infrastructure/uuid-migration.ts +750 -0
  36. package/core/outcomes/recorder.ts +2 -1
  37. package/core/plugin/loader.ts +4 -7
  38. package/core/plugin/registry.ts +3 -3
  39. package/core/schemas/index.ts +23 -25
  40. package/core/schemas/state.ts +1 -0
  41. package/core/serializers/ideas-serializer.ts +187 -0
  42. package/core/serializers/index.ts +16 -0
  43. package/core/serializers/shipped-serializer.ts +108 -0
  44. package/core/session/utils.ts +3 -9
  45. package/core/storage/ideas-storage.ts +273 -0
  46. package/core/storage/index.ts +204 -0
  47. package/core/storage/queue-storage.ts +297 -0
  48. package/core/storage/shipped-storage.ts +223 -0
  49. package/core/storage/state-storage.ts +235 -0
  50. package/core/storage/storage-manager.ts +175 -0
  51. package/package.json +1 -1
  52. package/packages/web/app/api/projects/[id]/momentum/route.ts +257 -0
  53. package/packages/web/app/api/sessions/current/route.ts +132 -0
  54. package/packages/web/app/api/sessions/history/route.ts +96 -14
  55. package/packages/web/app/globals.css +5 -0
  56. package/packages/web/app/layout.tsx +2 -0
  57. package/packages/web/app/project/[id]/code/layout.tsx +18 -0
  58. package/packages/web/app/project/[id]/code/page.tsx +408 -0
  59. package/packages/web/app/project/[id]/page.tsx +359 -389
  60. package/packages/web/app/project/[id]/reports/page.tsx +59 -0
  61. package/packages/web/app/project/[id]/reports/print/page.tsx +58 -0
  62. package/packages/web/components/ActivityTimeline/ActivityTimeline.tsx +0 -1
  63. package/packages/web/components/AgentsCard/AgentsCard.tsx +64 -34
  64. package/packages/web/components/AgentsCard/AgentsCard.types.ts +1 -0
  65. package/packages/web/components/AppSidebar/AppSidebar.tsx +135 -11
  66. package/packages/web/components/BentoCard/BentoCard.constants.ts +3 -3
  67. package/packages/web/components/BentoCard/BentoCard.tsx +2 -1
  68. package/packages/web/components/BentoGrid/BentoGrid.tsx +2 -2
  69. package/packages/web/components/BlockersCard/BlockersCard.tsx +65 -57
  70. package/packages/web/components/BlockersCard/BlockersCard.types.ts +1 -0
  71. package/packages/web/components/CommandBar/CommandBar.tsx +67 -0
  72. package/packages/web/components/CommandBar/index.ts +1 -0
  73. package/packages/web/components/DashboardContent/DashboardContent.tsx +35 -5
  74. package/packages/web/components/DateGroup/DateGroup.tsx +1 -1
  75. package/packages/web/components/EmptyState/EmptyState.tsx +39 -21
  76. package/packages/web/components/EmptyState/EmptyState.types.ts +1 -0
  77. package/packages/web/components/EventRow/EventRow.tsx +4 -4
  78. package/packages/web/components/EventRow/EventRow.utils.ts +3 -3
  79. package/packages/web/components/HeroSection/HeroSection.tsx +52 -15
  80. package/packages/web/components/HeroSection/HeroSection.types.ts +4 -4
  81. package/packages/web/components/HeroSection/HeroSection.utils.ts +7 -3
  82. package/packages/web/components/IdeasCard/IdeasCard.tsx +94 -27
  83. package/packages/web/components/IdeasCard/IdeasCard.types.ts +1 -0
  84. package/packages/web/components/MasonryGrid/MasonryGrid.tsx +18 -0
  85. package/packages/web/components/MasonryGrid/index.ts +1 -0
  86. package/packages/web/components/MomentumWidget/MomentumWidget.tsx +119 -0
  87. package/packages/web/components/MomentumWidget/MomentumWidget.types.ts +16 -0
  88. package/packages/web/components/MomentumWidget/index.ts +2 -0
  89. package/packages/web/components/NowCard/NowCard.tsx +81 -56
  90. package/packages/web/components/NowCard/NowCard.types.ts +1 -0
  91. package/packages/web/components/PageHeader/PageHeader.tsx +24 -0
  92. package/packages/web/components/PageHeader/index.ts +1 -0
  93. package/packages/web/components/ProgressRing/ProgressRing.constants.ts +2 -2
  94. package/packages/web/components/ProjectAvatar/ProjectAvatar.tsx +2 -2
  95. package/packages/web/components/ProjectColorDot/ProjectColorDot.tsx +37 -0
  96. package/packages/web/components/ProjectColorDot/index.ts +1 -0
  97. package/packages/web/components/ProjectSelectorModal/ProjectSelectorModal.tsx +104 -0
  98. package/packages/web/components/ProjectSelectorModal/index.ts +1 -0
  99. package/packages/web/components/Providers/Providers.tsx +4 -1
  100. package/packages/web/components/QueueCard/QueueCard.tsx +78 -25
  101. package/packages/web/components/QueueCard/QueueCard.types.ts +1 -0
  102. package/packages/web/components/QueueCard/QueueCard.utils.ts +3 -3
  103. package/packages/web/components/RecoverCard/RecoverCard.tsx +72 -0
  104. package/packages/web/components/RecoverCard/RecoverCard.types.ts +16 -0
  105. package/packages/web/components/RecoverCard/index.ts +2 -0
  106. package/packages/web/components/RoadmapCard/RoadmapCard.tsx +101 -33
  107. package/packages/web/components/RoadmapCard/RoadmapCard.types.ts +1 -0
  108. package/packages/web/components/ShipsCard/ShipsCard.tsx +71 -28
  109. package/packages/web/components/ShipsCard/ShipsCard.types.ts +2 -0
  110. package/packages/web/components/SparklineChart/SparklineChart.tsx +20 -18
  111. package/packages/web/components/StatsMasonry/StatsMasonry.tsx +95 -0
  112. package/packages/web/components/StatsMasonry/index.ts +1 -0
  113. package/packages/web/components/StreakCard/StreakCard.tsx +37 -35
  114. package/packages/web/components/TasksCounter/TasksCounter.tsx +1 -1
  115. package/packages/web/components/TechStackBadges/TechStackBadges.tsx +12 -4
  116. package/packages/web/components/TerminalDock/DockToggleTab.tsx +29 -0
  117. package/packages/web/components/TerminalDock/TerminalDock.tsx +386 -0
  118. package/packages/web/components/TerminalDock/TerminalDockTab.tsx +130 -0
  119. package/packages/web/components/TerminalDock/TerminalTabBar.tsx +142 -0
  120. package/packages/web/components/TerminalDock/index.ts +2 -0
  121. package/packages/web/components/VelocityBadge/VelocityBadge.tsx +8 -3
  122. package/packages/web/components/VelocityCard/VelocityCard.tsx +49 -47
  123. package/packages/web/components/WeeklyReports/PrintableReport.tsx +259 -0
  124. package/packages/web/components/WeeklyReports/ReportPreviewCard.tsx +187 -0
  125. package/packages/web/components/WeeklyReports/WeekCalendar.tsx +288 -0
  126. package/packages/web/components/WeeklyReports/WeeklyReports.tsx +149 -0
  127. package/packages/web/components/WeeklyReports/index.ts +4 -0
  128. package/packages/web/components/WeeklySparkline/WeeklySparkline.tsx +16 -4
  129. package/packages/web/components/WeeklySparkline/WeeklySparkline.types.ts +1 -0
  130. package/packages/web/components/charts/SessionsChart.tsx +6 -3
  131. package/packages/web/components/ui/dialog.tsx +143 -0
  132. package/packages/web/components/ui/drawer.tsx +135 -0
  133. package/packages/web/components/ui/select.tsx +187 -0
  134. package/packages/web/context/GlobalTerminalContext.tsx +538 -0
  135. package/packages/web/lib/commands.ts +81 -0
  136. package/packages/web/lib/generate-week-report.ts +285 -0
  137. package/packages/web/lib/parse-prjct-files.ts +56 -55
  138. package/packages/web/lib/project-colors.ts +58 -0
  139. package/packages/web/lib/projects.ts +58 -5
  140. package/packages/web/lib/services/projects.server.ts +11 -1
  141. package/packages/web/next-env.d.ts +1 -1
  142. package/packages/web/package.json +5 -1
  143. package/templates/commands/analyze.md +39 -3
  144. package/templates/commands/ask.md +58 -3
  145. package/templates/commands/bug.md +117 -26
  146. package/templates/commands/dash.md +95 -158
  147. package/templates/commands/done.md +130 -148
  148. package/templates/commands/feature.md +125 -103
  149. package/templates/commands/git.md +18 -3
  150. package/templates/commands/idea.md +121 -38
  151. package/templates/commands/init.md +124 -20
  152. package/templates/commands/migrate-all.md +63 -28
  153. package/templates/commands/migrate.md +140 -0
  154. package/templates/commands/next.md +115 -5
  155. package/templates/commands/now.md +146 -82
  156. package/templates/commands/pause.md +89 -74
  157. package/templates/commands/redo.md +6 -4
  158. package/templates/commands/resume.md +141 -59
  159. package/templates/commands/setup.md +18 -3
  160. package/templates/commands/ship.md +103 -231
  161. package/templates/commands/spec.md +98 -8
  162. package/templates/commands/suggest.md +22 -2
  163. package/templates/commands/sync.md +192 -203
  164. package/templates/commands/undo.md +6 -4
  165. package/templates/mcp-config.json +20 -1
  166. package/core/data/agents-manager.ts +0 -76
  167. package/core/data/analysis-manager.ts +0 -83
  168. package/core/data/base-manager.ts +0 -156
  169. package/core/data/ideas-manager.ts +0 -81
  170. package/core/data/outcomes-manager.ts +0 -96
  171. package/core/data/project-manager.ts +0 -75
  172. package/core/data/roadmap-manager.ts +0 -118
  173. package/core/data/shipped-manager.ts +0 -65
  174. package/core/data/state-manager.ts +0 -214
  175. package/core/state/index.ts +0 -25
  176. package/core/state/manager.ts +0 -376
  177. package/core/state/types.ts +0 -185
  178. package/core/utils/project-capabilities.ts +0 -156
  179. package/core/view-generator.ts +0 -536
  180. package/packages/web/app/project/[id]/stats/loading.tsx +0 -43
  181. package/packages/web/app/project/[id]/stats/page.tsx +0 -253
  182. package/templates/agent-assignment.md +0 -72
  183. package/templates/analysis/project-analysis.md +0 -78
  184. package/templates/checklists/accessibility.md +0 -33
  185. package/templates/commands/build.md +0 -17
  186. package/templates/commands/decision.md +0 -226
  187. package/templates/commands/fix.md +0 -79
  188. package/templates/commands/help.md +0 -61
  189. package/templates/commands/progress.md +0 -14
  190. package/templates/commands/recap.md +0 -14
  191. package/templates/commands/roadmap.md +0 -52
  192. package/templates/commands/status.md +0 -17
  193. package/templates/commands/task.md +0 -63
  194. package/templates/commands/work.md +0 -44
  195. package/templates/commands/workflow.md +0 -12
@@ -2,23 +2,32 @@
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: 'MD-first - MD files are source of truth'
5
+ architecture: 'Write-Through (JSON MD Events)'
6
+ storage-layer: true
7
+ source-of-truth: 'storage/state.json'
8
+ claude-context: 'context/now.md'
9
+ backend-sync: 'sync/pending.json'
6
10
  ---
7
11
 
8
12
  # /p:now - Current Task with Session Tracking
9
13
 
10
- ## Architecture: MD-First
14
+ ## Architecture: Write-Through Pattern
11
15
 
12
- **Source of Truth**: `core/now.md`
16
+ ```
17
+ User Action → Storage (JSON) → Context (MD) → Sync Events
18
+ ```
13
19
 
14
- MD files are the source of truth. Write directly to MD files.
20
+ **Source of Truth**: `storage/state.json`
21
+ **Claude Context**: `context/now.md` (generated)
22
+ **Backend Sync**: `sync/pending.json` (events)
15
23
 
16
24
  ## Context Variables
17
25
  - `{projectId}`: From `.prjct/prjct.config.json`
18
26
  - `{globalPath}`: `~/.prjct-cli/projects/{projectId}`
19
- - `{nowPath}`: `{globalPath}/core/now.md`
20
- - `{sessionPath}`: `{globalPath}/sessions/current.json`
21
- - `{memoryPath}`: `{globalPath}/memory/context.jsonl`
27
+ - `{statePath}`: `{globalPath}/storage/state.json`
28
+ - `{nowContextPath}`: `{globalPath}/context/now.md`
29
+ - `{syncPath}`: `{globalPath}/sync/pending.json`
30
+ - `{memoryPath}`: `{globalPath}/memory/events.jsonl`
22
31
  - `{task}`: User-provided task (optional)
23
32
  - `{estimate}`: User-provided time estimate (optional, e.g., "2h", "30m", "1d")
24
33
 
@@ -35,6 +44,48 @@ If no estimate provided, gently remind:
35
44
  💡 Tip: Add estimate next time with /p:now "task" 2h
36
45
  ```
37
46
 
47
+ ## Agent Detection (Optional)
48
+
49
+ When starting a task, auto-detect the best agent based on keywords:
50
+
51
+ | Keywords | Agent | Domain |
52
+ |----------|-------|--------|
53
+ | UI, frontend, React, component, CSS, style | `fe` | Frontend |
54
+ | API, backend, database, server, endpoint | `be` | Backend |
55
+ | design, UX, layout, wireframe | `ux` | UX Design |
56
+ | test, QA, bug, coverage, spec | `qa` | Testing |
57
+ | docs, README, documentation | `docs` | Documentation |
58
+ | (default) | `general` | General |
59
+
60
+ **Usage**: Agent is logged for analytics but doesn't affect workflow.
61
+
62
+ ## Step 0: Detect Abandoned Sessions (BEFORE anything else)
63
+
64
+ READ: `{statePath}` (`storage/state.json`)
65
+
66
+ IF file exists AND has `currentTask`:
67
+ SET: {existingTask} = currentTask object
68
+ SET: {lastActivity} = existingTask.startedAt or last timeline entry
69
+ SET: {hoursAgo} = hours between {lastActivity} and now
70
+
71
+ IF {hoursAgo} >= 8: // Session considered abandoned after 8 hours
72
+ OUTPUT:
73
+ ```
74
+ ⚠️ Found abandoned session from {hoursAgo}h ago
75
+
76
+ Task: {existingTask.description}
77
+ Session: {existingTask.sessionId}
78
+ Started: {existingTask.startedAt}
79
+
80
+ Options:
81
+ 1. Resume previous task → /p:resume
82
+ 2. Close previous as partial → /p:recover close
83
+ 3. View full context → /p:recover
84
+
85
+ Choose an option before starting a new task.
86
+ ```
87
+ STOP
88
+
38
89
  ## Step 1: Read Config
39
90
 
40
91
  READ: `.prjct/prjct.config.json`
@@ -46,46 +97,36 @@ IF file not found:
46
97
 
47
98
  ## Step 2: Check Current State
48
99
 
49
- ### Read now.md (source of truth)
50
- READ: `{nowPath}`
51
-
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}
58
-
59
- ### Check for active session (for detailed tracking)
60
- READ: `{sessionPath}`
100
+ ### Read state.json (source of truth)
101
+ READ: `{statePath}`
61
102
 
62
103
  IF file exists:
63
- PARSE as JSON
64
- EXTRACT: {session.task}, {session.status}, {session.startedAt}, {session.duration}
104
+ PARSE JSON
105
+ EXTRACT: {currentTask}, {pausedTask} if present
65
106
 
66
107
  ## Step 3: Handle Cases
67
108
 
68
109
  ### Case A: No task provided - Show current
69
110
  IF {task} is empty OR not provided:
70
- IF {currentTask} exists AND {status} == "active":
71
- CALCULATE: {elapsed} = time since {startedAt}
111
+ IF {currentTask} exists AND {currentTask.status} == "active":
112
+ CALCULATE: {elapsed} = time since {currentTask.startedAt}
72
113
  OUTPUT:
73
114
  ```
74
- 🎯 {currentTask}
115
+ 🎯 {currentTask.description}
75
116
 
76
- Session: {sessionId}
77
- Started: {startedAt} ({elapsed} ago)
117
+ Session: {currentTask.sessionId}
118
+ Started: {currentTask.startedAt} ({elapsed} ago)
78
119
  Status: active
79
120
 
80
121
  /p:done to complete | /p:pause to pause
81
122
  ```
82
123
  STOP
83
- ELSE IF {currentTask} exists AND {status} == "paused":
124
+ ELSE IF {pausedTask} exists:
84
125
  OUTPUT:
85
126
  ```
86
- ⏸️ Paused: {currentTask}
127
+ ⏸️ Paused: {pausedTask.description}
87
128
 
88
- Duration so far: {duration}
129
+ Duration so far: {pausedTask.duration}
89
130
 
90
131
  /p:resume to continue | /p:done to complete
91
132
  ```
@@ -97,31 +138,54 @@ IF {task} is empty OR not provided:
97
138
  ### Case B: Task provided - Create/Update session
98
139
  IF {task} is provided:
99
140
 
100
- ## Check for existing active session
101
- IF {status} == "active" AND {currentTask} != {task}:
102
- OUTPUT:
103
- ```
104
- ⚠️ Already working on: {currentTask}
141
+ ## Check for existing active task
142
+ IF {currentTask} exists AND {currentTask.status} == "active":
143
+ IF {currentTask.description} != {task}:
144
+ OUTPUT:
145
+ ```
146
+ ⚠️ Already working on: {currentTask.description}
105
147
 
106
- Options:
107
- • /p:done - Complete current task first
108
- • /p:pause - Pause and switch
109
- • /p:now (same task) - Continue current
110
- ```
111
- STOP
148
+ Options:
149
+ • /p:done - Complete current task first
150
+ • /p:pause - Pause and switch
151
+ • /p:now (same task) - Continue current
152
+ ```
153
+ STOP
112
154
 
113
155
  ## If same task, just continue
114
- IF {currentTask} == {task}:
156
+ IF {currentTask} AND {currentTask.description} == {task}:
115
157
  OUTPUT: "🎯 Continuing: {task}"
116
158
  STOP
117
159
 
118
- ## Create new session
119
- GENERATE: {sessionId} = "sess_" + 8 random alphanumeric chars
160
+ ## Create new task
161
+ GENERATE: {taskId} = UUID v4
162
+ GENERATE: {sessionId} = UUID v4
120
163
  SET: {startedAt} = GetTimestamp()
121
164
 
122
- ### Write now.md (SOURCE OF TRUTH)
165
+ ## Step 4: Write to Storage (SOURCE OF TRUTH)
166
+
167
+ ### Prepare task object
168
+ ```json
169
+ {
170
+ "id": "{taskId}",
171
+ "description": "{task}",
172
+ "status": "active",
173
+ "startedAt": "{startedAt}",
174
+ "sessionId": "{sessionId}",
175
+ "estimate": "{estimate OR null}",
176
+ "estimateSeconds": {estimateInSeconds OR null}
177
+ }
178
+ ```
179
+
180
+ ### Write state.json
181
+ READ existing `{statePath}` or create empty object
182
+ SET: state.currentTask = new task object
183
+ SET: state.lastUpdated = {startedAt}
184
+ WRITE: `{statePath}`
185
+
186
+ ## Step 5: Generate Context (FOR CLAUDE)
123
187
 
124
- WRITE: `{nowPath}`
188
+ WRITE: `{nowContextPath}`
125
189
 
126
190
  IF {estimate} provided:
127
191
  ```markdown
@@ -144,53 +208,39 @@ IF {task} is provided:
144
208
  Session: {sessionId}
145
209
  ```
146
210
 
147
- ### Create session JSON (for detailed tracking)
148
- WRITE: `{sessionPath}`
149
- Content:
211
+ ## Step 6: Queue Sync Event (FOR BACKEND)
212
+
213
+ READ: `{syncPath}` or create empty array
214
+ APPEND event:
150
215
  ```json
151
216
  {
152
- "id": "{sessionId}",
153
- "projectId": "{projectId}",
154
- "task": "{task}",
155
- "status": "active",
156
- "startedAt": "{startedAt}",
157
- "pausedAt": null,
158
- "completedAt": null,
159
- "duration": 0,
160
- "estimate": "{estimate OR null}",
161
- "estimateSeconds": {estimateInSeconds OR null},
162
- "metrics": {
163
- "filesChanged": 0,
164
- "linesAdded": 0,
165
- "linesRemoved": 0,
166
- "commits": 0,
167
- "snapshots": []
217
+ "type": "task.started",
218
+ "path": ["state"],
219
+ "data": {
220
+ "taskId": "{taskId}",
221
+ "description": "{task}",
222
+ "startedAt": "{startedAt}",
223
+ "sessionId": "{sessionId}"
168
224
  },
169
- "timeline": [
170
- {"type": "start", "at": "{startedAt}"}
171
- ]
225
+ "timestamp": "{startedAt}",
226
+ "projectId": "{projectId}"
172
227
  }
173
228
  ```
229
+ WRITE: `{syncPath}`
174
230
 
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
231
+ ## Step 7: Log to Memory (AUDIT TRAIL)
181
232
 
182
- ### Log to memory
183
233
  APPEND to: `{memoryPath}`
184
234
  Single line (JSONL):
185
235
 
186
236
  IF {estimate} provided:
187
237
  ```json
188
- {"timestamp":"{startedAt}","action":"session_started","sessionId":"{sessionId}","task":"{task}","estimate":"{estimate}","estimateSeconds":{estimateInSeconds}}
238
+ {"timestamp":"{startedAt}","action":"task_started","taskId":"{taskId}","sessionId":"{sessionId}","task":"{task}","estimate":"{estimate}","estimateSeconds":{estimateInSeconds}}
189
239
  ```
190
240
 
191
241
  ELSE:
192
242
  ```json
193
- {"timestamp":"{startedAt}","action":"session_started","sessionId":"{sessionId}","task":"{task}"}
243
+ {"timestamp":"{startedAt}","action":"task_started","taskId":"{taskId}","sessionId":"{sessionId}","task":"{task}"}
194
244
  ```
195
245
 
196
246
  ## Output
@@ -223,9 +273,23 @@ Started: now
223
273
  | Error | Response | Action |
224
274
  |-------|----------|--------|
225
275
  | No project | "No prjct project" | STOP |
226
- | Active session exists | Show options | STOP |
276
+ | Active task exists | Show options | STOP |
227
277
  | Write fails | "Failed to create session" | STOP |
228
278
 
279
+ ## File Structure Reference
280
+
281
+ ```
282
+ ~/.prjct-cli/projects/{projectId}/
283
+ ├── storage/
284
+ │ └── state.json # Source of truth (current + paused tasks)
285
+ ├── context/
286
+ │ └── now.md # Generated for Claude
287
+ ├── sync/
288
+ │ └── pending.json # Events for backend
289
+ └── memory/
290
+ └── events.jsonl # Audit trail
291
+ ```
292
+
229
293
  ## Examples
230
294
 
231
295
  ### Example 1: Show Current Task
@@ -234,7 +298,7 @@ User: /p:now
234
298
  Output:
235
299
  🎯 Implement user authentication
236
300
 
237
- Session: sess_abc12345
301
+ Session: 550e8400-e29b-41d4-a716-446655440000
238
302
  Started: 2 hours ago
239
303
  Status: active
240
304
 
@@ -247,7 +311,7 @@ User: /p:now "Add login form"
247
311
  Output:
248
312
  🎯 Add login form
249
313
 
250
- Session: sess_xyz98765
314
+ Session: 7c9e6679-7425-40de-944b-e07fc1f90ae7
251
315
  Started: now
252
316
 
253
317
  💡 Tip: Add estimate next time with /p:now "task" 2h
@@ -255,20 +319,20 @@ Started: now
255
319
  /p:done when finished | /p:pause to take a break
256
320
  ```
257
321
 
258
- ### Example 2b: Start New Task (with estimate)
322
+ ### Example 3: Start New Task (with estimate)
259
323
  ```
260
324
  User: /p:now "Add login form" 2h
261
325
  Output:
262
326
  🎯 Add login form
263
327
 
264
- Session: sess_xyz98765
328
+ Session: 7c9e6679-7425-40de-944b-e07fc1f90ae7
265
329
  Started: now
266
330
  Estimate: 2h
267
331
 
268
332
  /p:done when finished | /p:pause to take a break
269
333
  ```
270
334
 
271
- ### Example 3: Task Conflict
335
+ ### Example 4: Task Conflict
272
336
  ```
273
337
  User: /p:now "Something else"
274
338
  Output:
@@ -2,21 +2,32 @@
2
2
  allowed-tools: [Read, Write, Bash]
3
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
+ architecture: 'Write-Through (JSON MD Events)'
6
+ storage-layer: true
7
+ source-of-truth: 'storage/state.json'
8
+ claude-context: 'context/now.md'
9
+ backend-sync: 'sync/pending.json'
6
10
  ---
7
11
 
8
12
  # /p:pause - Pause Current Session
9
13
 
10
- ## Architecture: MD-First
14
+ ## Architecture: Write-Through Pattern
11
15
 
12
- **Source of Truth**: `core/now.md`, `sessions/current.json`
16
+ ```
17
+ User Action → Storage (JSON) → Context (MD) → Sync Events
18
+ ```
19
+
20
+ **Source of Truth**: `storage/state.json`
21
+ **Claude Context**: `context/now.md` (generated)
22
+ **Backend Sync**: `sync/pending.json` (events)
13
23
 
14
24
  ## Context Variables
15
25
  - `{projectId}`: From `.prjct/prjct.config.json`
16
26
  - `{globalPath}`: `~/.prjct-cli/projects/{projectId}`
17
- - `{sessionPath}`: `{globalPath}/sessions/current.json`
18
- - `{nowPath}`: `{globalPath}/core/now.md`
19
- - `{memoryPath}`: `{globalPath}/memory/context.jsonl`
27
+ - `{statePath}`: `{globalPath}/storage/state.json`
28
+ - `{nowContextPath}`: `{globalPath}/context/now.md`
29
+ - `{syncPath}`: `{globalPath}/sync/pending.json`
30
+ - `{memoryPath}`: `{globalPath}/memory/events.jsonl`
20
31
  - `{reason}`: User-provided reason (optional)
21
32
 
22
33
  ## Pause Reasons
@@ -48,33 +59,35 @@ IF file not found:
48
59
  OUTPUT: "No prjct project. Run /p:init first."
49
60
  STOP
50
61
 
51
- ## Step 2: Check Session State
62
+ ## Step 2: Check Current State
52
63
 
53
- READ: `{sessionPath}`
64
+ ### Read state.json (source of truth)
65
+ READ: `{statePath}`
54
66
 
55
- IF file not found OR empty:
67
+ IF file not found OR no currentTask:
56
68
  OUTPUT: "⚠️ No active session to pause. Use /p:now to start one."
57
69
  STOP
58
70
 
59
- PARSE as JSON → {session}
71
+ PARSE JSON
72
+ EXTRACT: {currentTask}, {pausedTask}
60
73
 
61
- IF {session.status} == "paused":
62
- CALCULATE: {elapsed} = time since {session.pausedAt}
63
- OUTPUT:
64
- ```
65
- ⏸️ Already paused: {session.task}
74
+ IF {currentTask} is null OR {currentTask.status} != "active":
75
+ IF {pausedTask} exists:
76
+ CALCULATE: {elapsed} = time since {pausedTask.pausedAt}
77
+ OUTPUT:
78
+ ```
79
+ ⏸️ Already paused: {pausedTask.description}
66
80
 
67
- Paused: {elapsed} ago
68
- Duration so far: {session.duration}
69
- Reason: {session.pauseReason}
81
+ Paused: {elapsed} ago
82
+ Duration so far: {pausedTask.duration}
83
+ Reason: {pausedTask.pauseReason}
70
84
 
71
- /p:resume to continue | /p:done to complete
72
- ```
73
- STOP
74
-
75
- IF {session.status} != "active":
76
- OUTPUT: "⚠️ No active session to pause."
77
- STOP
85
+ /p:resume to continue | /p:done to complete
86
+ ```
87
+ STOP
88
+ ELSE:
89
+ OUTPUT: "⚠️ No active session to pause."
90
+ STOP
78
91
 
79
92
  ## Step 3: Get Pause Reason
80
93
 
@@ -89,73 +102,90 @@ IF {reason} == "blocked":
89
102
  ## Step 4: Calculate Duration So Far
90
103
 
91
104
  SET: {now} = GetTimestamp()
92
-
93
- For each event in {session.timeline}:
94
- Track start/resume/pause times
95
- Calculate total active time up to now
96
-
97
- SET: {duration} = total active seconds
105
+ SET: {durationSeconds} = seconds between {currentTask.startedAt} and {now}
98
106
  SET: {durationFormatted} = format as "Xh Ym" or "Xm"
99
107
 
100
- ## Step 5: Update Session
108
+ ## Step 5: Update Storage (SOURCE OF TRUTH)
101
109
 
102
- UPDATE {session}:
110
+ ### Prepare paused task
103
111
  ```json
104
112
  {
105
- "id": "{session.id}",
106
- "projectId": "{session.projectId}",
107
- "task": "{session.task}",
113
+ "id": "{currentTask.id}",
114
+ "description": "{currentTask.description}",
108
115
  "status": "paused",
109
- "startedAt": "{session.startedAt}",
116
+ "startedAt": "{currentTask.startedAt}",
110
117
  "pausedAt": "{now}",
118
+ "sessionId": "{currentTask.sessionId}",
119
+ "duration": {durationSeconds},
111
120
  "pauseReason": "{reason}",
112
121
  "pauseNote": "{blockerNote}",
113
- "completedAt": null,
114
- "duration": {duration},
115
- "metrics": {session.metrics},
116
- "timeline": [
117
- ...{session.timeline},
118
- {"type": "pause", "at": "{now}", "reason": "{reason}", "note": "{blockerNote}"}
119
- ]
122
+ "estimate": "{currentTask.estimate}",
123
+ "estimateSeconds": {currentTask.estimateSeconds}
120
124
  }
121
125
  ```
122
126
 
123
- WRITE: `{sessionPath}`
124
- Content: Updated session JSON
127
+ ### Update state.json
128
+ READ: `{statePath}`
129
+ SET: state.pausedTask = paused task object
130
+ SET: state.currentTask = null
131
+ SET: state.lastUpdated = {now}
132
+ WRITE: `{statePath}`
133
+
134
+ ## Step 6: Generate Context (FOR CLAUDE)
125
135
 
126
- ## Step 6: Update now.md (SOURCE OF TRUTH)
136
+ WRITE: `{nowContextPath}`
127
137
 
128
- WRITE: `{nowPath}`
129
- Content:
130
138
  ```markdown
131
139
  # NOW
132
140
 
133
- ⏸️ **{session.task}** (paused)
141
+ ⏸️ **{currentTask.description}** (paused)
134
142
 
135
- Started: {session.startedAt}
143
+ Started: {currentTask.startedAt}
136
144
  Paused: {now}
137
145
  Duration: {durationFormatted}
138
146
  Reason: {reason}
139
- Session: {session.id}
147
+ Session: {currentTask.sessionId}
140
148
  {IF blockerNote: Note: {blockerNote}}
141
149
  ```
142
150
 
143
- ## Step 7: Log to Memory
151
+ ## Step 7: Queue Sync Event (FOR BACKEND)
152
+
153
+ READ: `{syncPath}` or create empty array
154
+ APPEND event:
155
+ ```json
156
+ {
157
+ "type": "task.paused",
158
+ "path": ["state"],
159
+ "data": {
160
+ "taskId": "{currentTask.id}",
161
+ "description": "{currentTask.description}",
162
+ "pausedAt": "{now}",
163
+ "duration": {durationSeconds},
164
+ "reason": "{reason}",
165
+ "note": "{blockerNote}"
166
+ },
167
+ "timestamp": "{now}",
168
+ "projectId": "{projectId}"
169
+ }
170
+ ```
171
+ WRITE: `{syncPath}`
172
+
173
+ ## Step 8: Log to Memory (AUDIT TRAIL)
144
174
 
145
175
  APPEND to: `{memoryPath}`
146
176
 
147
177
  Single line (JSONL):
148
178
  ```json
149
- {"timestamp":"{now}","action":"session_paused","sessionId":"{session.id}","task":"{session.task}","duration":{duration},"reason":"{reason}","note":"{blockerNote}"}
179
+ {"timestamp":"{now}","action":"task_paused","taskId":"{currentTask.id}","sessionId":"{currentTask.sessionId}","task":"{currentTask.description}","duration":{durationSeconds},"reason":"{reason}","note":"{blockerNote}"}
150
180
  ```
151
181
 
152
182
  ## Output
153
183
 
154
184
  SUCCESS:
155
185
  ```
156
- ⏸️ Paused: {session.task}
186
+ ⏸️ Paused: {currentTask.description}
157
187
 
158
- Session: {session.id}
188
+ Session: {currentTask.sessionId}
159
189
  Active time: {durationFormatted}
160
190
  Reason: {reason}
161
191
  {IF blockerNote: Note: {blockerNote}}
@@ -186,7 +216,7 @@ Next:
186
216
  ```
187
217
  ⏸️ Paused: implement auth
188
218
 
189
- Session: sess_abc12345
219
+ Session: 550e8400-e29b-41d4-a716-446655440000
190
220
  Active time: 2h 30m
191
221
  Reason: blocked
192
222
  Note: Waiting for API credentials from vendor
@@ -203,7 +233,7 @@ Next:
203
233
  ```
204
234
  ⏸️ Paused: implement auth
205
235
 
206
- Session: sess_abc12345
236
+ Session: 550e8400-e29b-41d4-a716-446655440000
207
237
  Active time: 2h 30m
208
238
  Reason: break
209
239
 
@@ -218,25 +248,10 @@ Next:
218
248
  ```
219
249
  ⏸️ Paused: implement auth
220
250
 
221
- Session: sess_abc12345
251
+ Session: 550e8400-e29b-41d4-a716-446655440000
222
252
  Active time: 2h 30m
223
253
  Reason: switch
224
254
 
225
255
  Next:
226
256
  • /p:now <task> - Start the urgent task
227
257
  ```
228
-
229
- ### Example 4: No Reason (Interactive)
230
- **Input:** `/p:pause`
231
-
232
- **Output:**
233
- ```
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]:
242
- ```
@@ -2,6 +2,8 @@
2
2
  allowed-tools: [Read, Write, Bash]
3
3
  description: 'Redo previously undone changes'
4
4
  timestamp-rule: 'GetTimestamp() for ALL timestamps'
5
+ architecture: 'Write-Through (JSON → MD → Events)'
6
+ storage-layer: true
5
7
  ---
6
8
 
7
9
  # /p:redo - Redo Previously Undone Snapshot
@@ -13,7 +15,7 @@ Restores a previously undone snapshot. Only works if you have recently used /p:u
13
15
  - `{projectId}`: From `.prjct/prjct.config.json`
14
16
  - `{globalPath}`: `~/.prjct-cli/projects/{projectId}`
15
17
  - `{snapshotDir}`: `{globalPath}/snapshots`
16
- - `{memoryPath}`: `{globalPath}/memory/context.jsonl`
18
+ - `{memoryPath}`: `{globalPath}/memory/events.jsonl`
17
19
  - `{redoStackPath}`: `{snapshotDir}/redo-stack.json`
18
20
 
19
21
  ## Step 1: Read Config
@@ -30,14 +32,14 @@ IF file not found:
30
32
  READ: `{redoStackPath}`
31
33
 
32
34
  IF file not found OR empty OR equals "[]":
33
- OUTPUT: "⚠️ Nothing to redo. Use /p:undo first."
35
+ OUTPUT: "Nothing to redo. Use /p:undo first."
34
36
  STOP
35
37
 
36
38
  PARSE as JSON array
37
39
  GET last item as {redoSnapshot}
38
40
 
39
41
  IF array is empty:
40
- OUTPUT: "⚠️ Nothing to redo. Use /p:undo first."
42
+ OUTPUT: "Nothing to redo. Use /p:undo first."
41
43
  STOP
42
44
 
43
45
  EXTRACT from {redoSnapshot}:
@@ -131,7 +133,7 @@ Files affected: 5
131
133
 
132
134
  ### Example 2: Nothing to Redo
133
135
  ```
134
- ⚠️ Nothing to redo. Use /p:undo first.
136
+ Nothing to redo. Use /p:undo first.
135
137
  ```
136
138
 
137
139
  ## Notes