@litmers/cursorflow-orchestrator 0.1.20 → 0.1.26

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 (224) hide show
  1. package/CHANGELOG.md +9 -0
  2. package/commands/cursorflow-clean.md +19 -0
  3. package/commands/cursorflow-runs.md +59 -0
  4. package/commands/cursorflow-stop.md +55 -0
  5. package/dist/cli/clean.js +171 -0
  6. package/dist/cli/clean.js.map +1 -1
  7. package/dist/cli/index.js +7 -0
  8. package/dist/cli/index.js.map +1 -1
  9. package/dist/cli/init.js +1 -1
  10. package/dist/cli/init.js.map +1 -1
  11. package/dist/cli/logs.js +83 -42
  12. package/dist/cli/logs.js.map +1 -1
  13. package/dist/cli/monitor.d.ts +7 -0
  14. package/dist/cli/monitor.js +1007 -189
  15. package/dist/cli/monitor.js.map +1 -1
  16. package/dist/cli/prepare.js +4 -3
  17. package/dist/cli/prepare.js.map +1 -1
  18. package/dist/cli/resume.js +188 -236
  19. package/dist/cli/resume.js.map +1 -1
  20. package/dist/cli/run.js +8 -3
  21. package/dist/cli/run.js.map +1 -1
  22. package/dist/cli/runs.d.ts +5 -0
  23. package/dist/cli/runs.js +214 -0
  24. package/dist/cli/runs.js.map +1 -0
  25. package/dist/cli/setup-commands.js +0 -0
  26. package/dist/cli/signal.js +1 -1
  27. package/dist/cli/signal.js.map +1 -1
  28. package/dist/cli/stop.d.ts +5 -0
  29. package/dist/cli/stop.js +215 -0
  30. package/dist/cli/stop.js.map +1 -0
  31. package/dist/cli/tasks.d.ts +10 -0
  32. package/dist/cli/tasks.js +165 -0
  33. package/dist/cli/tasks.js.map +1 -0
  34. package/dist/core/auto-recovery.d.ts +212 -0
  35. package/dist/core/auto-recovery.js +737 -0
  36. package/dist/core/auto-recovery.js.map +1 -0
  37. package/dist/core/failure-policy.d.ts +156 -0
  38. package/dist/core/failure-policy.js +488 -0
  39. package/dist/core/failure-policy.js.map +1 -0
  40. package/dist/core/orchestrator.d.ts +15 -2
  41. package/dist/core/orchestrator.js +392 -15
  42. package/dist/core/orchestrator.js.map +1 -1
  43. package/dist/core/reviewer.d.ts +2 -0
  44. package/dist/core/reviewer.js +2 -0
  45. package/dist/core/reviewer.js.map +1 -1
  46. package/dist/core/runner.d.ts +33 -10
  47. package/dist/core/runner.js +321 -146
  48. package/dist/core/runner.js.map +1 -1
  49. package/dist/services/logging/buffer.d.ts +67 -0
  50. package/dist/services/logging/buffer.js +309 -0
  51. package/dist/services/logging/buffer.js.map +1 -0
  52. package/dist/services/logging/console.d.ts +89 -0
  53. package/dist/services/logging/console.js +169 -0
  54. package/dist/services/logging/console.js.map +1 -0
  55. package/dist/services/logging/file-writer.d.ts +71 -0
  56. package/dist/services/logging/file-writer.js +516 -0
  57. package/dist/services/logging/file-writer.js.map +1 -0
  58. package/dist/services/logging/formatter.d.ts +39 -0
  59. package/dist/services/logging/formatter.js +227 -0
  60. package/dist/services/logging/formatter.js.map +1 -0
  61. package/dist/services/logging/index.d.ts +11 -0
  62. package/dist/services/logging/index.js +30 -0
  63. package/dist/services/logging/index.js.map +1 -0
  64. package/dist/services/logging/parser.d.ts +31 -0
  65. package/dist/services/logging/parser.js +222 -0
  66. package/dist/services/logging/parser.js.map +1 -0
  67. package/dist/services/process/index.d.ts +59 -0
  68. package/dist/services/process/index.js +257 -0
  69. package/dist/services/process/index.js.map +1 -0
  70. package/dist/types/agent.d.ts +20 -0
  71. package/dist/types/agent.js +6 -0
  72. package/dist/types/agent.js.map +1 -0
  73. package/dist/types/config.d.ts +65 -0
  74. package/dist/types/config.js +6 -0
  75. package/dist/types/config.js.map +1 -0
  76. package/dist/types/events.d.ts +125 -0
  77. package/dist/types/events.js +6 -0
  78. package/dist/types/events.js.map +1 -0
  79. package/dist/types/index.d.ts +12 -0
  80. package/dist/types/index.js +37 -0
  81. package/dist/types/index.js.map +1 -0
  82. package/dist/types/lane.d.ts +43 -0
  83. package/dist/types/lane.js +6 -0
  84. package/dist/types/lane.js.map +1 -0
  85. package/dist/types/logging.d.ts +71 -0
  86. package/dist/types/logging.js +16 -0
  87. package/dist/types/logging.js.map +1 -0
  88. package/dist/types/review.d.ts +17 -0
  89. package/dist/types/review.js +6 -0
  90. package/dist/types/review.js.map +1 -0
  91. package/dist/types/run.d.ts +32 -0
  92. package/dist/types/run.js +6 -0
  93. package/dist/types/run.js.map +1 -0
  94. package/dist/types/task.d.ts +71 -0
  95. package/dist/types/task.js +6 -0
  96. package/dist/types/task.js.map +1 -0
  97. package/dist/ui/components.d.ts +134 -0
  98. package/dist/ui/components.js +389 -0
  99. package/dist/ui/components.js.map +1 -0
  100. package/dist/ui/log-viewer.d.ts +49 -0
  101. package/dist/ui/log-viewer.js +449 -0
  102. package/dist/ui/log-viewer.js.map +1 -0
  103. package/dist/utils/checkpoint.d.ts +87 -0
  104. package/dist/utils/checkpoint.js +317 -0
  105. package/dist/utils/checkpoint.js.map +1 -0
  106. package/dist/utils/config.d.ts +4 -0
  107. package/dist/utils/config.js +11 -2
  108. package/dist/utils/config.js.map +1 -1
  109. package/dist/utils/cursor-agent.js.map +1 -1
  110. package/dist/utils/dependency.d.ts +74 -0
  111. package/dist/utils/dependency.js +420 -0
  112. package/dist/utils/dependency.js.map +1 -0
  113. package/dist/utils/doctor.js +10 -5
  114. package/dist/utils/doctor.js.map +1 -1
  115. package/dist/utils/enhanced-logger.d.ts +10 -33
  116. package/dist/utils/enhanced-logger.js +94 -9
  117. package/dist/utils/enhanced-logger.js.map +1 -1
  118. package/dist/utils/git.d.ts +121 -0
  119. package/dist/utils/git.js +322 -2
  120. package/dist/utils/git.js.map +1 -1
  121. package/dist/utils/health.d.ts +91 -0
  122. package/dist/utils/health.js +556 -0
  123. package/dist/utils/health.js.map +1 -0
  124. package/dist/utils/lock.d.ts +95 -0
  125. package/dist/utils/lock.js +332 -0
  126. package/dist/utils/lock.js.map +1 -0
  127. package/dist/utils/log-buffer.d.ts +17 -0
  128. package/dist/utils/log-buffer.js +14 -0
  129. package/dist/utils/log-buffer.js.map +1 -0
  130. package/dist/utils/log-constants.d.ts +23 -0
  131. package/dist/utils/log-constants.js +28 -0
  132. package/dist/utils/log-constants.js.map +1 -0
  133. package/dist/utils/log-formatter.d.ts +9 -0
  134. package/dist/utils/log-formatter.js +113 -70
  135. package/dist/utils/log-formatter.js.map +1 -1
  136. package/dist/utils/log-service.d.ts +19 -0
  137. package/dist/utils/log-service.js +47 -0
  138. package/dist/utils/log-service.js.map +1 -0
  139. package/dist/utils/logger.d.ts +46 -27
  140. package/dist/utils/logger.js +82 -60
  141. package/dist/utils/logger.js.map +1 -1
  142. package/dist/utils/process-manager.d.ts +21 -0
  143. package/dist/utils/process-manager.js +138 -0
  144. package/dist/utils/process-manager.js.map +1 -0
  145. package/dist/utils/retry.d.ts +121 -0
  146. package/dist/utils/retry.js +374 -0
  147. package/dist/utils/retry.js.map +1 -0
  148. package/dist/utils/run-service.d.ts +88 -0
  149. package/dist/utils/run-service.js +412 -0
  150. package/dist/utils/run-service.js.map +1 -0
  151. package/dist/utils/state.d.ts +58 -2
  152. package/dist/utils/state.js +306 -3
  153. package/dist/utils/state.js.map +1 -1
  154. package/dist/utils/task-service.d.ts +82 -0
  155. package/dist/utils/task-service.js +348 -0
  156. package/dist/utils/task-service.js.map +1 -0
  157. package/dist/utils/types.d.ts +2 -272
  158. package/dist/utils/types.js +16 -0
  159. package/dist/utils/types.js.map +1 -1
  160. package/package.json +38 -23
  161. package/scripts/ai-security-check.js +0 -1
  162. package/scripts/local-security-gate.sh +0 -0
  163. package/scripts/monitor-lanes.sh +94 -0
  164. package/scripts/patches/test-cursor-agent.js +0 -1
  165. package/scripts/release.sh +0 -0
  166. package/scripts/setup-security.sh +0 -0
  167. package/scripts/stream-logs.sh +72 -0
  168. package/scripts/verify-and-fix.sh +0 -0
  169. package/src/cli/clean.ts +180 -0
  170. package/src/cli/index.ts +7 -0
  171. package/src/cli/init.ts +1 -1
  172. package/src/cli/logs.ts +79 -42
  173. package/src/cli/monitor.ts +1815 -899
  174. package/src/cli/prepare.ts +4 -3
  175. package/src/cli/resume.ts +220 -277
  176. package/src/cli/run.ts +9 -3
  177. package/src/cli/runs.ts +212 -0
  178. package/src/cli/setup-commands.ts +0 -0
  179. package/src/cli/signal.ts +1 -1
  180. package/src/cli/stop.ts +209 -0
  181. package/src/cli/tasks.ts +154 -0
  182. package/src/core/auto-recovery.ts +909 -0
  183. package/src/core/failure-policy.ts +592 -0
  184. package/src/core/orchestrator.ts +1131 -675
  185. package/src/core/reviewer.ts +4 -0
  186. package/src/core/runner.ts +388 -162
  187. package/src/services/logging/buffer.ts +326 -0
  188. package/src/services/logging/console.ts +193 -0
  189. package/src/services/logging/file-writer.ts +526 -0
  190. package/src/services/logging/formatter.ts +268 -0
  191. package/src/services/logging/index.ts +16 -0
  192. package/src/services/logging/parser.ts +232 -0
  193. package/src/services/process/index.ts +261 -0
  194. package/src/types/agent.ts +24 -0
  195. package/src/types/config.ts +79 -0
  196. package/src/types/events.ts +156 -0
  197. package/src/types/index.ts +29 -0
  198. package/src/types/lane.ts +56 -0
  199. package/src/types/logging.ts +96 -0
  200. package/src/types/review.ts +20 -0
  201. package/src/types/run.ts +37 -0
  202. package/src/types/task.ts +79 -0
  203. package/src/ui/components.ts +430 -0
  204. package/src/ui/log-viewer.ts +485 -0
  205. package/src/utils/checkpoint.ts +374 -0
  206. package/src/utils/config.ts +11 -2
  207. package/src/utils/cursor-agent.ts +1 -1
  208. package/src/utils/dependency.ts +482 -0
  209. package/src/utils/doctor.ts +11 -5
  210. package/src/utils/enhanced-logger.ts +108 -49
  211. package/src/utils/git.ts +374 -2
  212. package/src/utils/health.ts +596 -0
  213. package/src/utils/lock.ts +346 -0
  214. package/src/utils/log-buffer.ts +28 -0
  215. package/src/utils/log-constants.ts +26 -0
  216. package/src/utils/log-formatter.ts +120 -37
  217. package/src/utils/log-service.ts +49 -0
  218. package/src/utils/logger.ts +100 -51
  219. package/src/utils/process-manager.ts +100 -0
  220. package/src/utils/retry.ts +413 -0
  221. package/src/utils/run-service.ts +433 -0
  222. package/src/utils/state.ts +369 -3
  223. package/src/utils/task-service.ts +370 -0
  224. package/src/utils/types.ts +2 -315
