@litmers/cursorflow-orchestrator 0.1.18 → 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.
- package/CHANGELOG.md +25 -0
- package/README.md +25 -7
- package/commands/cursorflow-clean.md +19 -0
- package/commands/cursorflow-runs.md +59 -0
- package/commands/cursorflow-stop.md +55 -0
- package/dist/cli/clean.js +178 -6
- package/dist/cli/clean.js.map +1 -1
- package/dist/cli/index.js +12 -1
- package/dist/cli/index.js.map +1 -1
- package/dist/cli/init.js +8 -7
- package/dist/cli/init.js.map +1 -1
- package/dist/cli/logs.js +126 -77
- package/dist/cli/logs.js.map +1 -1
- package/dist/cli/monitor.d.ts +7 -0
- package/dist/cli/monitor.js +1021 -202
- package/dist/cli/monitor.js.map +1 -1
- package/dist/cli/prepare.js +39 -21
- package/dist/cli/prepare.js.map +1 -1
- package/dist/cli/resume.js +268 -163
- package/dist/cli/resume.js.map +1 -1
- package/dist/cli/run.js +11 -5
- package/dist/cli/run.js.map +1 -1
- package/dist/cli/runs.d.ts +5 -0
- package/dist/cli/runs.js +214 -0
- package/dist/cli/runs.js.map +1 -0
- package/dist/cli/setup-commands.js +0 -0
- package/dist/cli/signal.js +8 -8
- package/dist/cli/signal.js.map +1 -1
- package/dist/cli/stop.d.ts +5 -0
- package/dist/cli/stop.js +215 -0
- package/dist/cli/stop.js.map +1 -0
- package/dist/cli/tasks.d.ts +10 -0
- package/dist/cli/tasks.js +165 -0
- package/dist/cli/tasks.js.map +1 -0
- package/dist/core/auto-recovery.d.ts +212 -0
- package/dist/core/auto-recovery.js +737 -0
- package/dist/core/auto-recovery.js.map +1 -0
- package/dist/core/failure-policy.d.ts +156 -0
- package/dist/core/failure-policy.js +488 -0
- package/dist/core/failure-policy.js.map +1 -0
- package/dist/core/orchestrator.d.ts +16 -2
- package/dist/core/orchestrator.js +439 -105
- package/dist/core/orchestrator.js.map +1 -1
- package/dist/core/reviewer.d.ts +2 -0
- package/dist/core/reviewer.js +2 -0
- package/dist/core/reviewer.js.map +1 -1
- package/dist/core/runner.d.ts +33 -10
- package/dist/core/runner.js +374 -164
- package/dist/core/runner.js.map +1 -1
- package/dist/services/logging/buffer.d.ts +67 -0
- package/dist/services/logging/buffer.js +309 -0
- package/dist/services/logging/buffer.js.map +1 -0
- package/dist/services/logging/console.d.ts +89 -0
- package/dist/services/logging/console.js +169 -0
- package/dist/services/logging/console.js.map +1 -0
- package/dist/services/logging/file-writer.d.ts +71 -0
- package/dist/services/logging/file-writer.js +516 -0
- package/dist/services/logging/file-writer.js.map +1 -0
- package/dist/services/logging/formatter.d.ts +39 -0
- package/dist/services/logging/formatter.js +227 -0
- package/dist/services/logging/formatter.js.map +1 -0
- package/dist/services/logging/index.d.ts +11 -0
- package/dist/services/logging/index.js +30 -0
- package/dist/services/logging/index.js.map +1 -0
- package/dist/services/logging/parser.d.ts +31 -0
- package/dist/services/logging/parser.js +222 -0
- package/dist/services/logging/parser.js.map +1 -0
- package/dist/services/process/index.d.ts +59 -0
- package/dist/services/process/index.js +257 -0
- package/dist/services/process/index.js.map +1 -0
- package/dist/types/agent.d.ts +20 -0
- package/dist/types/agent.js +6 -0
- package/dist/types/agent.js.map +1 -0
- package/dist/types/config.d.ts +65 -0
- package/dist/types/config.js +6 -0
- package/dist/types/config.js.map +1 -0
- package/dist/types/events.d.ts +125 -0
- package/dist/types/events.js +6 -0
- package/dist/types/events.js.map +1 -0
- package/dist/types/index.d.ts +12 -0
- package/dist/types/index.js +37 -0
- package/dist/types/index.js.map +1 -0
- package/dist/types/lane.d.ts +43 -0
- package/dist/types/lane.js +6 -0
- package/dist/types/lane.js.map +1 -0
- package/dist/types/logging.d.ts +71 -0
- package/dist/types/logging.js +16 -0
- package/dist/types/logging.js.map +1 -0
- package/dist/types/review.d.ts +17 -0
- package/dist/types/review.js +6 -0
- package/dist/types/review.js.map +1 -0
- package/dist/types/run.d.ts +32 -0
- package/dist/types/run.js +6 -0
- package/dist/types/run.js.map +1 -0
- package/dist/types/task.d.ts +71 -0
- package/dist/types/task.js +6 -0
- package/dist/types/task.js.map +1 -0
- package/dist/ui/components.d.ts +134 -0
- package/dist/ui/components.js +389 -0
- package/dist/ui/components.js.map +1 -0
- package/dist/ui/log-viewer.d.ts +49 -0
- package/dist/ui/log-viewer.js +449 -0
- package/dist/ui/log-viewer.js.map +1 -0
- package/dist/utils/checkpoint.d.ts +87 -0
- package/dist/utils/checkpoint.js +317 -0
- package/dist/utils/checkpoint.js.map +1 -0
- package/dist/utils/config.d.ts +4 -0
- package/dist/utils/config.js +18 -8
- package/dist/utils/config.js.map +1 -1
- package/dist/utils/cursor-agent.js.map +1 -1
- package/dist/utils/dependency.d.ts +74 -0
- package/dist/utils/dependency.js +420 -0
- package/dist/utils/dependency.js.map +1 -0
- package/dist/utils/doctor.js +17 -11
- package/dist/utils/doctor.js.map +1 -1
- package/dist/utils/enhanced-logger.d.ts +10 -33
- package/dist/utils/enhanced-logger.js +108 -20
- package/dist/utils/enhanced-logger.js.map +1 -1
- package/dist/utils/git.d.ts +121 -0
- package/dist/utils/git.js +484 -11
- package/dist/utils/git.js.map +1 -1
- package/dist/utils/health.d.ts +91 -0
- package/dist/utils/health.js +556 -0
- package/dist/utils/health.js.map +1 -0
- package/dist/utils/lock.d.ts +95 -0
- package/dist/utils/lock.js +332 -0
- package/dist/utils/lock.js.map +1 -0
- package/dist/utils/log-buffer.d.ts +17 -0
- package/dist/utils/log-buffer.js +14 -0
- package/dist/utils/log-buffer.js.map +1 -0
- package/dist/utils/log-constants.d.ts +23 -0
- package/dist/utils/log-constants.js +28 -0
- package/dist/utils/log-constants.js.map +1 -0
- package/dist/utils/log-formatter.d.ts +25 -0
- package/dist/utils/log-formatter.js +237 -0
- package/dist/utils/log-formatter.js.map +1 -0
- package/dist/utils/log-service.d.ts +19 -0
- package/dist/utils/log-service.js +47 -0
- package/dist/utils/log-service.js.map +1 -0
- package/dist/utils/logger.d.ts +46 -27
- package/dist/utils/logger.js +82 -60
- package/dist/utils/logger.js.map +1 -1
- package/dist/utils/path.d.ts +19 -0
- package/dist/utils/path.js +77 -0
- package/dist/utils/path.js.map +1 -0
- package/dist/utils/process-manager.d.ts +21 -0
- package/dist/utils/process-manager.js +138 -0
- package/dist/utils/process-manager.js.map +1 -0
- package/dist/utils/retry.d.ts +121 -0
- package/dist/utils/retry.js +374 -0
- package/dist/utils/retry.js.map +1 -0
- package/dist/utils/run-service.d.ts +88 -0
- package/dist/utils/run-service.js +412 -0
- package/dist/utils/run-service.js.map +1 -0
- package/dist/utils/state.d.ts +62 -3
- package/dist/utils/state.js +317 -11
- package/dist/utils/state.js.map +1 -1
- package/dist/utils/task-service.d.ts +82 -0
- package/dist/utils/task-service.js +348 -0
- package/dist/utils/task-service.js.map +1 -0
- package/dist/utils/template.d.ts +14 -0
- package/dist/utils/template.js +122 -0
- package/dist/utils/template.js.map +1 -0
- package/dist/utils/types.d.ts +2 -271
- package/dist/utils/types.js +16 -0
- package/dist/utils/types.js.map +1 -1
- package/package.json +38 -23
- package/scripts/ai-security-check.js +0 -1
- package/scripts/local-security-gate.sh +0 -0
- package/scripts/monitor-lanes.sh +94 -0
- package/scripts/patches/test-cursor-agent.js +0 -1
- package/scripts/release.sh +0 -0
- package/scripts/setup-security.sh +0 -0
- package/scripts/stream-logs.sh +72 -0
- package/scripts/verify-and-fix.sh +0 -0
- package/src/cli/clean.ts +187 -6
- package/src/cli/index.ts +12 -1
- package/src/cli/init.ts +8 -7
- package/src/cli/logs.ts +124 -77
- package/src/cli/monitor.ts +1815 -898
- package/src/cli/prepare.ts +41 -21
- package/src/cli/resume.ts +753 -626
- package/src/cli/run.ts +12 -5
- package/src/cli/runs.ts +212 -0
- package/src/cli/setup-commands.ts +0 -0
- package/src/cli/signal.ts +8 -7
- package/src/cli/stop.ts +209 -0
- package/src/cli/tasks.ts +154 -0
- package/src/core/auto-recovery.ts +909 -0
- package/src/core/failure-policy.ts +592 -0
- package/src/core/orchestrator.ts +1131 -704
- package/src/core/reviewer.ts +4 -0
- package/src/core/runner.ts +444 -180
- package/src/services/logging/buffer.ts +326 -0
- package/src/services/logging/console.ts +193 -0
- package/src/services/logging/file-writer.ts +526 -0
- package/src/services/logging/formatter.ts +268 -0
- package/src/services/logging/index.ts +16 -0
- package/src/services/logging/parser.ts +232 -0
- package/src/services/process/index.ts +261 -0
- package/src/types/agent.ts +24 -0
- package/src/types/config.ts +79 -0
- package/src/types/events.ts +156 -0
- package/src/types/index.ts +29 -0
- package/src/types/lane.ts +56 -0
- package/src/types/logging.ts +96 -0
- package/src/types/review.ts +20 -0
- package/src/types/run.ts +37 -0
- package/src/types/task.ts +79 -0
- package/src/ui/components.ts +430 -0
- package/src/ui/log-viewer.ts +485 -0
- package/src/utils/checkpoint.ts +374 -0
- package/src/utils/config.ts +18 -8
- package/src/utils/cursor-agent.ts +1 -1
- package/src/utils/dependency.ts +482 -0
- package/src/utils/doctor.ts +18 -11
- package/src/utils/enhanced-logger.ts +122 -60
- package/src/utils/git.ts +517 -11
- package/src/utils/health.ts +596 -0
- package/src/utils/lock.ts +346 -0
- package/src/utils/log-buffer.ts +28 -0
- package/src/utils/log-constants.ts +26 -0
- package/src/utils/log-formatter.ts +245 -0
- package/src/utils/log-service.ts +49 -0
- package/src/utils/logger.ts +100 -51
- package/src/utils/path.ts +45 -0
- package/src/utils/process-manager.ts +100 -0
- package/src/utils/retry.ts +413 -0
- package/src/utils/run-service.ts +433 -0
- package/src/utils/state.ts +385 -11
- package/src/utils/task-service.ts +370 -0
- package/src/utils/template.ts +92 -0
- package/src/utils/types.ts +2 -314
- package/templates/basic.json +21 -0
package/src/cli/clean.ts
CHANGED
|
@@ -9,6 +9,8 @@ import * as path from 'path';
|
|
|
9
9
|
import * as logger from '../utils/logger';
|
|
10
10
|
import * as git from '../utils/git';
|
|
11
11
|
import { loadConfig, getLogsDir, getTasksDir } from '../utils/config';
|
|
12
|
+
import { safeJoin } from '../utils/path';
|
|
13
|
+
import { RunService } from '../utils/run-service';
|
|
12
14
|
|
|
13
15
|
interface CleanOptions {
|
|
14
16
|
type?: string;
|
|
@@ -19,6 +21,9 @@ interface CleanOptions {
|
|
|
19
21
|
help: boolean;
|
|
20
22
|
keepLatest: boolean;
|
|
21
23
|
includeLatest: boolean;
|
|
24
|
+
run?: string;
|
|
25
|
+
olderThan?: number;
|
|
26
|
+
orphaned: boolean;
|
|
22
27
|
}
|
|
23
28
|
|
|
24
29
|
function printHelp(): void {
|
|
@@ -35,6 +40,9 @@ Types:
|
|
|
35
40
|
all Remove all of the above (default)
|
|
36
41
|
|
|
37
42
|
Options:
|
|
43
|
+
--run <id> Clean resources linked to a specific run
|
|
44
|
+
--older-than <days> Clean resources older than N days
|
|
45
|
+
--orphaned Clean orphaned resources (not linked to any run)
|
|
38
46
|
--dry-run Show what would be removed without deleting
|
|
39
47
|
--force Force removal (ignore uncommitted changes)
|
|
40
48
|
--include-latest Also remove the most recent item (by default, latest is kept)
|
|
@@ -44,6 +52,9 @@ Options:
|
|
|
44
52
|
|
|
45
53
|
function parseArgs(args: string[]): CleanOptions {
|
|
46
54
|
const includeLatest = args.includes('--include-latest');
|
|
55
|
+
const runIdx = args.indexOf('--run');
|
|
56
|
+
const olderThanIdx = args.indexOf('--older-than');
|
|
57
|
+
|
|
47
58
|
return {
|
|
48
59
|
type: args.find(a => ['branches', 'worktrees', 'logs', 'tasks', 'all'].includes(a)),
|
|
49
60
|
pattern: null,
|
|
@@ -53,6 +64,9 @@ function parseArgs(args: string[]): CleanOptions {
|
|
|
53
64
|
help: args.includes('--help') || args.includes('-h'),
|
|
54
65
|
keepLatest: !includeLatest, // Default: keep latest, unless --include-latest is specified
|
|
55
66
|
includeLatest,
|
|
67
|
+
run: runIdx >= 0 ? args[runIdx + 1] : undefined,
|
|
68
|
+
olderThan: olderThanIdx >= 0 ? parseInt(args[olderThanIdx + 1] || '0') : undefined,
|
|
69
|
+
orphaned: args.includes('--orphaned'),
|
|
56
70
|
};
|
|
57
71
|
}
|
|
58
72
|
|
|
@@ -78,9 +92,33 @@ async function clean(args: string[]): Promise<void> {
|
|
|
78
92
|
|
|
79
93
|
const config = loadConfig();
|
|
80
94
|
const repoRoot = git.getRepoRoot();
|
|
95
|
+
const logsDir = getLogsDir(config);
|
|
96
|
+
const runsDir = safeJoin(logsDir, 'runs');
|
|
97
|
+
const runService = new RunService(runsDir);
|
|
81
98
|
|
|
82
99
|
logger.section('🧹 Cleaning CursorFlow Resources');
|
|
83
100
|
|
|
101
|
+
// Handle specific run cleanup
|
|
102
|
+
if (options.run) {
|
|
103
|
+
await cleanRunResources(runService, options.run, repoRoot, options);
|
|
104
|
+
logger.success('\n✨ Run cleaning complete!');
|
|
105
|
+
return;
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
// Handle older-than cleanup
|
|
109
|
+
if (options.olderThan !== undefined) {
|
|
110
|
+
await cleanOlderRuns(runService, options.olderThan, repoRoot, options);
|
|
111
|
+
logger.success(`\n✨ Older than ${options.olderThan} days cleaning complete!`);
|
|
112
|
+
return;
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
// Handle orphaned cleanup
|
|
116
|
+
if (options.orphaned) {
|
|
117
|
+
await cleanOrphanedResources(runService, config, repoRoot, options);
|
|
118
|
+
logger.success('\n✨ Orphaned resources cleaning complete!');
|
|
119
|
+
return;
|
|
120
|
+
}
|
|
121
|
+
|
|
84
122
|
const type = options.type || 'all';
|
|
85
123
|
|
|
86
124
|
if (type === 'all') {
|
|
@@ -105,7 +143,7 @@ async function cleanWorktrees(config: any, repoRoot: string, options: CleanOptio
|
|
|
105
143
|
logger.info('\nChecking worktrees...');
|
|
106
144
|
const worktrees = git.listWorktrees(repoRoot);
|
|
107
145
|
|
|
108
|
-
const worktreeRoot =
|
|
146
|
+
const worktreeRoot = safeJoin(repoRoot, config.worktreeRoot || '_cursorflow/worktrees');
|
|
109
147
|
let toRemove = worktrees.filter(wt => {
|
|
110
148
|
// Skip main worktree
|
|
111
149
|
if (wt.path === repoRoot) return false;
|
|
@@ -226,9 +264,9 @@ async function cleanLogs(config: any, options: CleanOptions) {
|
|
|
226
264
|
const entries = fs.readdirSync(logsDir, { withFileTypes: true });
|
|
227
265
|
let items = entries.map(entry => ({
|
|
228
266
|
name: entry.name,
|
|
229
|
-
path:
|
|
267
|
+
path: safeJoin(logsDir, entry.name),
|
|
230
268
|
isDir: entry.isDirectory(),
|
|
231
|
-
mtime: getModTime(
|
|
269
|
+
mtime: getModTime(safeJoin(logsDir, entry.name))
|
|
232
270
|
}));
|
|
233
271
|
|
|
234
272
|
if (items.length <= 1) {
|
|
@@ -288,9 +326,9 @@ async function cleanTasks(config: any, options: CleanOptions) {
|
|
|
288
326
|
.filter(entry => entry.name !== 'example')
|
|
289
327
|
.map(entry => ({
|
|
290
328
|
name: entry.name,
|
|
291
|
-
path:
|
|
329
|
+
path: safeJoin(tasksDir, entry.name),
|
|
292
330
|
isDir: entry.isDirectory(),
|
|
293
|
-
mtime: getModTime(
|
|
331
|
+
mtime: getModTime(safeJoin(tasksDir, entry.name))
|
|
294
332
|
}));
|
|
295
333
|
|
|
296
334
|
if (items.length <= 1) {
|
|
@@ -325,7 +363,7 @@ async function cleanTasks(config: any, options: CleanOptions) {
|
|
|
325
363
|
const entries = fs.readdirSync(tasksDir, { withFileTypes: true });
|
|
326
364
|
for (const entry of entries) {
|
|
327
365
|
if (entry.name === 'example') continue;
|
|
328
|
-
const itemPath =
|
|
366
|
+
const itemPath = safeJoin(tasksDir, entry.name);
|
|
329
367
|
logger.info(` Removing task: ${entry.name}...`);
|
|
330
368
|
fs.rmSync(itemPath, { recursive: true, force: true });
|
|
331
369
|
}
|
|
@@ -337,4 +375,147 @@ async function cleanTasks(config: any, options: CleanOptions) {
|
|
|
337
375
|
}
|
|
338
376
|
}
|
|
339
377
|
|
|
378
|
+
async function cleanRunResources(runService: RunService, runId: string, repoRoot: string, options: CleanOptions) {
|
|
379
|
+
const run = runService.getRunInfo(runId);
|
|
380
|
+
if (!run) {
|
|
381
|
+
logger.warn(`Run not found: ${runId}`);
|
|
382
|
+
return;
|
|
383
|
+
}
|
|
384
|
+
|
|
385
|
+
logger.info(`\nCleaning resources for run: ${runId} (${run.taskName})`);
|
|
386
|
+
|
|
387
|
+
// Clean branches
|
|
388
|
+
if (run.branches.length > 0) {
|
|
389
|
+
logger.info(' Cleaning branches...');
|
|
390
|
+
for (const branch of run.branches) {
|
|
391
|
+
if (options.dryRun) {
|
|
392
|
+
logger.info(` [DRY RUN] Would delete branch: ${branch}`);
|
|
393
|
+
} else {
|
|
394
|
+
try {
|
|
395
|
+
git.deleteBranch(branch, { cwd: repoRoot, force: true });
|
|
396
|
+
logger.info(` Deleted branch: ${branch}`);
|
|
397
|
+
} catch (e: any) {
|
|
398
|
+
logger.warn(` Could not delete branch ${branch}: ${e.message}`);
|
|
399
|
+
}
|
|
400
|
+
}
|
|
401
|
+
}
|
|
402
|
+
}
|
|
403
|
+
|
|
404
|
+
// Clean worktrees
|
|
405
|
+
if (run.worktrees.length > 0) {
|
|
406
|
+
logger.info(' Cleaning worktrees...');
|
|
407
|
+
for (const wtPath of run.worktrees) {
|
|
408
|
+
if (options.dryRun) {
|
|
409
|
+
logger.info(` [DRY RUN] Would remove worktree: ${wtPath}`);
|
|
410
|
+
} else {
|
|
411
|
+
try {
|
|
412
|
+
git.removeWorktree(wtPath, { cwd: repoRoot, force: true });
|
|
413
|
+
if (fs.existsSync(wtPath)) {
|
|
414
|
+
fs.rmSync(wtPath, { recursive: true, force: true });
|
|
415
|
+
}
|
|
416
|
+
logger.info(` Removed worktree: ${wtPath}`);
|
|
417
|
+
} catch (e: any) {
|
|
418
|
+
logger.warn(` Could not remove worktree ${wtPath}: ${e.message}`);
|
|
419
|
+
}
|
|
420
|
+
}
|
|
421
|
+
}
|
|
422
|
+
}
|
|
423
|
+
|
|
424
|
+
// Delete run directory
|
|
425
|
+
if (options.dryRun) {
|
|
426
|
+
logger.info(` [DRY RUN] Would delete run directory: ${run.path}`);
|
|
427
|
+
} else {
|
|
428
|
+
try {
|
|
429
|
+
runService.deleteRun(runId, { force: options.force });
|
|
430
|
+
logger.info(` Deleted run directory: ${run.path}`);
|
|
431
|
+
} catch (e: any) {
|
|
432
|
+
logger.error(` Failed to delete run ${runId}: ${e.message}`);
|
|
433
|
+
}
|
|
434
|
+
}
|
|
435
|
+
}
|
|
436
|
+
|
|
437
|
+
async function cleanOlderRuns(runService: RunService, days: number, repoRoot: string, options: CleanOptions) {
|
|
438
|
+
const cutoff = Date.now() - (days * 24 * 60 * 60 * 1000);
|
|
439
|
+
const runs = runService.listRuns();
|
|
440
|
+
const olderRuns = runs.filter(run => run.startTime < cutoff);
|
|
441
|
+
|
|
442
|
+
if (olderRuns.length === 0) {
|
|
443
|
+
logger.info(`No runs found older than ${days} days.`);
|
|
444
|
+
return;
|
|
445
|
+
}
|
|
446
|
+
|
|
447
|
+
logger.info(`Found ${olderRuns.length} runs older than ${days} days.`);
|
|
448
|
+
for (const run of olderRuns) {
|
|
449
|
+
await cleanRunResources(runService, run.id, repoRoot, options);
|
|
450
|
+
}
|
|
451
|
+
}
|
|
452
|
+
|
|
453
|
+
async function cleanOrphanedResources(runService: RunService, config: any, repoRoot: string, options: CleanOptions) {
|
|
454
|
+
const runs = runService.listRuns();
|
|
455
|
+
const linkedWorktrees = new Set(runs.flatMap(r => r.worktrees));
|
|
456
|
+
const linkedBranches = new Set(runs.flatMap(r => r.branches));
|
|
457
|
+
|
|
458
|
+
// Clean orphaned worktrees
|
|
459
|
+
logger.info('\nChecking for orphaned worktrees...');
|
|
460
|
+
const worktrees = git.listWorktrees(repoRoot);
|
|
461
|
+
const worktreeRoot = safeJoin(repoRoot, config.worktreeRoot || '_cursorflow/worktrees');
|
|
462
|
+
|
|
463
|
+
const orphanedWorktrees = worktrees.filter(wt => {
|
|
464
|
+
if (wt.path === repoRoot) return false;
|
|
465
|
+
const isInsideRoot = wt.path.startsWith(worktreeRoot);
|
|
466
|
+
const hasPrefix = path.basename(wt.path).startsWith(config.worktreePrefix || 'cursorflow-');
|
|
467
|
+
return (isInsideRoot || hasPrefix) && !linkedWorktrees.has(wt.path);
|
|
468
|
+
});
|
|
469
|
+
|
|
470
|
+
if (orphanedWorktrees.length === 0) {
|
|
471
|
+
logger.info(' No orphaned worktrees found.');
|
|
472
|
+
} else {
|
|
473
|
+
for (const wt of orphanedWorktrees) {
|
|
474
|
+
if (options.dryRun) {
|
|
475
|
+
logger.info(` [DRY RUN] Would remove orphaned worktree: ${wt.path}`);
|
|
476
|
+
} else {
|
|
477
|
+
try {
|
|
478
|
+
git.removeWorktree(wt.path, { cwd: repoRoot, force: true });
|
|
479
|
+
if (fs.existsSync(wt.path)) {
|
|
480
|
+
fs.rmSync(wt.path, { recursive: true, force: true });
|
|
481
|
+
}
|
|
482
|
+
logger.info(` Removed orphaned worktree: ${wt.path}`);
|
|
483
|
+
} catch (e: any) {
|
|
484
|
+
logger.warn(` Could not remove orphaned worktree ${wt.path}: ${e.message}`);
|
|
485
|
+
}
|
|
486
|
+
}
|
|
487
|
+
}
|
|
488
|
+
}
|
|
489
|
+
|
|
490
|
+
// Clean orphaned branches
|
|
491
|
+
logger.info('\nChecking for orphaned branches...');
|
|
492
|
+
const result = git.runGitResult(['branch', '--list'], { cwd: repoRoot });
|
|
493
|
+
if (result.success) {
|
|
494
|
+
const branches = result.stdout
|
|
495
|
+
.split('\n')
|
|
496
|
+
.map(b => b.replace(/\*/g, '').trim())
|
|
497
|
+
.filter(b => b && b !== 'main' && b !== 'master');
|
|
498
|
+
|
|
499
|
+
const prefix = config.branchPrefix || 'feature/';
|
|
500
|
+
const orphanedBranches = branches.filter(b => b.startsWith(prefix) && !linkedBranches.has(b));
|
|
501
|
+
|
|
502
|
+
if (orphanedBranches.length === 0) {
|
|
503
|
+
logger.info(' No orphaned branches found.');
|
|
504
|
+
} else {
|
|
505
|
+
for (const branch of orphanedBranches) {
|
|
506
|
+
if (options.dryRun) {
|
|
507
|
+
logger.info(` [DRY RUN] Would delete orphaned branch: ${branch}`);
|
|
508
|
+
} else {
|
|
509
|
+
try {
|
|
510
|
+
git.deleteBranch(branch, { cwd: repoRoot, force: true });
|
|
511
|
+
logger.info(` Deleted orphaned branch: ${branch}`);
|
|
512
|
+
} catch (e: any) {
|
|
513
|
+
logger.warn(` Could not delete orphaned branch ${branch}: ${e.message}`);
|
|
514
|
+
}
|
|
515
|
+
}
|
|
516
|
+
}
|
|
517
|
+
}
|
|
518
|
+
}
|
|
519
|
+
}
|
|
520
|
+
|
|
340
521
|
export = clean;
|
package/src/cli/index.ts
CHANGED
|
@@ -21,6 +21,9 @@ const COMMANDS: Record<string, CommandFn> = {
|
|
|
21
21
|
signal: require('./signal'),
|
|
22
22
|
models: require('./models'),
|
|
23
23
|
logs: require('./logs'),
|
|
24
|
+
runs: require('./runs'),
|
|
25
|
+
tasks: require('./tasks'),
|
|
26
|
+
stop: require('./stop'),
|
|
24
27
|
setup: require('./setup-commands').main,
|
|
25
28
|
'setup-commands': require('./setup-commands').main,
|
|
26
29
|
};
|
|
@@ -34,10 +37,14 @@ function printHelp(): void {
|
|
|
34
37
|
|
|
35
38
|
\x1b[1mCOMMANDS\x1b[0m
|
|
36
39
|
\x1b[33minit\x1b[0m [options] Initialize CursorFlow in project
|
|
40
|
+
\x1b[33msetup\x1b[0m [options] Install Cursor IDE commands
|
|
37
41
|
\x1b[33mprepare\x1b[0m <feature> [opts] Prepare task directory and JSON files
|
|
38
42
|
\x1b[33mrun\x1b[0m <tasks-dir> [options] Run orchestration (DAG-based)
|
|
39
43
|
\x1b[33mmonitor\x1b[0m [run-dir] [options] \x1b[36mInteractive\x1b[0m lane dashboard
|
|
40
|
-
\x1b[
|
|
44
|
+
\x1b[33mtasks\x1b[0m [name] [options] Browse and validate prepared tasks
|
|
45
|
+
\x1b[33mruns\x1b[0m [run-id] [options] List and view run details
|
|
46
|
+
\x1b[33mstop\x1b[0m [run-id] [options] Stop running workflows
|
|
47
|
+
\x1b[33mclean\x1b[0m <type> [options] Clean branches/worktrees/logs/tasks
|
|
41
48
|
\x1b[33mresume\x1b[0m [lane] [options] Resume lane(s) - use --all for batch resume
|
|
42
49
|
\x1b[33mdoctor\x1b[0m [options] Check environment and preflight
|
|
43
50
|
\x1b[33msignal\x1b[0m <lane> <msg> Directly intervene in a running lane
|
|
@@ -54,6 +61,10 @@ function printHelp(): void {
|
|
|
54
61
|
$ \x1b[32mcursorflow prepare NewFeature --lanes 3\x1b[0m
|
|
55
62
|
$ \x1b[32mcursorflow run _cursorflow/tasks/MyFeature/\x1b[0m
|
|
56
63
|
$ \x1b[32mcursorflow monitor latest\x1b[0m
|
|
64
|
+
$ \x1b[32mcursorflow logs --all --follow\x1b[0m
|
|
65
|
+
$ \x1b[32mcursorflow runs --running\x1b[0m
|
|
66
|
+
$ \x1b[32mcursorflow resume --all\x1b[0m
|
|
67
|
+
$ \x1b[32mcursorflow doctor\x1b[0m
|
|
57
68
|
$ \x1b[32mcursorflow models\x1b[0m
|
|
58
69
|
|
|
59
70
|
\x1b[1mDOCUMENTATION\x1b[0m
|
package/src/cli/init.ts
CHANGED
|
@@ -9,6 +9,7 @@ import * as path from 'path';
|
|
|
9
9
|
import * as logger from '../utils/logger';
|
|
10
10
|
import { findProjectRoot, createDefaultConfig, CursorFlowConfig } from '../utils/config';
|
|
11
11
|
import { setupCommands } from './setup-commands';
|
|
12
|
+
import { safeJoin } from '../utils/path';
|
|
12
13
|
|
|
13
14
|
interface InitOptions {
|
|
14
15
|
example: boolean;
|
|
@@ -84,8 +85,8 @@ Examples:
|
|
|
84
85
|
}
|
|
85
86
|
|
|
86
87
|
function createDirectories(projectRoot: string, config: CursorFlowConfig): void {
|
|
87
|
-
const tasksDir =
|
|
88
|
-
const logsDir =
|
|
88
|
+
const tasksDir = safeJoin(projectRoot, config.tasksDir);
|
|
89
|
+
const logsDir = safeJoin(projectRoot, config.logsDir);
|
|
89
90
|
|
|
90
91
|
if (!fs.existsSync(tasksDir)) {
|
|
91
92
|
fs.mkdirSync(tasksDir, { recursive: true });
|
|
@@ -103,7 +104,7 @@ function createDirectories(projectRoot: string, config: CursorFlowConfig): void
|
|
|
103
104
|
}
|
|
104
105
|
|
|
105
106
|
function createExampleTasks(projectRoot: string, config: CursorFlowConfig): void {
|
|
106
|
-
const exampleDir =
|
|
107
|
+
const exampleDir = safeJoin(projectRoot, config.tasksDir, 'example');
|
|
107
108
|
|
|
108
109
|
if (!fs.existsSync(exampleDir)) {
|
|
109
110
|
fs.mkdirSync(exampleDir, { recursive: true });
|
|
@@ -111,7 +112,7 @@ function createExampleTasks(projectRoot: string, config: CursorFlowConfig): void
|
|
|
111
112
|
|
|
112
113
|
const exampleTask = {
|
|
113
114
|
repository: "https://github.com/your-org/your-repo",
|
|
114
|
-
baseBranch
|
|
115
|
+
// baseBranch is auto-detected from current branch at runtime
|
|
115
116
|
branchPrefix: "cursorflow/example-",
|
|
116
117
|
executor: "cursor-agent",
|
|
117
118
|
autoCreatePr: false,
|
|
@@ -134,13 +135,13 @@ Create a simple hello.txt file with a greeting message.
|
|
|
134
135
|
]
|
|
135
136
|
};
|
|
136
137
|
|
|
137
|
-
const taskPath =
|
|
138
|
+
const taskPath = safeJoin(exampleDir, '01-hello.json');
|
|
138
139
|
fs.writeFileSync(taskPath, JSON.stringify(exampleTask, null, 2) + '\n', 'utf8');
|
|
139
140
|
|
|
140
141
|
logger.success(`Created example task: ${path.relative(projectRoot, taskPath)}`);
|
|
141
142
|
|
|
142
143
|
// Create README
|
|
143
|
-
const readmePath =
|
|
144
|
+
const readmePath = safeJoin(exampleDir, 'README.md');
|
|
144
145
|
const readme = `# Example Task
|
|
145
146
|
|
|
146
147
|
This is an example CursorFlow task to help you get started.
|
|
@@ -172,7 +173,7 @@ cursorflow run ${config.tasksDir}/example/
|
|
|
172
173
|
* Add _cursorflow to .gitignore
|
|
173
174
|
*/
|
|
174
175
|
function updateGitignore(projectRoot: string): void {
|
|
175
|
-
const gitignorePath =
|
|
176
|
+
const gitignorePath = safeJoin(projectRoot, '.gitignore');
|
|
176
177
|
const entry = '_cursorflow/';
|
|
177
178
|
|
|
178
179
|
// Try to read existing .gitignore (avoid TOCTOU by reading directly)
|