@litmers/cursorflow-orchestrator 0.1.20 → 0.1.28

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 +20 -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 +87 -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 +125 -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 +397 -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 +97 -3
  175. package/src/cli/resume.ts +220 -277
  176. package/src/cli/run.ts +154 -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 +1136 -675
  185. package/src/core/reviewer.ts +4 -0
  186. package/src/core/runner.ts +1443 -1217
  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 +871 -499
  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
package/package.json CHANGED
@@ -1,32 +1,12 @@
1
1
  {
2
2
  "name": "@litmers/cursorflow-orchestrator",
3
- "version": "0.1.20",
3
+ "version": "0.1.28",
4
4
  "description": "Git worktree-based parallel AI agent orchestration system for Cursor",
5
5
  "main": "dist/cli/index.js",
6
6
  "bin": {
7
7
  "cursorflow": "dist/cli/index.js",
8
8
  "cursorflow-setup": "dist/cli/setup-commands.js"
9
9
  },
10
- "scripts": {
11
- "build": "tsc",
12
- "watch": "tsc -w",
13
- "test": "jest",
14
- "prepublishOnly": "npm run build && npm run validate",
15
- "postinstall": "node scripts/postinstall.js",
16
- "validate": "npm pack --dry-run",
17
- "release": "scripts/release.sh",
18
- "release:patch": "scripts/release.sh patch",
19
- "release:minor": "scripts/release.sh minor",
20
- "release:major": "scripts/release.sh major",
21
- "security:check": "scripts/local-security-gate.sh",
22
- "security:audit": "npm audit",
23
- "security:audit:fix": "npm audit fix",
24
- "security:setup": "scripts/setup-security.sh",
25
- "verify": "scripts/verify-and-fix.sh",
26
- "test:lifecycle": "tests/scripts/test-real-cursor-lifecycle.sh",
27
- "test:comprehensive": "tests/scripts/test-comprehensive-lifecycle.sh",
28
- "prepare": "husky"
29
- },
30
10
  "keywords": [
31
11
  "cursor",
32
12
  "cursor-ide",
@@ -70,5 +50,40 @@
70
50
  "README.md",
71
51
  "LICENSE",
72
52
  "CHANGELOG.md"
73
- ]
74
- }
53
+ ],
54
+ "scripts": {
55
+ "build": "tsc",
56
+ "watch": "tsc -w",
57
+ "test": "jest",
58
+ "postinstall": "node scripts/postinstall.js",
59
+ "validate": "pnpm pack",
60
+ "release": "scripts/release.sh",
61
+ "release:patch": "scripts/release.sh patch",
62
+ "release:minor": "scripts/release.sh minor",
63
+ "release:major": "scripts/release.sh major",
64
+ "security:check": "scripts/local-security-gate.sh",
65
+ "security:audit": "pnpm audit",
66
+ "security:audit:fix": "pnpm audit --fix",
67
+ "security:setup": "scripts/setup-security.sh",
68
+ "verify": "scripts/verify-and-fix.sh",
69
+ "monitor": "scripts/monitor-lanes.sh",
70
+ "monitor:watch": "scripts/monitor-lanes.sh --watch",
71
+ "monitor:stream": "scripts/stream-logs.sh",
72
+ "cf": "node dist/cli/index.js",
73
+ "cf:init": "node dist/cli/index.js init",
74
+ "cf:setup": "node dist/cli/index.js setup",
75
+ "cf:prepare": "node dist/cli/index.js prepare",
76
+ "cf:run": "node dist/cli/index.js run",
77
+ "cf:monitor": "node dist/cli/index.js monitor",
78
+ "cf:clean": "node dist/cli/index.js clean",
79
+ "cf:stop": "node dist/cli/index.js stop",
80
+ "cf:resume": "node dist/cli/index.js resume",
81
+ "cf:doctor": "node dist/cli/index.js doctor",
82
+ "cf:signal": "node dist/cli/index.js signal",
83
+ "cf:logs": "node dist/cli/index.js logs",
84
+ "cf:runs": "node dist/cli/index.js runs",
85
+ "cf:models": "node dist/cli/index.js models",
86
+ "test:lifecycle": "tests/scripts/test-real-cursor-lifecycle.sh",
87
+ "test:comprehensive": "tests/scripts/test-comprehensive-lifecycle.sh"
88
+ }
89
+ }
@@ -6,7 +6,6 @@
6
6
  */