@@ -0,0 +1,374 @@
1
+ /**
2
+ * Checkpoint and recovery system for CursorFlow
3
+ */
4
+
5
+ import * as fs from 'fs';
6
+ import * as path from 'path';
7
+ import { safeJoin } from './path';
8
+ import * as git from './git';
9
+ import { LaneState } from './types';
10
+ import { loadState, saveState } from './state';
11
+ import * as logger from './logger';
12
+
13
+ export interface GitState {
14
+ branch: string | null;
15
+ commit: string | null;
16
+ uncommittedChanges: boolean;
17
+ changedFiles: string[];
18
+ }
19
+
20
+ export interface Checkpoint {
21
+ id: string;
22
+ timestamp: number;
23
+ laneName: string;
24
+ laneState: LaneState;
25
+ gitState: GitState | null;
26
+ taskIndex: number;
27
+ description?: string;
28
+ }
29
+
30
+ export interface CheckpointOptions {
31
+ /** Directory to store checkpoints */
32
+ checkpointDir?: string;
33
+ /** Maximum number of checkpoints to keep per lane */
34
+ maxCheckpoints?: number;
35
+ /** Description of the checkpoint */
36
+ description?: string;
37
+ }
38
+
39
+ const DEFAULT_MAX_CHECKPOINTS = 10;
40
+
41
+ /**
42
+ * Get checkpoint directory for a lane
43
+ */
44
+ export function getCheckpointDir(laneDir: string): string {
45
+ return safeJoin(laneDir, 'checkpoints');
46
+ }
47
+
48
+ /**
49
+ * Generate checkpoint ID
50
+ */
51
+ function generateCheckpointId(): string {
52
+ return `cp-${Date.now()}-${Math.random().toString(36).substring(2, 7)}`;
53
+ }
54
+
55
+ /**
56
+ * Create a checkpoint for a lane
57
+ */
58
+ export async function createCheckpoint(
59
+ laneName: string,
60
+ laneDir: string,
61
+ worktreeDir: string | null,
62
+ options: CheckpointOptions = {}
63
+ ): Promise<Checkpoint> {
64
+ const checkpointDir = options.checkpointDir || getCheckpointDir(laneDir);
65
+ const maxCheckpoints = options.maxCheckpoints || DEFAULT_MAX_CHECKPOINTS;
66
+
67
+ // Ensure checkpoint directory exists
68
+ if (!fs.existsSync(checkpointDir)) {
69
+ fs.mkdirSync(checkpointDir, { recursive: true });
70
+ }
71
+
72
+ // Load current lane state
73
+ const statePath = safeJoin(laneDir, 'state.json');
74
+ const laneState = loadState<LaneState>(statePath);
75
+
76
+ if (!laneState) {
77
+ throw new Error(`Cannot create checkpoint: Lane state not found at ${statePath}`);
78
+ }
79
+
80
+ // Get Git state if worktree exists
81
+ let gitState: GitState | null = null;
82
+ if (worktreeDir && fs.existsSync(worktreeDir)) {
83
+ try {
84
+ const branch = git.getCurrentBranch(worktreeDir);
85
+ const commit = git.runGit(['rev-parse', 'HEAD'], { cwd: worktreeDir, silent: true });
86
+ const changedFiles = git.getChangedFiles(worktreeDir);
87
+
88
+ gitState = {
89
+ branch,
90
+ commit,
91
+ uncommittedChanges: changedFiles.length > 0,
92
+ changedFiles: changedFiles.map(f => f.file),
93
+ };
94
+ } catch (e) {
95
+ logger.warn(`Failed to capture Git state for checkpoint: ${e}`);
96
+ }
97
+ }
98
+
99
+ // Create checkpoint
100
+ const checkpoint: Checkpoint = {
101
+ id: generateCheckpointId(),
102
+ timestamp: Date.now(),
103
+ laneName,
104
+ laneState: { ...laneState },
105
+ gitState,
106
+ taskIndex: laneState.currentTaskIndex,
107
+ description: options.description,
108
+ };
109
+
110
+ // Save checkpoint
111
+ const checkpointPath = safeJoin(checkpointDir, `${checkpoint.id}.json`);
112
+ fs.writeFileSync(checkpointPath, JSON.stringify(checkpoint, null, 2), 'utf8');
113
+
114
+ // Cleanup old checkpoints
115
+ await cleanupOldCheckpoints(checkpointDir, maxCheckpoints);
116
+
117
+ logger.info(`Created checkpoint: ${checkpoint.id} (task ${checkpoint.taskIndex})`);
118
+
119
+ return checkpoint;
120
+ }
121
+
122
+ /**
123
+ * List all checkpoints for a lane
124
+ */
125
+ export function listCheckpoints(laneDir: string): Checkpoint[] {
126
+ const checkpointDir = getCheckpointDir(laneDir);
127
+
128
+ if (!fs.existsSync(checkpointDir)) {
129
+ return [];
130
+ }
131
+
132
+ const files = fs.readdirSync(checkpointDir)
133
+ .filter(f => f.startsWith('cp-') && f.endsWith('.json'))
134
+ .sort()
135
+ .reverse(); // Most recent first
136
+
137
+ return files.map(f => {
138
+ try {
139
+ const content = fs.readFileSync(safeJoin(checkpointDir, f), 'utf8');
140
+ return JSON.parse(content) as Checkpoint;
141
+ } catch {
142
+ return null;
143
+ }
144
+ }).filter((cp): cp is Checkpoint => cp !== null);
145
+ }
146
+
147
+ /**
148
+ * Get a specific checkpoint
149
+ */
150
+ export function getCheckpoint(laneDir: string, checkpointId: string): Checkpoint | null {
151
+ const checkpointDir = getCheckpointDir(laneDir);
152
+ const checkpointPath = safeJoin(checkpointDir, `${checkpointId}.json`);
153
+
154
+ if (!fs.existsSync(checkpointPath)) {
155
+ return null;
156
+ }
157
+
158
+ try {
159
+ const content = fs.readFileSync(checkpointPath, 'utf8');
160
+ return JSON.parse(content) as Checkpoint;
161
+ } catch {
162
+ return null;
163
+ }
164
+ }
165
+
166
+ /**
167
+ * Get the latest checkpoint for a lane
168
+ */
169
+ export function getLatestCheckpoint(laneDir: string): Checkpoint | null {
170
+ const checkpoints = listCheckpoints(laneDir);
171
+ return checkpoints.length > 0 ? checkpoints[0]! : null;
172
+ }
173
+
174
+ /**
175
+ * Restore lane state from a checkpoint
176
+ */
177
+ export async function restoreFromCheckpoint(
178
+ checkpoint: Checkpoint,
179
+ laneDir: string,
180
+ options: {
181
+ restoreGitState?: boolean;
182
+ worktreeDir?: string;
183
+ } = {}
184
+ ): Promise<{ success: boolean; warnings: string[] }> {
185
+ const warnings: string[] = [];
186
+
187
+ // Restore lane state
188
+ const statePath = safeJoin(laneDir, 'state.json');
189
+ const restoredState: LaneState = {
190
+ ...checkpoint.laneState,
191
+ status: 'pending', // Reset status for resume
192
+ error: null,
193
+ updatedAt: Date.now(),
194
+ };
195
+ saveState(statePath, restoredState);
196
+
197
+ logger.info(`Restored lane state from checkpoint ${checkpoint.id}`);
198
+
199
+ // Restore Git state if requested
200
+ if (options.restoreGitState && checkpoint.gitState && options.worktreeDir) {
201
+ const worktreeDir = options.worktreeDir;
202
+
203
+ if (!fs.existsSync(worktreeDir)) {
204
+ warnings.push(`Worktree not found: ${worktreeDir}`);
205
+ } else {
206
+ try {
207
+ // Check for uncommitted changes
208
+ if (git.hasUncommittedChanges(worktreeDir)) {
209
+ warnings.push('Worktree has uncommitted changes. Stashing...');
210
+ git.runGit(['stash', 'push', '-m', `Pre-restore checkpoint ${checkpoint.id}`], { cwd: worktreeDir });
211
+ }
212
+
213
+ // Checkout the checkpoint commit if available
214
+ if (checkpoint.gitState.commit) {
215
+ git.runGit(['checkout', checkpoint.gitState.commit], { cwd: worktreeDir, silent: true });
216
+ logger.info(`Restored Git state to commit ${checkpoint.gitState.commit.substring(0, 7)}`);
217
+ }
218
+ } catch (e: any) {
219
+ warnings.push(`Failed to restore Git state: ${e.message}`);
220
+ }
221
+ }
222
+ }
223
+
224
+ return { success: true, warnings };
225
+ }
226
+
227
+ /**
228
+ * Delete a checkpoint
229
+ */
230
+ export function deleteCheckpoint(laneDir: string, checkpointId: string): boolean {
231
+ const checkpointDir = getCheckpointDir(laneDir);
232
+ const checkpointPath = safeJoin(checkpointDir, `${checkpointId}.json`);
233
+
234
+ if (!fs.existsSync(checkpointPath)) {
235
+ return false;
236
+ }
237
+
238
+ try {
239
+ fs.unlinkSync(checkpointPath);
240
+ return true;
241
+ } catch {
242
+ return false;
243
+ }
244
+ }
245
+
246
+ /**
247
+ * Clean up old checkpoints, keeping only the most recent ones
248
+ */
249
+ async function cleanupOldCheckpoints(checkpointDir: string, maxCheckpoints: number): Promise<number> {
250
+ if (!fs.existsSync(checkpointDir)) {
251
+ return 0;
252
+ }
253
+
254
+ const files = fs.readdirSync(checkpointDir)
255
+ .filter(f => f.startsWith('cp-') && f.endsWith('.json'))
256
+ .sort()
257
+ .reverse();
258
+
259
+ let deleted = 0;
260
+ for (let i = maxCheckpoints; i < files.length; i++) {
261
+ try {
262
+ fs.unlinkSync(safeJoin(checkpointDir, files[i]!));
263
+ deleted++;
264
+ } catch {
265
+ // Ignore
266
+ }
267
+ }
268
+
269
+ return deleted;
270
+ }
271
+
272
+ /**
273
+ * Auto-checkpoint decorator - creates checkpoints before critical operations
274
+ */
275
+ export function withAutoCheckpoint<T extends (...args: any[]) => Promise<any>>(
276
+ fn: T,
277
+ options: {
278
+ getLaneDir: (...args: Parameters<T>) => string;
279
+ getLaneName: (...args: Parameters<T>) => string;
280
+ getWorktreeDir?: (...args: Parameters<T>) => string | null;
281
+ description?: string;
282
+ }
283
+ ): T {
284
+ return (async (...args: Parameters<T>): Promise<ReturnType<T>> => {
285
+ const laneDir = options.getLaneDir(...args);
286
+ const laneName = options.getLaneName(...args);
287
+ const worktreeDir = options.getWorktreeDir?.(...args) || null;
288
+
289
+ try {
290
+ await createCheckpoint(laneName, laneDir, worktreeDir, {
291
+ description: options.description || `Before ${fn.name}`,
292
+ });
293
+ } catch (e) {
294
+ logger.warn(`Auto-checkpoint failed: ${e}`);
295
+ }
296
+
297
+ return fn(...args);
298
+ }) as T;
299
+ }
300
+
301
+ /**
302
+ * Find the best checkpoint to recover from after a failure
303
+ */
304
+ export function findRecoveryCheckpoint(
305
+ laneDir: string,
306
+ targetTaskIndex?: number
307
+ ): Checkpoint | null {
308
+ const checkpoints = listCheckpoints(laneDir);
309
+
310
+ if (checkpoints.length === 0) {
311
+ return null;
312
+ }
313
+
314
+ // If target task index is specified, find the checkpoint just before it
315
+ if (targetTaskIndex !== undefined) {
316
+ for (const cp of checkpoints) {
317
+ if (cp.taskIndex <= targetTaskIndex) {
318
+ return cp;
319
+ }
320
+ }
321
+ }
322
+
323
+ // Return the latest checkpoint
324
+ return checkpoints[0]!;
325
+ }
326
+
327
+ /**
328
+ * Checkpoint statistics for monitoring
329
+ */
330
+ export interface CheckpointStats {
331
+ totalCheckpoints: number;
332
+ oldestTimestamp: number | null;
333
+ newestTimestamp: number | null;
334
+ totalSizeBytes: number;
335
+ }
336
+
337
+ /**
338
+ * Get checkpoint statistics for a lane
339
+ */
340
+ export function getCheckpointStats(laneDir: string): CheckpointStats {
341
+ const checkpointDir = getCheckpointDir(laneDir);
342
+
343
+ if (!fs.existsSync(checkpointDir)) {
344
+ return {
345
+ totalCheckpoints: 0,
346
+ oldestTimestamp: null,
347
+ newestTimestamp: null,
348
+ totalSizeBytes: 0,
349
+ };
350
+ }
351
+
352
+ const checkpoints = listCheckpoints(laneDir);
353
+ let totalSize = 0;
354
+
355
+ const files = fs.readdirSync(checkpointDir)
356
+ .filter(f => f.startsWith('cp-') && f.endsWith('.json'));
357
+
358
+ for (const f of files) {
359
+ try {
360
+ const stat = fs.statSync(safeJoin(checkpointDir, f));
361
+ totalSize += stat.size;
362
+ } catch {
363
+ // Ignore
364
+ }
365
+ }
366
+
367
+ return {
368
+ totalCheckpoints: checkpoints.length,
369
+ oldestTimestamp: checkpoints.length > 0 ? checkpoints[checkpoints.length - 1]!.timestamp : null,
370
+ newestTimestamp: checkpoints.length > 0 ? checkpoints[0]!.timestamp : null,
371
+ totalSizeBytes: totalSize,
372
+ };
373
+ }
374
+
@@ -44,9 +44,10 @@ export function loadConfig(projectRoot: string | null = null): CursorFlowConfig
44
44
  // Directories
