prjct-cli 0.13.3 → 0.15.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 (193) hide show
  1. package/CHANGELOG.md +106 -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/ship.md +103 -231
  160. package/templates/commands/spec.md +98 -8
  161. package/templates/commands/suggest.md +22 -2
  162. package/templates/commands/sync.md +192 -203
  163. package/templates/commands/undo.md +6 -4
  164. package/core/data/agents-manager.ts +0 -76
  165. package/core/data/analysis-manager.ts +0 -83
  166. package/core/data/base-manager.ts +0 -156
  167. package/core/data/ideas-manager.ts +0 -81
  168. package/core/data/outcomes-manager.ts +0 -96
  169. package/core/data/project-manager.ts +0 -75
  170. package/core/data/roadmap-manager.ts +0 -118
  171. package/core/data/shipped-manager.ts +0 -65
  172. package/core/data/state-manager.ts +0 -214
  173. package/core/state/index.ts +0 -25
  174. package/core/state/manager.ts +0 -376
  175. package/core/state/types.ts +0 -185
  176. package/core/utils/project-capabilities.ts +0 -156
  177. package/core/view-generator.ts +0 -536
  178. package/packages/web/app/project/[id]/stats/loading.tsx +0 -43
  179. package/packages/web/app/project/[id]/stats/page.tsx +0 -253
  180. package/templates/agent-assignment.md +0 -72
  181. package/templates/analysis/project-analysis.md +0 -78
  182. package/templates/checklists/accessibility.md +0 -33
  183. package/templates/commands/build.md +0 -17
  184. package/templates/commands/decision.md +0 -226
  185. package/templates/commands/fix.md +0 -79
  186. package/templates/commands/help.md +0 -61
  187. package/templates/commands/progress.md +0 -14
  188. package/templates/commands/recap.md +0 -14
  189. package/templates/commands/roadmap.md +0 -52
  190. package/templates/commands/status.md +0 -17
  191. package/templates/commands/task.md +0 -63
  192. package/templates/commands/work.md +0 -44
  193. package/templates/commands/workflow.md +0 -12
@@ -2,16 +2,32 @@
2
2
  allowed-tools: [Read, Write, Bash]
3
3
  description: 'Resume paused session'
4
4
  timestamp-rule: 'GetTimestamp() for all timestamps'
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'
5
10
  ---
6
11
 
7
12
  # /p:resume - Resume Paused Session
8
13
 
14
+ ## Architecture: Write-Through Pattern
15
+
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)
23
+
9
24
  ## Context Variables
10
25
  - `{projectId}`: From `.prjct/prjct.config.json`
11
26
  - `{globalPath}`: `~/.prjct-cli/projects/{projectId}`
12
- - `{sessionPath}`: `{globalPath}/sessions/current.json`
13
- - `{nowPath}`: `{globalPath}/core/now.md`
14
- - `{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`
15
31
 
16
32
  ## Step 1: Read Config
17
33
 
@@ -22,11 +38,12 @@ IF file not found:
22
38
  OUTPUT: "No prjct project. Run /p:init first."
23
39
  STOP
24
40
 
25
- ## Step 2: Check Session State
41
+ ## Step 2: Check Current State
26
42
 
27
- READ: `{sessionPath}`
43
+ ### Read state.json (source of truth)
44
+ READ: `{statePath}`
28
45
 
29
- IF file not found OR empty:
46
+ IF file not found:
30
47
  OUTPUT:
31
48
  ```
32
49
  ⚠️ No paused session to resume.
@@ -36,97 +53,115 @@ IF file not found OR empty:
36
53
  ```
37
54
  STOP
38
55
 
39
- PARSE as JSON → {session}
56
+ PARSE JSON
57
+ EXTRACT: {currentTask}, {pausedTask}
40
58
 
41
- IF {session.status} == "active":
42
- CALCULATE: {elapsed} = time since last start/resume
59
+ IF {currentTask} exists AND {currentTask.status} == "active":
60
+ CALCULATE: {elapsed} = time since last start
43
61
  OUTPUT:
44
62
  ```
45
- ▶️ Already active: {session.task}
63
+ ▶️ Already active: {currentTask.description}
46
64
 
47
- Session: {session.id}
65
+ Session: {currentTask.sessionId}
48
66
  Working for: {elapsed}
49
67
 
50
68
  /p:done to complete | /p:pause to pause
51
69
  ```
52
70
  STOP
53
71
 
54
- IF {session.status} == "completed":
72
+ IF {pausedTask} is null:
55
73
  OUTPUT:
56
74
  ```
57
- ⚠️ Session already completed.
75
+ ⚠️ No paused session to resume.
58
76
 
59
77
  Start a new task:
60
78
  • /p:now <task>
61
79
  ```