7
7
 
8
8
  const fs = require('fs');
9
- const path = require('path');
10
9
  const { spawnSync } = require('child_process');
11
10
 
12
11
  // 색상 정의
File without changes
@@ -0,0 +1,94 @@
1
+ #!/bin/bash
2
+
3
+ # CursorFlow Lane Monitor
4
+ # Displays the latest logs from all active lanes in the current or latest run.
5
+
6
+ # Colors for output
7
+ BLUE='\033[0;34m'
8
+ GREEN='\033[0;32m'
9
+ YELLOW='\033[1;33m'
10
+ RED='\033[0;31m'
11
+ NC='\033[0m' # No Color
12
+ BOLD='\033[1m'
13
+
14
+ LOGS_DIR_BASE="${1:-.}"
15
+ LOGS_DIR="${LOGS_DIR_BASE}/_cursorflow/logs/runs"
16
+
17
+ # Shift arguments if path was provided
18
+ if [[ -d "$1" && "$1" != "-w" && "$1" != "--watch" ]]; then
19
+ shift
20
+ fi
21
+
22
+ # Ensure we are in the root of the project or target dir
23
+ if [ ! -d "$LOGS_DIR" ]; then
24
+ echo -e "${RED}Error: ${LOGS_DIR} directory not found.${NC}"
25
+ echo "Please run this script from the root of the CursorFlow project or provide a path."
26
+ exit 1
27
+ fi
28
+
29
+ # Find the latest run directory
30
+ LATEST_RUN=$(ls -td ${LOGS_DIR}/run-* 2>/dev/null | head -n 1)
31
+
32
+ if [ -z "$LATEST_RUN" ]; then
33
+ echo -e "${YELLOW}No runs found in ${LOGS_DIR}${NC}"
34
+ exit 1
35
+ fi
36
+
37
+ RUN_ID=$(basename "$LATEST_RUN")
38
+
39
+ # Clear screen if requested or if using watch
40
+ show_summary() {
41
+ echo -e "${BOLD}CursorFlow Lane Monitor${NC} - Run: ${GREEN}${RUN_ID}${NC}"
42
+ echo -e "Time: $(date '+%Y-%m-%d %H:%M:%S')"
43
+ echo "--------------------------------------------------------------------------------"
44
+
45
+ for lane_dir in "${LATEST_RUN}/lanes"/*; do
46
+ if [ -d "$lane_dir" ]; then
47
+ lane_name=$(basename "$lane_dir")
48
+ log_file="${lane_dir}/terminal-readable.log"
49
+
50
+ # Extract status if possible (last line of log often contains status info)
51
+ if [ -f "$log_file" ]; then
52
+ # Get the last few lines
53
+ LAST_LOG=$(tail -n 1 "$log_file")
54
+
55
+ # Check for completion or errors
56
+ STATUS="${BLUE}RUNNING${NC}"
57
+ if grep -q "✅ Pipeline completed" "$log_file" 2>/dev/null; then
58
+ STATUS="${GREEN}SUCCESS${NC}"
59
+ elif grep -q "❌ Pipeline failed" "$log_file" 2>/dev/null; then
60
+ STATUS="${RED}ERROR${NC}"
61
+ elif grep -q "❌ Task failed" "$log_file" 2>/dev/null; then
62
+ STATUS="${RED}ERROR${NC}"
63
+ elif grep -q "✅ ✓ Configuration valid" "$log_file" 2>/dev/null; then
64
+ STATUS="${BLUE}ACTIVE${NC}"
65
+ fi
66
+
67
+ echo -e "[${STATUS}] ${BOLD}${lane_name}${NC}"
68
+ echo -e " ${LAST_LOG:0:100}"
69
+ echo ""
70
+ else
71
+ echo -e "[${YELLOW}WAITING${NC}] ${BOLD}${lane_name}${NC}"
72
+ echo " (No logs yet)"
73
+ echo ""
74
+ fi
75
+ fi
76
+ done
77
+ }
78
+
79
+ # Check for watch mode
80
+ if [[ "$1" == "-w" || "$1" == "--watch" ]]; then
81
+ # Use simple loop to avoid argument passing issues with 'watch' command
82
+ while true; do
83
+ clear
84
+ show_summary
85
+ echo "Press Ctrl+C to stop..."
86
+ sleep 2
87
+ done
88
+ else
89
+ show_summary
90
+ echo -e "${NC}Tip: Use ${BOLD}$0 --watch${NC} to monitor in real-time."
91
+ fi
92
+
93
+ exit 0
94
+
@@ -15,7 +15,6 @@
15
15
  */
16
16
 
17
17
  const { spawn, spawnSync } = require('child_process');
18
- const path = require('path');
19
18
 
20
19
  // Parse args
21
20
  const args = process.argv.slice(2);
File without changes
File without changes
@@ -0,0 +1,72 @@
1
+ #!/bin/bash
2
+
3
+ # CursorFlow All Lanes Log Streamer
4
+ # Replicates the output of 'cursorflow run' by streaming logs from all lanes.
5
+
6
+ BLUE='\033[0;34m'
7
+ GREEN='\033[0;32m'
8
+ YELLOW='\033[1;33m'
9
+ RED='\033[0;31m'
10
+ NC='\033[0m' # No Color
11
+ BOLD='\033[1m'
12
+
13
+ LOGS_DIR_BASE="${1:-.}"
14
+ LOGS_DIR="${LOGS_DIR_BASE}/_cursorflow/logs/runs"
15
+
16
+ if [ ! -d "$LOGS_DIR" ]; then
17
+ echo -e "${RED}Error: ${LOGS_DIR} directory not found.${NC}"
18
+ exit 1
19
+ fi
20
+
21
+ LATEST_RUN=$(ls -td ${LOGS_DIR}/run-* 2>/dev/null | head -n 1)
22
+
23
+ if [ -z "$LATEST_RUN" ]; then
24
+ echo -e "${YELLOW}No runs found in ${LOGS_DIR}${NC}"
25
+ exit 1
26
+ fi
27
+
28
+ RUN_ID=$(basename "$LATEST_RUN")
29
+ echo -e "${BOLD}Streaming logs for Run: ${GREEN}${RUN_ID}${NC}"
30
+ echo "--------------------------------------------------------------------------------"
31
+
32
+ # Function to stream a single log file with a prefix
33
+ stream_log() {
34
+ local lane_name=$1
35
+ local log_file=$2
36
+ local color=$3
37
+
38
+ # Check if file exists, if not wait for it
39
+ until [ -f "$log_file" ]; do
40
+ sleep 1
41
+ done
42
+
43
+ # Tail the file and prefix each line
44
+ tail -n +1 -f "$log_file" | while IFS= read -r line; do
45
+ echo -e "${color}[${lane_name}]${NC} ${line}"
46
+ done
47
+ }
48
+
49
+ # Colors to rotate through
50
+ COLORS=('\033[0;32m' '\033[0;34m' '\033[0;35m' '\033[0;36m' '\033[1;32m' '\033[1;34m' '\033[1;35m' '\033[1;36m')
51
+ color_idx=0
52
+
53
+ # Clean up background processes on exit
54
+ trap 'kill $(jobs -p) 2>/dev/null' EXIT
55
+
56
+ # Find all lanes and start streaming
57
+ for lane_dir in "${LATEST_RUN}/lanes"/*; do
58
+ if [ -d "$lane_dir" ]; then
59
+ lane_name=$(basename "$lane_dir")
60
+ log_file="${lane_dir}/terminal-readable.log"
61
+ color=${COLORS[$color_idx]}
62
+
63
+ # Start streaming in background
64
+ stream_log "$lane_name" "$log_file" "$color" &
65
+
66
+ color_idx=$(( (color_idx + 1) % ${#COLORS[@]} ))
67
+ fi
68
+ done
69
+
70
+ # Wait for all background processes
71
+ wait
72
+
File without changes
package/src/cli/clean.ts CHANGED
@@ -10,6 +10,7 @@ import * as logger from '../utils/logger';
10
10
  import * as git from '../utils/git';
11
11
  import { loadConfig, getLogsDir, getTasksDir } from '../utils/config';
12
12
  import { safeJoin } from '../utils/path';
13
+ import { RunService } from '../utils/run-service';
13
14
 
14
15
  interface CleanOptions {
15
16
  type?: string;
@@ -20,6 +21,9 @@ interface CleanOptions {
20
21
  help: boolean;
21
22
  keepLatest: boolean;
22
23
  includeLatest: boolean;
24
+ run?: string;
25
+ olderThan?: number;
26
+ orphaned: boolean;
23
27
  }
24
28
 
25
29
  function printHelp(): void {
@@ -36,6 +40,9 @@ Types:
36
40
  all Remove all of the above (default)
37
41
 
38
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)
39
46
  --dry-run Show what would be removed without deleting
40
47
  --force Force removal (ignore uncommitted changes)
41
48
  --include-latest Also remove the most recent item (by default, latest is kept)
@@ -45,6 +52,9 @@ Options:
45
52
 
46
53
  function parseArgs(args: string[]): CleanOptions {
47
54
  const includeLatest = args.includes('--include-latest');
55
+ const runIdx = args.indexOf('--run');
56
+ const olderThanIdx = args.indexOf('--older-than');
57
+
48
58
  return {
49
59
  type: args.find(a => ['branches', 'worktrees', 'logs', 'tasks', 'all'].includes(a)),
50
60
  pattern: null,
@@ -54,6 +64,9 @@ function parseArgs(args: string[]): CleanOptions {
54
64
  help: args.includes('--help') || args.includes('-h'),
55
65
  keepLatest: !includeLatest, // Default: keep latest, unless --include-latest is specified
56
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'),
57
70
  };
58
71
  }
59
72
 
@@ -79,9 +92,33 @@ async function clean(args: string[]): Promise<void> {
79
92
 
80
93
  const config = loadConfig();
81
94
  const repoRoot = git.getRepoRoot();
95
+ const logsDir = getLogsDir(config);
96
+ const runsDir = safeJoin(logsDir, 'runs');
97
+ const runService = new RunService(runsDir);
82
98
 
83
99
  logger.section('🧹 Cleaning CursorFlow Resources');
84
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
+
85
122
  const type = options.type || 'all';
86
123
 
87
124
  if (type === 'all') {
@@ -338,4 +375,147 @@ async function cleanTasks(config: any, options: CleanOptions) {
338
375
  }
339
376
  }
340
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
+
341
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
  };
@@ -38,6 +41,9 @@ function printHelp(): void {
38
41
  \x1b[33mprepare\x1b[0m <feature> [opts] Prepare task directory and JSON files
39
42
  \x1b[33mrun\x1b[0m <tasks-dir> [options] Run orchestration (DAG-based)
40
43
  \x1b[33mmonitor\x1b[0m [run-dir] [options] \x1b[36mInteractive\x1b[0m lane dashboard
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
41
47
  \x1b[33mclean\x1b[0m <type> [options] Clean branches/worktrees/logs/tasks
42
48
  \x1b[33mresume\x1b[0m [lane] [options] Resume lane(s) - use --all for batch resume
43
49
  \x1b[33mdoctor\x1b[0m [options] Check environment and preflight
@@ -56,6 +62,7 @@ function printHelp(): void {
56
62
  $ \x1b[32mcursorflow run _cursorflow/tasks/MyFeature/\x1b[0m
57
63
  $ \x1b[32mcursorflow monitor latest\x1b[0m
58
64
  $ \x1b[32mcursorflow logs --all --follow\x1b[0m
65
+ $ \x1b[32mcursorflow runs --running\x1b[0m
59
66
  $ \x1b[32mcursorflow resume --all\x1b[0m
60
67
  $ \x1b[32mcursorflow doctor\x1b[0m
61
68
  $ \x1b[32mcursorflow models\x1b[0m
package/src/cli/init.ts CHANGED
@@ -112,7 +112,7 @@ function createExampleTasks(projectRoot: string, config: CursorFlowConfig): void
112
112
 
113
113
  const exampleTask = {
114
114
  repository: "https://github.com/your-org/your-repo",
115
- baseBranch: "main",
115
+ // baseBranch is auto-detected from current branch at runtime
116
116
  branchPrefix: "cursorflow/example-",
117
117
  executor: "cursor-agent",
118
118
  autoCreatePr: false,