@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.
- package/CHANGELOG.md +9 -0
- 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 +171 -0
- package/dist/cli/clean.js.map +1 -1
- package/dist/cli/index.js +7 -0
- package/dist/cli/index.js.map +1 -1
- package/dist/cli/init.js +1 -1
- package/dist/cli/init.js.map +1 -1
- package/dist/cli/logs.js +83 -42
- package/dist/cli/logs.js.map +1 -1
- package/dist/cli/monitor.d.ts +7 -0
- package/dist/cli/monitor.js +1007 -189
- package/dist/cli/monitor.js.map +1 -1
- package/dist/cli/prepare.js +4 -3
- package/dist/cli/prepare.js.map +1 -1
- package/dist/cli/resume.js +188 -236
- package/dist/cli/resume.js.map +1 -1
- package/dist/cli/run.js +8 -3
- 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 +1 -1
- 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 +15 -2
- package/dist/core/orchestrator.js +392 -15
- 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 +321 -146
- 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 +11 -2
- 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 +10 -5
- package/dist/utils/doctor.js.map +1 -1
- package/dist/utils/enhanced-logger.d.ts +10 -33
- package/dist/utils/enhanced-logger.js +94 -9
- package/dist/utils/enhanced-logger.js.map +1 -1
- package/dist/utils/git.d.ts +121 -0
- package/dist/utils/git.js +322 -2
- 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 +9 -0
- package/dist/utils/log-formatter.js +113 -70
- package/dist/utils/log-formatter.js.map +1 -1
- 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/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 +58 -2
- package/dist/utils/state.js +306 -3
- 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/types.d.ts +2 -272
- 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 +180 -0
- package/src/cli/index.ts +7 -0
- package/src/cli/init.ts +1 -1
- package/src/cli/logs.ts +79 -42
- package/src/cli/monitor.ts +1815 -899
- package/src/cli/prepare.ts +4 -3
- package/src/cli/resume.ts +220 -277
- package/src/cli/run.ts +9 -3
- package/src/cli/runs.ts +212 -0
- package/src/cli/setup-commands.ts +0 -0
- package/src/cli/signal.ts +1 -1
- 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 -675
- package/src/core/reviewer.ts +4 -0
- package/src/core/runner.ts +388 -162
- 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 +11 -2
- package/src/utils/cursor-agent.ts +1 -1
- package/src/utils/dependency.ts +482 -0
- package/src/utils/doctor.ts +11 -5
- package/src/utils/enhanced-logger.ts +108 -49
- package/src/utils/git.ts +374 -2
- 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 +120 -37
- package/src/utils/log-service.ts +49 -0
- package/src/utils/logger.ts +100 -51
- 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 +369 -3
- package/src/utils/task-service.ts +370 -0
- 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.
|
|
3
|
+
"version": "0.1.26",
|
|
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
|
+
}
|
|
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
|
+
|
package/scripts/release.sh
CHANGED
|
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
|
|
115
|
+
// baseBranch is auto-detected from current branch at runtime
|
|
116
116
|
branchPrefix: "cursorflow/example-",
|
|
117
117
|
executor: "cursor-agent",
|
|
118
118
|
autoCreatePr: false,
|