62
80
  STOP
63
81
 
64
- IF {session.status} != "paused":
65
- OUTPUT: "⚠️ No paused session to resume."
66
- STOP
67
-
68
82
  ## Step 3: Calculate Pause Duration
69
83
 
70
84
  SET: {now} = GetTimestamp()
71
- SET: {pauseDuration} = time since {session.pausedAt}
85
+ SET: {pauseDurationSeconds} = seconds between {pausedTask.pausedAt} and {now}
72
86
  SET: {pauseFormatted} = format as "Xh Ym" or "Xm"
73
87
 
74
- ## Step 4: Update Session
88
+ ## Step 4: Update Storage (SOURCE OF TRUTH)
75
89
 
76
- UPDATE {session}:
90
+ ### Prepare resumed task
77
91
  ```json
78
92
  {
79
- "id": "{session.id}",
80
- "projectId": "{session.projectId}",
81
- "task": "{session.task}",
93
+ "id": "{pausedTask.id}",
94
+ "description": "{pausedTask.description}",
82
95
  "status": "active",
83
- "startedAt": "{session.startedAt}",
84
- "pausedAt": null,
85
- "completedAt": null,
86
- "duration": {session.duration},
87
- "metrics": {session.metrics},
88
- "timeline": [
89
- ...{session.timeline},
90
- {"type": "resume", "at": "{now}"}
91
- ]
96
+ "startedAt": "{pausedTask.startedAt}",
97
+ "resumedAt": "{now}",
98
+ "sessionId": "{pausedTask.sessionId}",
99
+ "duration": {pausedTask.duration},
100
+ "estimate": "{pausedTask.estimate}",
101
+ "estimateSeconds": {pausedTask.estimateSeconds}
92
102
  }
93
103
  ```
94
104
 
95
- WRITE: `{sessionPath}`
96
- Content: Updated session JSON
105
+ ### Update state.json
106
+ READ: `{statePath}`
107
+ SET: state.currentTask = resumed task object
108
+ SET: state.pausedTask = null
109
+ SET: state.lastUpdated = {now}
110
+ WRITE: `{statePath}`
97
111
 
98
- ## Step 5: Update Legacy now.md
112
+ ## Step 5: Generate Context (FOR CLAUDE)
113
+
114
+ WRITE: `{nowContextPath}`
99
115
 
100
- WRITE: `{nowPath}`
101
- Content:
102
116
  ```markdown
103
117
  # NOW
104
118
 
105
- **{session.task}**
119
+ **{pausedTask.description}**
106
120
 
107
- Started: {session.startedAt}
121
+ Started: {pausedTask.startedAt}
108
122
  Resumed: {now}
109
- Session: {session.id}
123
+ Session: {pausedTask.sessionId}
124
+ {IF pausedTask.estimate: Estimate: {pausedTask.estimate}}
125
+ ```
126
+
127
+ ## Step 6: Queue Sync Event (FOR BACKEND)
128
+
129
+ READ: `{syncPath}` or create empty array
130
+ APPEND event:
131
+ ```json
132
+ {
133
+ "type": "task.resumed",
134
+ "path": ["state"],
135
+ "data": {
136
+ "taskId": "{pausedTask.id}",
137
+ "description": "{pausedTask.description}",
138
+ "resumedAt": "{now}",
139
+ "pauseDuration": {pauseDurationSeconds}
140
+ },
141
+ "timestamp": "{now}",
142
+ "projectId": "{projectId}"
143
+ }
110
144
  ```
145
+ WRITE: `{syncPath}`
111
146
 
112
- ## Step 6: Log to Memory
147
+ ## Step 7: Log to Memory (AUDIT TRAIL)
113
148
 
114
149
  APPEND to: `{memoryPath}`
115
150
 
116
151
  Single line (JSONL):
117
152
  ```json
118
- {"timestamp":"{now}","action":"session_resumed","sessionId":"{session.id}","task":"{session.task}","pauseDuration":{pauseDurationSeconds}}
153
+ {"timestamp":"{now}","action":"task_resumed","taskId":"{pausedTask.id}","sessionId":"{pausedTask.sessionId}","task":"{pausedTask.description}","pauseDuration":{pauseDurationSeconds}}
119
154
  ```
120
155
 
121
156
  ## Output
122
157
 
123
158
  SUCCESS:
