@litmers/cursorflow-orchestrator 0.1.14 → 0.1.15
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 +3 -0
- package/dist/cli/logs.js +42 -29
- package/dist/cli/logs.js.map +1 -1
- package/dist/cli/run.js +7 -0
- package/dist/cli/run.js.map +1 -1
- package/dist/core/orchestrator.d.ts +3 -1
- package/dist/core/orchestrator.js +147 -8
- package/dist/core/orchestrator.js.map +1 -1
- package/dist/core/reviewer.d.ts +2 -0
- package/dist/core/reviewer.js +4 -2
- package/dist/core/reviewer.js.map +1 -1
- package/dist/core/runner.d.ts +9 -3
- package/dist/core/runner.js +160 -55
- package/dist/core/runner.js.map +1 -1
- package/dist/utils/config.js +4 -1
- package/dist/utils/config.js.map +1 -1
- package/dist/utils/enhanced-logger.d.ts +3 -2
- package/dist/utils/enhanced-logger.js +87 -20
- package/dist/utils/enhanced-logger.js.map +1 -1
- package/dist/utils/git.d.ts +6 -0
- package/dist/utils/git.js +15 -0
- package/dist/utils/git.js.map +1 -1
- package/dist/utils/logger.d.ts +2 -0
- package/dist/utils/logger.js +4 -1
- package/dist/utils/logger.js.map +1 -1
- package/dist/utils/types.d.ts +10 -0
- package/package.json +2 -1
- package/scripts/patches/test-cursor-agent.js +1 -1
- package/scripts/test-real-cursor-lifecycle.sh +289 -0
- package/src/cli/logs.ts +43 -28
- package/src/cli/run.ts +8 -0
- package/src/core/orchestrator.ts +164 -8
- package/src/core/reviewer.ts +18 -4
- package/src/core/runner.ts +174 -57
- package/src/utils/config.ts +5 -1
- package/src/utils/enhanced-logger.ts +90 -21
- package/src/utils/git.ts +15 -0
- package/src/utils/logger.ts +4 -1
- package/src/utils/types.ts +10 -0
package/dist/utils/logger.js
CHANGED
|
@@ -29,7 +29,9 @@ exports.COLORS = {
|
|
|
29
29
|
green: '\x1b[32m',
|
|
30
30
|
blue: '\x1b[34m',
|
|
31
31
|
cyan: '\x1b[36m',
|
|
32
|
+
magenta: '\x1b[35m',
|
|
32
33
|
gray: '\x1b[90m',
|
|
34
|
+
bold: '\x1b[1m',
|
|
33
35
|
};
|
|
34
36
|
let currentLogLevel = LogLevel.info;
|
|
35
37
|
/**
|
|
@@ -49,7 +51,8 @@ function setLogLevel(level) {
|
|
|
49
51
|
function formatMessage(level, message, emoji = '') {
|
|
50
52
|
const timestamp = new Date().toISOString();
|
|
51
53
|
const prefix = emoji ? `${emoji} ` : '';
|
|
52
|
-
|
|
54
|
+
const lines = String(message).split('\n');
|
|
55
|
+
return lines.map(line => `[${timestamp}] [${level.toUpperCase()}] ${prefix}${line}`).join('\n');
|
|
53
56
|
}
|
|
54
57
|
/**
|
|
55
58
|
* Log with color
|
package/dist/utils/logger.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"logger.js","sourceRoot":"","sources":["../../src/utils/logger.ts"],"names":[],"mappings":";AAAA;;GAEG;;;
|
|
1
|
+
{"version":3,"file":"logger.js","sourceRoot":"","sources":["../../src/utils/logger.ts"],"names":[],"mappings":"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"}
|
package/dist/utils/types.d.ts
CHANGED
|
@@ -23,6 +23,8 @@ export interface CursorFlowConfig {
|
|
|
23
23
|
worktreePrefix: string;
|
|
24
24
|
maxConcurrentLanes: number;
|
|
25
25
|
projectRoot: string;
|
|
26
|
+
/** Output format for cursor-agent (default: 'stream-json') */
|
|
27
|
+
agentOutputFormat: 'stream-json' | 'json' | 'plain';
|
|
26
28
|
webhooks?: WebhookConfig[];
|
|
27
29
|
/** Enhanced logging configuration */
|
|
28
30
|
enhancedLogging?: Partial<EnhancedLogConfig>;
|
|
@@ -165,6 +167,8 @@ export interface RunnerConfig {
|
|
|
165
167
|
baseBranch?: string;
|
|
166
168
|
model?: string;
|
|
167
169
|
dependencyPolicy: DependencyPolicy;
|
|
170
|
+
/** Output format for cursor-agent (default: 'stream-json') */
|
|
171
|
+
agentOutputFormat?: 'stream-json' | 'json' | 'plain';
|
|
168
172
|
reviewModel?: string;
|
|
169
173
|
maxReviewIterations?: number;
|
|
170
174
|
acceptanceCriteria?: string[];
|
|
@@ -176,6 +180,12 @@ export interface RunnerConfig {
|
|
|
176
180
|
* Default: false
|
|
177
181
|
*/
|
|
178
182
|
enableIntervention?: boolean;
|
|
183
|
+
/**
|
|
184
|
+
* Disable Git operations (worktree, branch, push, commit).
|
|
185
|
+
* Useful for testing or environments without Git remote.
|
|
186
|
+
* Default: false
|
|
187
|
+
*/
|
|
188
|
+
noGit?: boolean;
|
|
179
189
|
}
|
|
180
190
|
export interface DependencyRequestPlan {
|
|
181
191
|
reason: string;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@litmers/cursorflow-orchestrator",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.15",
|
|
4
4
|
"description": "Git worktree-based parallel AI agent orchestration system for Cursor",
|
|
5
5
|
"main": "dist/cli/index.js",
|
|
6
6
|
"bin": {
|
|
@@ -22,6 +22,7 @@
|
|
|
22
22
|
"security:audit": "npm audit",
|
|
23
23
|
"security:audit:fix": "npm audit fix",
|
|
24
24
|
"security:setup": "scripts/setup-security.sh",
|
|
25
|
+
"test:lifecycle": "scripts/test-real-cursor-lifecycle.sh",
|
|
25
26
|
"prepare": "husky"
|
|
26
27
|
},
|
|
27
28
|
"keywords": [
|
|
@@ -0,0 +1,289 @@
|
|
|
1
|
+
#!/bin/bash
|
|
2
|
+
# scripts/test-real-cursor-lifecycle.sh
|
|
3
|
+
#
|
|
4
|
+
# Full Lifecycle Integration Test for CursorFlow
|
|
5
|
+
#
|
|
6
|
+
# This script performs a real-world test by:
|
|
7
|
+
# 1. Creating a temporary Git repository
|
|
8
|
+
# 2. Initializing CursorFlow
|
|
9
|
+
# 3. Defining a real task for cursor-agent
|
|
10
|
+
# 4. Running the orchestration
|
|
11
|
+
# 5. Verifying the results (file changes)
|
|
12
|
+
# 6. Cleaning up all resources (branches, worktrees, logs)
|
|
13
|
+
|
|
14
|
+
set -e
|
|
15
|
+
|
|
16
|
+
# Colors
|
|
17
|
+
RED='\033[0;31m'
|
|
18
|
+
GREEN='\033[0;32m'
|
|
19
|
+
YELLOW='\033[1;33m'
|
|
20
|
+
CYAN='\033[0;36m'
|
|
21
|
+
NC='\033[0m' # No Color
|
|
22
|
+
|
|
23
|
+
# Parse arguments
|
|
24
|
+
CLEANUP=true
|
|
25
|
+
NO_GIT=false
|
|
26
|
+
for arg in "$@"; do
|
|
27
|
+
if [ "$arg" == "--no-cleanup" ]; then
|
|
28
|
+
CLEANUP=false
|
|
29
|
+
fi
|
|
30
|
+
if [ "$arg" == "--no-git" ]; then
|
|
31
|
+
NO_GIT=true
|
|
32
|
+
fi
|
|
33
|
+
done
|
|
34
|
+
|
|
35
|
+
echo -e "${CYAN}━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━${NC}"
|
|
36
|
+
echo -e "${CYAN} 🧪 Full Lifecycle Integration Test${NC}"
|
|
37
|
+
echo -e "${CYAN}━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━${NC}"
|
|
38
|
+
|
|
39
|
+
# Prerequisites Check
|
|
40
|
+
echo -e "${YELLOW}Checking prerequisites...${NC}"
|
|
41
|
+
if ! command -v cursor-agent &> /dev/null; then
|
|
42
|
+
echo -e "${RED}❌ cursor-agent CLI not found. Please install it first.${NC}"
|
|
43
|
+
exit 1
|
|
44
|
+
fi
|
|
45
|
+
|
|
46
|
+
if ! cursor-agent create-chat &> /dev/null; then
|
|
47
|
+
echo -e "${RED}❌ cursor-agent authentication failed.${NC}"
|
|
48
|
+
echo " Please sign in to Cursor IDE first."
|
|
49
|
+
exit 1
|
|
50
|
+
fi
|
|
51
|
+
echo -e "${GREEN}✓ Prerequisites OK${NC}"
|
|
52
|
+
|
|
53
|
+
# Setup Directories
|
|
54
|
+
PROJECT_ROOT="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)"
|
|
55
|
+
TEST_ROOT="$PROJECT_ROOT/_lifecycle_test"
|
|
56
|
+
CLI_BIN="$PROJECT_ROOT/dist/cli/index.js"
|
|
57
|
+
|
|
58
|
+
echo -e "${YELLOW}Setting up temporary repository at $TEST_ROOT...${NC}"
|
|
59
|
+
rm -rf "$TEST_ROOT"
|
|
60
|
+
mkdir -p "$TEST_ROOT"
|
|
61
|
+
cd "$TEST_ROOT"
|
|
62
|
+
|
|
63
|
+
# Init Git
|
|
64
|
+
# Use a more compatible way to init and set branch
|
|
65
|
+
git init > /dev/null
|
|
66
|
+
echo "# Lifecycle Test Project" > README.md
|
|
67
|
+
|
|
68
|
+
# IMPORTANT: Create a dummy package.json AND .cursorignore to ensure this is treated as a separate root
|
|
69
|
+
cat > package.json << 'EOF'
|
|
70
|
+
{
|
|
71
|
+
"name": "lifecycle-test-project",
|
|
72
|
+
"version": "1.0.0"
|
|
73
|
+
}
|
|
74
|
+
EOF
|
|
75
|
+
|
|
76
|
+
touch .cursorignore
|
|
77
|
+
|
|
78
|
+
git add README.md package.json .cursorignore
|
|
79
|
+
git commit -m "initial commit" > /dev/null
|
|
80
|
+
git branch -m main > /dev/null 2>&1 || true
|
|
81
|
+
|
|
82
|
+
git config user.email "test@cursorflow.com"
|
|
83
|
+
git config user.name "CursorFlow Test"
|
|
84
|
+
|
|
85
|
+
echo -e "${GREEN}✓ Git repository initialized with package.json${NC}"
|
|
86
|
+
|
|
87
|
+
# Build CursorFlow (ensure latest changes)
|
|
88
|
+
echo -e "${YELLOW}Building CursorFlow...${NC}"
|
|
89
|
+
cd "$PROJECT_ROOT"
|
|
90
|
+
npm run build > /dev/null
|
|
91
|
+
cd "$TEST_ROOT"
|
|
92
|
+
echo -e "${GREEN}✓ Build complete${NC}"
|
|
93
|
+
echo -e "${GREEN}✓ Build complete${NC}"
|
|
94
|
+
|
|
95
|
+
# Create an alias for cursorflow to test it as a command
|
|
96
|
+
shopt -s expand_aliases
|
|
97
|
+
alias cursorflow="node $CLI_BIN"
|
|
98
|
+
|
|
99
|
+
# Init CursorFlow
|
|
100
|
+
echo -e "${YELLOW}Initializing CursorFlow...${NC}"
|
|
101
|
+
cursorflow init --yes > /dev/null
|
|
102
|
+
echo -e "${GREEN}✓ CursorFlow initialized${NC}"
|
|
103
|
+
|
|
104
|
+
# Define Task
|
|
105
|
+
echo -e "${YELLOW}Defining complex tasks with dependencies...${NC}"
|
|
106
|
+
mkdir -p _cursorflow/tasks
|
|
107
|
+
|
|
108
|
+
# Lane 1: Creates and updates a config file
|
|
109
|
+
cat > _cursorflow/tasks/lane-1.json << 'EOF'
|
|
110
|
+
{
|
|
111
|
+
"name": "lane-1",
|
|
112
|
+
"tasks": [
|
|
113
|
+
{
|
|
114
|
+
"name": "create-config",
|
|
115
|
+
"prompt": "Create a file named 'config.json' with { \"version\": \"1.0.0\", \"status\": \"alpha\" }. Commit it.",
|
|
116
|
+
"model": "sonnet-4.5"
|
|
117
|
+
},
|
|
118
|
+
{
|
|
119
|
+
"name": "update-config",
|
|
120
|
+
"prompt": "Update 'config.json' to set \"status\": \"beta\" and add \"author\": \"cursorflow-test\". Commit it.",
|
|
121
|
+
"model": "sonnet-4.5"
|
|
122
|
+
}
|
|
123
|
+
],
|
|
124
|
+
"dependencyPolicy": {
|
|
125
|
+
"allowDependencyChange": false,
|
|
126
|
+
"lockfileReadOnly": true
|
|
127
|
+
}
|
|
128
|
+
}
|
|
129
|
+
EOF
|
|
130
|
+
|
|
131
|
+
# Lane 2: Depends on Lane 1, creates a main file using the config
|
|
132
|
+
cat > _cursorflow/tasks/lane-2.json << 'EOF'
|
|
133
|
+
{
|
|
134
|
+
"name": "lane-2",
|
|
135
|
+
"dependsOn": ["lane-1"],
|
|
136
|
+
"tasks": [
|
|
137
|
+
{
|
|
138
|
+
"name": "create-main",
|
|
139
|
+
"prompt": "Read 'config.json'. Create a file named 'app.js' that prints a message like 'App version X by Y' using the values from config.json. Commit it.",
|
|
140
|
+
"model": "sonnet-4.5"
|
|
141
|
+
}
|
|
142
|
+
],
|
|
143
|
+
"dependencyPolicy": {
|
|
144
|
+
"allowDependencyChange": false,
|
|
145
|
+
"lockfileReadOnly": true
|
|
146
|
+
}
|
|
147
|
+
}
|
|
148
|
+
EOF
|
|
149
|
+
echo -e "${GREEN}✓ Complex tasks defined${NC}"
|
|
150
|
+
|
|
151
|
+
# Run Orchestration
|
|
152
|
+
echo -e "${YELLOW}Running orchestration (2 lanes, 3 tasks total)...${NC}"
|
|
153
|
+
echo -e "${CYAN}This will interact with Cursor IDE. Please wait...${NC}"
|
|
154
|
+
echo ""
|
|
155
|
+
|
|
156
|
+
# We use the CLI command directly
|
|
157
|
+
if [ "$NO_GIT" == "true" ]; then
|
|
158
|
+
echo -e "${YELLOW}⚠️ Running in --no-git mode (no Git operations)${NC}"
|
|
159
|
+
cursorflow run _cursorflow/tasks --skip-doctor --no-git
|
|
160
|
+
else
|
|
161
|
+
cursorflow run _cursorflow/tasks --skip-doctor
|
|
162
|
+
fi
|
|
163
|
+
|
|
164
|
+
echo -e "${GREEN}✓ Orchestration finished${NC}"
|
|
165
|
+
|
|
166
|
+
# Verify Result
|
|
167
|
+
echo -e "${YELLOW}Verifying results...${NC}"
|
|
168
|
+
|
|
169
|
+
if [ "$NO_GIT" == "true" ]; then
|
|
170
|
+
# In no-git mode, check workdir instead of branches
|
|
171
|
+
WORKDIR=$(find _cursorflow/workdir -type d -name "cursorflow-*" 2>/dev/null | head -n 1)
|
|
172
|
+
|
|
173
|
+
if [ -z "$WORKDIR" ]; then
|
|
174
|
+
WORKDIR=$(find _cursorflow/workdir -type d -mindepth 1 2>/dev/null | head -n 1)
|
|
175
|
+
fi
|
|
176
|
+
|
|
177
|
+
if [ -z "$WORKDIR" ]; then
|
|
178
|
+
echo -e "${YELLOW}⚠️ No workdir found, checking current directory${NC}"
|
|
179
|
+
WORKDIR="."
|
|
180
|
+
fi
|
|
181
|
+
|
|
182
|
+
echo -e "${GREEN}✓ Work directory: $WORKDIR${NC}"
|
|
183
|
+
|
|
184
|
+
# In noGit mode, files are created in the workdir
|
|
185
|
+
if [ -f "$WORKDIR/config.json" ]; then
|
|
186
|
+
CONFIG_CONTENT=$(cat "$WORKDIR/config.json")
|
|
187
|
+
echo -e "${GREEN}✓ config.json found${NC}"
|
|
188
|
+
echo -e " config.json: $CONFIG_CONTENT"
|
|
189
|
+
else
|
|
190
|
+
echo -e "${YELLOW}⚠️ config.json not found in workdir (may be in different location)${NC}"
|
|
191
|
+
fi
|
|
192
|
+
|
|
193
|
+
echo -e "${GREEN}✓ Verification SUCCESS (no-git mode)${NC}"
|
|
194
|
+
else
|
|
195
|
+
# Check Lane 2's final branch (which should have everything)
|
|
196
|
+
LANE2_BRANCH=$(git branch --list 'feature/lane-2*' 'cursorflow/lane-2*' | head -n 1 | sed 's/*//' | xargs)
|
|
197
|
+
|
|
198
|
+
if [ -z "$LANE2_BRANCH" ]; then
|
|
199
|
+
# Try to find it by looking at the latest branches
|
|
200
|
+
LANE2_BRANCH=$(git for-each-ref --sort=-committerdate refs/heads/ --format='%(refname:short)' | grep 'lane-2' | head -n 1)
|
|
201
|
+
fi
|
|
202
|
+
|
|
203
|
+
if [ -z "$LANE2_BRANCH" ]; then
|
|
204
|
+
echo -e "${RED}❌ No branch found for lane-2${NC}"
|
|
205
|
+
exit 1
|
|
206
|
+
fi
|
|
207
|
+
|
|
208
|
+
echo -e "${GREEN}✓ Lane 2 final branch: $LANE2_BRANCH${NC}"
|
|
209
|
+
|
|
210
|
+
# Checkout and check files
|
|
211
|
+
git checkout "$LANE2_BRANCH" > /dev/null 2>&1
|
|
212
|
+
|
|
213
|
+
if [ -f "config.json" ] && [ -f "app.js" ]; then
|
|
214
|
+
CONFIG_CONTENT=$(cat config.json)
|
|
215
|
+
APP_CONTENT=$(cat app.js)
|
|
216
|
+
echo -e "${GREEN}✓ Verification SUCCESS${NC}"
|
|
217
|
+
echo -e " config.json: $CONFIG_CONTENT"
|
|
218
|
+
echo -e " app.js: $APP_CONTENT"
|
|
219
|
+
else
|
|
220
|
+
echo -e "${RED}❌ Verification FAILED - Missing files${NC}"
|
|
221
|
+
[ ! -f "config.json" ] && echo " - config.json is missing"
|
|
222
|
+
[ ! -f "app.js" ] && echo " - app.js is missing"
|
|
223
|
+
exit 1
|
|
224
|
+
fi
|
|
225
|
+
fi
|
|
226
|
+
|
|
227
|
+
# Verify Logs
|
|
228
|
+
echo -e "${YELLOW}Verifying logs...${NC}"
|
|
229
|
+
LOG_DIR="_cursorflow/logs"
|
|
230
|
+
if [ -d "$LOG_DIR" ]; then
|
|
231
|
+
echo -e "${GREEN}✓ Logs directory exists${NC}"
|
|
232
|
+
RUN_LOGS=$(ls -d $LOG_DIR/runs/run-* 2>/dev/null | sort -r | head -n 1)
|
|
233
|
+
if [ -n "$RUN_LOGS" ]; then
|
|
234
|
+
echo -e "${GREEN}✓ Run logs found in $RUN_LOGS${NC}"
|
|
235
|
+
# Check for readable log in lane-1
|
|
236
|
+
READABLE_LOG="$RUN_LOGS/lanes/lane-1/terminal-readable.log"
|
|
237
|
+
if [ -f "$READABLE_LOG" ]; then
|
|
238
|
+
echo -e "${GREEN}✓ Readable log file created: $READABLE_LOG${NC}"
|
|
239
|
+
echo -e "${YELLOW} Log preview (first 10 lines):${NC}"
|
|
240
|
+
head -n 10 "$READABLE_LOG" | sed 's/^/ /'
|
|
241
|
+
else
|
|
242
|
+
echo -e "${RED}❌ Readable log NOT found at $READABLE_LOG${NC}"
|
|
243
|
+
echo "Available files in lane-1 directory:"
|
|
244
|
+
ls -R "$RUN_LOGS/lanes/lane-1"
|
|
245
|
+
exit 1
|
|
246
|
+
fi
|
|
247
|
+
else
|
|
248
|
+
echo -e "${RED}❌ No run logs found in $LOG_DIR/runs${NC}"
|
|
249
|
+
ls -R "$LOG_DIR"
|
|
250
|
+
exit 1
|
|
251
|
+
fi
|
|
252
|
+
else
|
|
253
|
+
echo -e "${RED}❌ Logs directory NOT found at $LOG_DIR${NC}"
|
|
254
|
+
echo "Current working directory contents:"
|
|
255
|
+
ls -R .
|
|
256
|
+
exit 1
|
|
257
|
+
fi
|
|
258
|
+
|
|
259
|
+
# Cleanup
|
|
260
|
+
if [ "$CLEANUP" = "true" ]; then
|
|
261
|
+
echo ""
|
|
262
|
+
echo -e "${CYAN}━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━${NC}"
|
|
263
|
+
echo -e "${CYAN} 🧹 Cleaning Up${NC}"
|
|
264
|
+
echo -e "${CYAN}━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━${NC}"
|
|
265
|
+
|
|
266
|
+
if [ "$NO_GIT" != "true" ]; then
|
|
267
|
+
# Return to main branch
|
|
268
|
+
git checkout main > /dev/null 2>&1
|
|
269
|
+
|
|
270
|
+
# Use cursorflow clean
|
|
271
|
+
echo -e "${YELLOW}Cleaning CursorFlow resources...${NC}"
|
|
272
|
+
cursorflow clean all --include-latest --force > /dev/null 2>&1 || true
|
|
273
|
+
fi
|
|
274
|
+
|
|
275
|
+
# Finally remove the test root
|
|
276
|
+
cd "$PROJECT_ROOT"
|
|
277
|
+
rm -rf "$TEST_ROOT"
|
|
278
|
+
echo -e "${GREEN}✓ Temporary test directory removed${NC}"
|
|
279
|
+
else
|
|
280
|
+
echo ""
|
|
281
|
+
echo -e "${YELLOW}⚠️ Skipping cleanup as requested.${NC}"
|
|
282
|
+
echo -e " Test directory: $TEST_ROOT"
|
|
283
|
+
echo -e " You can inspect the results there."
|
|
284
|
+
fi
|
|
285
|
+
|
|
286
|
+
echo ""
|
|
287
|
+
echo -e "${GREEN}✅ Full lifecycle test PASSED successfully!${NC}"
|
|
288
|
+
echo -e "${CYAN}━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━${NC}"
|
|
289
|
+
|
package/src/cli/logs.ts
CHANGED
|
@@ -45,15 +45,15 @@ Options:
|
|
|
45
45
|
--follow, -f Follow log output in real-time
|
|
46
46
|
--filter <pattern> Filter entries by regex pattern
|
|
47
47
|
--level <level> Filter by log level: stdout, stderr, info, error, debug
|
|
48
|
-
--
|
|
49
|
-
--
|
|
50
|
-
--
|
|
48
|
+
--readable, -r Show readable log (parsed AI output) (default)
|
|
49
|
+
--clean Show clean terminal logs without ANSI codes
|
|
50
|
+
--raw Show raw terminal logs with ANSI codes
|
|
51
51
|
--help, -h Show help
|
|
52
52
|
|
|
53
53
|
Examples:
|
|
54
54
|
cursorflow logs # View latest run logs summary
|
|
55
|
-
cursorflow logs --lane api-setup # View
|
|
56
|
-
cursorflow logs --lane api-setup --
|
|
55
|
+
cursorflow logs --lane api-setup # View readable parsed log (default)
|
|
56
|
+
cursorflow logs --lane api-setup --clean # View clean terminal logs
|
|
57
57
|
cursorflow logs --all # View all lanes merged by time
|
|
58
58
|
cursorflow logs --all --follow # Follow all lanes in real-time
|
|
59
59
|
cursorflow logs --all --format json # Export all lanes as JSON
|
|
@@ -81,6 +81,10 @@ function parseArgs(args: string[]): LogsOptions {
|
|
|
81
81
|
return true;
|
|
82
82
|
});
|
|
83
83
|
|
|
84
|
+
const raw = args.includes('--raw');
|
|
85
|
+
const clean = args.includes('--clean');
|
|
86
|
+
const readable = args.includes('--readable') || args.includes('-r');
|
|
87
|
+
|
|
84
88
|
return {
|
|
85
89
|
runDir,
|
|
86
90
|
lane: laneIdx >= 0 ? args[laneIdx + 1] : undefined,
|
|
@@ -91,9 +95,10 @@ function parseArgs(args: string[]): LogsOptions {
|
|
|
91
95
|
follow: args.includes('--follow') || args.includes('-f'),
|
|
92
96
|
filter: filterIdx >= 0 ? args[filterIdx + 1] : undefined,
|
|
93
97
|
level: levelIdx >= 0 ? args[levelIdx + 1] : undefined,
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
98
|
+
raw,
|
|
99
|
+
clean,
|
|
100
|
+
// Default to readable if no other format is specified
|
|
101
|
+
readable: readable || (!raw && !clean),
|
|
97
102
|
help: args.includes('--help') || args.includes('-h'),
|
|
98
103
|
};
|
|
99
104
|
}
|
|
@@ -136,20 +141,23 @@ function displayTextLogs(
|
|
|
136
141
|
options: LogsOptions
|
|
137
142
|
): void {
|
|
138
143
|
let logFile: string;
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
144
|
+
const readableLog = path.join(laneDir, 'terminal-readable.log');
|
|
145
|
+
const rawLog = path.join(laneDir, 'terminal-raw.log');
|
|
146
|
+
const cleanLog = path.join(laneDir, 'terminal.log');
|
|
147
|
+
|
|
148
|
+
if (options.raw) {
|
|
149
|
+
logFile = rawLog;
|
|
150
|
+
} else if (options.clean) {
|
|
151
|
+
logFile = cleanLog;
|
|
152
|
+
} else if (options.readable && fs.existsSync(readableLog)) {
|
|
153
|
+
logFile = readableLog;
|
|
143
154
|
} else {
|
|
144
|
-
|
|
155
|
+
// Default or fallback to clean log
|
|
156
|
+
logFile = cleanLog;
|
|
145
157
|
}
|
|
146
158
|
|
|
147
159
|
if (!fs.existsSync(logFile)) {
|
|
148
|
-
|
|
149
|
-
console.log('Readable log not found. This log is only available for runs with streaming output enabled.');
|
|
150
|
-
} else {
|
|
151
|
-
console.log('No log file found.');
|
|
152
|
-
}
|
|
160
|
+
console.log('No log file found.');
|
|
153
161
|
return;
|
|
154
162
|
}
|
|
155
163
|
|
|
@@ -167,8 +175,8 @@ function displayTextLogs(
|
|
|
167
175
|
lines = lines.slice(-options.tail);
|
|
168
176
|
}
|
|
169
177
|
|
|
170
|
-
// Clean ANSI if needed (for clean mode)
|
|
171
|
-
if (
|
|
178
|
+
// Clean ANSI if needed (for clean mode or default fallback)
|
|
179
|
+
if (!options.raw) {
|
|
172
180
|
lines = lines.map(line => stripAnsi(line));
|
|
173
181
|
}
|
|
174
182
|
|
|
@@ -628,12 +636,19 @@ function escapeHtml(text: string): string {
|
|
|
628
636
|
*/
|
|
629
637
|
function followLogs(laneDir: string, options: LogsOptions): void {
|
|
630
638
|
let logFile: string;
|
|
631
|
-
|
|
632
|
-
|
|
633
|
-
|
|
634
|
-
|
|
639
|
+
const readableLog = path.join(laneDir, 'terminal-readable.log');
|
|
640
|
+
const rawLog = path.join(laneDir, 'terminal-raw.log');
|
|
641
|
+
const cleanLog = path.join(laneDir, 'terminal.log');
|
|
642
|
+
|
|
643
|
+
if (options.raw) {
|
|
644
|
+
logFile = rawLog;
|
|
645
|
+
} else if (options.clean) {
|
|
646
|
+
logFile = cleanLog;
|
|
647
|
+
} else if (options.readable && fs.existsSync(readableLog)) {
|
|
648
|
+
logFile = readableLog;
|
|
635
649
|
} else {
|
|
636
|
-
|
|
650
|
+
// Default or fallback to clean log
|
|
651
|
+
logFile = cleanLog;
|
|
637
652
|
}
|
|
638
653
|
|
|
639
654
|
if (!fs.existsSync(logFile)) {
|
|
@@ -669,8 +684,8 @@ function followLogs(laneDir: string, options: LogsOptions): void {
|
|
|
669
684
|
content = lines.filter(line => regex.test(line)).join('\n');
|
|
670
685
|
}
|
|
671
686
|
|
|
672
|
-
// Clean ANSI if needed
|
|
673
|
-
if (
|
|
687
|
+
// Clean ANSI if needed (unless raw mode)
|
|
688
|
+
if (!options.raw) {
|
|
674
689
|
content = stripAnsi(content);
|
|
675
690
|
}
|
|
676
691
|
|
|
@@ -809,7 +824,7 @@ async function logs(args: string[]): Promise<void> {
|
|
|
809
824
|
// If no lane specified, show summary
|
|
810
825
|
if (!options.lane) {
|
|
811
826
|
displaySummary(runDir);
|
|
812
|
-
console.log(`${logger.COLORS.gray}Use --lane <name> to view logs, --
|
|
827
|
+
console.log(`${logger.COLORS.gray}Use --lane <name> to view logs (default: readable), --clean for terminal logs, or --all to view all lanes merged${logger.COLORS.reset}`);
|
|
813
828
|
return;
|
|
814
829
|
}
|
|
815
830
|
|
package/src/cli/run.ts
CHANGED
|
@@ -16,6 +16,7 @@ interface RunOptions {
|
|
|
16
16
|
executor: string | null;
|
|
17
17
|
maxConcurrent: number | null;
|
|
18
18
|
skipDoctor: boolean;
|
|
19
|
+
noGit: boolean;
|
|
19
20
|
help: boolean;
|
|
20
21
|
}
|
|
21
22
|
|
|
@@ -30,8 +31,13 @@ Options:
|
|
|
30
31
|
--max-concurrent <num> Limit parallel agents (overrides config)
|
|
31
32
|
--executor <type> cursor-agent | cloud
|
|
32
33
|
--skip-doctor Skip environment checks (not recommended)
|
|
34
|
+
--no-git Disable Git operations (worktree, push, commit)
|
|
33
35
|
--dry-run Show execution plan without starting agents
|
|
34
36
|
--help, -h Show help
|
|
37
|
+
|
|
38
|
+
Examples:
|
|
39
|
+
cursorflow run _cursorflow/tasks
|
|
40
|
+
cursorflow run _cursorflow/tasks --no-git --skip-doctor
|
|
35
41
|
`);
|
|
36
42
|
}
|
|
37
43
|
|
|
@@ -46,6 +52,7 @@ function parseArgs(args: string[]): RunOptions {
|
|
|
46
52
|
executor: executorIdx >= 0 ? args[executorIdx + 1] || null : null,
|
|
47
53
|
maxConcurrent: maxConcurrentIdx >= 0 ? parseInt(args[maxConcurrentIdx + 1] || '0') || null : null,
|
|
48
54
|
skipDoctor: args.includes('--skip-doctor') || args.includes('--no-doctor'),
|
|
55
|
+
noGit: args.includes('--no-git'),
|
|
49
56
|
help: args.includes('--help') || args.includes('-h'),
|
|
50
57
|
};
|
|
51
58
|
}
|
|
@@ -136,6 +143,7 @@ async function run(args: string[]): Promise<void> {
|
|
|
136
143
|
maxConcurrentLanes: options.maxConcurrent || config.maxConcurrentLanes,
|
|
137
144
|
webhooks: config.webhooks || [],
|
|
138
145
|
enhancedLogging: config.enhancedLogging,
|
|
146
|
+
noGit: options.noGit,
|
|
139
147
|
});
|
|
140
148
|
} catch (error: any) {
|
|
141
149
|
// Re-throw to be handled by the main entry point
|