45
45
  tasksDir: '_cursorflow/tasks',
46
46
  logsDir: '_cursorflow/logs',
47
+ pofDir: '_cursorflow/pof',
47
48
 
48
49
  // Git
49
- baseBranch: 'main',
50
+ // baseBranch is auto-detected from current branch at runtime
50
51
  branchPrefix: 'feature/',
51
52
 
52
53
  // Execution
@@ -125,6 +126,13 @@ export function getLogsDir(config: CursorFlowConfig): string {
125
126
  return safeJoin(config.projectRoot, config.logsDir);
126
127
  }
127
128
 
129
+ /**
130
+ * Get absolute path for POF directory
131
+ */
132
+ export function getPofDir(config: CursorFlowConfig): string {
133
+ return safeJoin(config.projectRoot, config.pofDir);
134
+ }
135
+
128
136
  /**
129
137
  * Validate configuration
130
138
  */
@@ -164,9 +172,10 @@ export function createDefaultConfig(projectRoot: string, force = false): string
164
172
  // Directory configuration
165
173
  tasksDir: '_cursorflow/tasks',
166
174
  logsDir: '_cursorflow/logs',
175
+ pofDir: '_cursorflow/pof',
167
176
 
168
177
  // Git configuration
169
- baseBranch: 'main',
178
+ baseBranch: git.getCurrentBranch() || 'main',
170
179
  branchPrefix: 'feature/',
171
180
 
172
181
  // Execution configuration
@@ -2,7 +2,7 @@
2
2
  * Cursor Agent CLI wrapper and utilities
3
3
  */
4
4
 
5
- import { execSync, spawnSync } from 'child_process';
5
+ import { spawnSync } from 'child_process';
6
6
 
7
7
  /**
8
8
  * Check if cursor-agent CLI is installed