124
159
  ```
125
- ▶️ Resumed: {session.task}
160
+ ▶️ Resumed: {pausedTask.description}
126
161
 
127
- Session: {session.id}
162
+ Session: {pausedTask.sessionId}
128
163
  Was paused: {pauseFormatted}
129
- Total active: {session.duration} (before this stretch)
164
+ Total active: {pausedTask.duration} (before this stretch)
130
165
 
131
166
  /p:done when finished | /p:pause for another break
132
167
  ```
@@ -136,26 +171,24 @@ Total active: {session.duration} (before this stretch)
136
171
  | Error | Response | Action |
137
172
  |-------|----------|--------|
138
173
  | No project | "No prjct project" | STOP |
139
- | No session | "No paused session" | STOP |
174
+ | No paused task | "No paused session" | STOP |
140
175
  | Already active | Show active state | STOP |
141
- | Already completed | Suggest /p:now | STOP |
142
176
  | Write fails | Log warning | CONTINUE |
143
177
 
144
178
  ## Examples
145
179
 
146
180
  ### Example 1: Resume Paused Session
147
- **Session:**
181
+ **State:**
148
182
  ```json
149
183
  {
150
- "id": "sess_abc12345",
151
- "task": "implement auth",
152
- "status": "paused",
153
- "pausedAt": "2025-12-07T12:30:00.000Z",
154
- "duration": 9000,
155
- "timeline": [
156
- {"type": "start", "at": "2025-12-07T10:00:00.000Z"},
157
- {"type": "pause", "at": "2025-12-07T12:30:00.000Z"}
158
- ]
184
+ "currentTask": null,
185
+ "pausedTask": {
186
+ "id": "550e8400-e29b-41d4-a716-446655440000",
187
+ "description": "implement auth",
188
+ "status": "paused",
189
+ "pausedAt": "2025-12-07T12:30:00.000Z",
190
+ "duration": 9000
191
+ }
159
192
  }
160
193
  ```
161
194
 
@@ -165,7 +198,7 @@ Total active: {session.duration} (before this stretch)
165
198
  ```
166
199
  ▶️ Resumed: implement auth
167
200
 
168
- Session: sess_abc12345
201
+ Session: 550e8400-e29b-41d4-a716-446655440000
169
202
  Was paused: 1h 30m
170
203
  Total active: 2h 30m (before this stretch)
171
204
 
@@ -177,7 +210,7 @@ Total active: 2h 30m (before this stretch)
177
210
  ```
178
211
  ▶️ Already active: implement auth
179
212
 
180
- Session: sess_abc12345
213
+ Session: 550e8400-e29b-41d4-a716-446655440000
181
214
  Working for: 45m
182
215
 
183
216
  /p:done to complete | /p:pause to pause
@@ -199,3 +232,52 @@ Detect intent for resume:
199
232
  - "p. continue" → Resume paused session
200
233
  - "p. back to work" → Resume paused session
201
234
  - "p. unpause" → Resume paused session
235
+ - "p. recover" → Recovery mode (abandoned session)
236
+
237
+ ## Recovery Mode (Abandoned Sessions)
238
+
239
+ When called as `/p:resume --recover` OR when detecting sessions older than 8 hours:
240
+
241
+ ### Detection
242
+ IF {currentTask} exists AND hours since {lastActivity} >= 8:
243
+ TRIGGER: Recovery mode
244
+
245
+ ### Recovery Options
246
+
247
+ OUTPUT:
248
+ ```
249
+ 🔄 Found abandoned session
250
+
251
+ Task: {task.description}
252
+ Session: {task.sessionId}
253
+ Started: {task.startedAt}
254
+ Last activity: {hoursAgo}h ago
255
+
256
+ 📝 Original prompt (if saved):
257
+ ┌────────────────────────────────────────
258
+ │ {task.context.prompt}
259
+ └────────────────────────────────────────
260
+
261
+ Options:
262
+ 1. ▶️ Resume - Continue this session
263
+ 2. ✅ Close - Mark as partial completion (counts in metrics)
264
+ 3. 🗑️ Discard - Remove without logging
265
+ 4. ⏸️ Save - Archive for later reference
266
+
267
+ Choose [1-4]:
268
+ ```
269
+
270
+ ### Choice Handling
271
+
272
+ | Choice | Action | Storage Update |
273
+ |--------|--------|----------------|
274
+ | 1. Resume | Continue session | `status: active`, `resumedAt: now` |
275
+ | 2. Close | Mark partial completion | Log to sessions, clear task |
276
+ | 3. Discard | Remove without metrics | Clear task, audit log only |
277
+ | 4. Save | Archive for later | `savedTask: {...}`, clear current |
278
+
279
+ ### Events Logged
280
+
281
+ ```json
282
+ {"type": "session.recovered", "gapHours": {hoursAgo}, "choice": "{choice}"}
283
+ ```