@litmers/cursorflow-orchestrator 0.1.31 → 0.1.36
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 +27 -0
- package/README.md +182 -59
- package/commands/cursorflow-add.md +159 -0
- package/commands/cursorflow-doctor.md +45 -23
- package/commands/cursorflow-monitor.md +23 -2
- package/commands/cursorflow-new.md +87 -0
- package/commands/cursorflow-run.md +60 -111
- package/dist/cli/add.d.ts +7 -0
- package/dist/cli/add.js +377 -0
- package/dist/cli/add.js.map +1 -0
- package/dist/cli/clean.js +1 -0
- package/dist/cli/clean.js.map +1 -1
- package/dist/cli/config.d.ts +7 -0
- package/dist/cli/config.js +181 -0
- package/dist/cli/config.js.map +1 -0
- package/dist/cli/doctor.js +47 -4
- package/dist/cli/doctor.js.map +1 -1
- package/dist/cli/index.js +34 -30
- package/dist/cli/index.js.map +1 -1
- package/dist/cli/logs.js +17 -34
- package/dist/cli/logs.js.map +1 -1
- package/dist/cli/monitor.js +62 -65
- package/dist/cli/monitor.js.map +1 -1
- package/dist/cli/new.d.ts +7 -0
- package/dist/cli/new.js +232 -0
- package/dist/cli/new.js.map +1 -0
- package/dist/cli/prepare.js +95 -193
- package/dist/cli/prepare.js.map +1 -1
- package/dist/cli/resume.js +57 -68
- package/dist/cli/resume.js.map +1 -1
- package/dist/cli/run.js +60 -30
- package/dist/cli/run.js.map +1 -1
- package/dist/cli/stop.js +6 -0
- package/dist/cli/stop.js.map +1 -1
- package/dist/cli/tasks.d.ts +5 -3
- package/dist/cli/tasks.js +181 -29
- package/dist/cli/tasks.js.map +1 -1
- package/dist/core/failure-policy.d.ts +9 -0
- package/dist/core/failure-policy.js +9 -0
- package/dist/core/failure-policy.js.map +1 -1
- package/dist/core/orchestrator.d.ts +20 -6
- package/dist/core/orchestrator.js +215 -334
- package/dist/core/orchestrator.js.map +1 -1
- package/dist/core/runner/agent.d.ts +27 -0
- package/dist/core/runner/agent.js +294 -0
- package/dist/core/runner/agent.js.map +1 -0
- package/dist/core/runner/index.d.ts +5 -0
- package/dist/core/runner/index.js +22 -0
- package/dist/core/runner/index.js.map +1 -0
- package/dist/core/runner/pipeline.d.ts +9 -0
- package/dist/core/runner/pipeline.js +539 -0
- package/dist/core/runner/pipeline.js.map +1 -0
- package/dist/core/runner/prompt.d.ts +25 -0
- package/dist/core/runner/prompt.js +175 -0
- package/dist/core/runner/prompt.js.map +1 -0
- package/dist/core/runner/task.d.ts +26 -0
- package/dist/core/runner/task.js +283 -0
- package/dist/core/runner/task.js.map +1 -0
- package/dist/core/runner/utils.d.ts +37 -0
- package/dist/core/runner/utils.js +161 -0
- package/dist/core/runner/utils.js.map +1 -0
- package/dist/core/runner.d.ts +2 -96
- package/dist/core/runner.js +11 -1136
- package/dist/core/runner.js.map +1 -1
- package/dist/core/stall-detection.d.ts +326 -0
- package/dist/core/stall-detection.js +781 -0
- package/dist/core/stall-detection.js.map +1 -0
- package/dist/services/logging/console.js +2 -1
- package/dist/services/logging/console.js.map +1 -1
- package/dist/types/config.d.ts +6 -6
- package/dist/types/flow.d.ts +84 -0
- package/dist/types/flow.js +10 -0
- package/dist/types/flow.js.map +1 -0
- package/dist/types/index.d.ts +1 -0
- package/dist/types/index.js +3 -3
- package/dist/types/index.js.map +1 -1
- package/dist/types/lane.d.ts +0 -2
- package/dist/types/logging.d.ts +5 -1
- package/dist/types/task.d.ts +7 -11
- package/dist/utils/config.d.ts +5 -1
- package/dist/utils/config.js +15 -16
- package/dist/utils/config.js.map +1 -1
- package/dist/utils/dependency.d.ts +36 -1
- package/dist/utils/dependency.js +256 -1
- package/dist/utils/dependency.js.map +1 -1
- package/dist/utils/doctor.js +40 -8
- package/dist/utils/doctor.js.map +1 -1
- package/dist/utils/enhanced-logger.d.ts +45 -82
- package/dist/utils/enhanced-logger.js +239 -844
- package/dist/utils/enhanced-logger.js.map +1 -1
- package/dist/utils/flow.d.ts +9 -0
- package/dist/utils/flow.js +73 -0
- package/dist/utils/flow.js.map +1 -0
- package/dist/utils/git.d.ts +29 -0
- package/dist/utils/git.js +115 -5
- package/dist/utils/git.js.map +1 -1
- package/dist/utils/state.js +0 -2
- package/dist/utils/state.js.map +1 -1
- package/dist/utils/task-service.d.ts +2 -2
- package/dist/utils/task-service.js +40 -31
- package/dist/utils/task-service.js.map +1 -1
- package/package.json +4 -3
- package/src/cli/add.ts +397 -0
- package/src/cli/clean.ts +1 -0
- package/src/cli/config.ts +177 -0
- package/src/cli/doctor.ts +48 -4
- package/src/cli/index.ts +36 -32
- package/src/cli/logs.ts +20 -33
- package/src/cli/monitor.ts +70 -75
- package/src/cli/new.ts +235 -0
- package/src/cli/prepare.ts +98 -205
- package/src/cli/resume.ts +61 -76
- package/src/cli/run.ts +333 -306
- package/src/cli/stop.ts +8 -0
- package/src/cli/tasks.ts +200 -21
- package/src/core/failure-policy.ts +9 -0
- package/src/core/orchestrator.ts +279 -379
- package/src/core/runner/agent.ts +314 -0
- package/src/core/runner/index.ts +6 -0
- package/src/core/runner/pipeline.ts +567 -0
- package/src/core/runner/prompt.ts +174 -0
- package/src/core/runner/task.ts +320 -0
- package/src/core/runner/utils.ts +142 -0
- package/src/core/runner.ts +8 -1347
- package/src/core/stall-detection.ts +936 -0
- package/src/services/logging/console.ts +2 -1
- package/src/types/config.ts +6 -6
- package/src/types/flow.ts +91 -0
- package/src/types/index.ts +15 -3
- package/src/types/lane.ts +0 -2
- package/src/types/logging.ts +5 -1
- package/src/types/task.ts +7 -11
- package/src/utils/config.ts +16 -17
- package/src/utils/dependency.ts +311 -2
- package/src/utils/doctor.ts +36 -8
- package/src/utils/enhanced-logger.ts +264 -927
- package/src/utils/flow.ts +42 -0
- package/src/utils/git.ts +145 -5
- package/src/utils/state.ts +0 -2
- package/src/utils/task-service.ts +48 -40
- package/commands/cursorflow-review.md +0 -56
- package/commands/cursorflow-runs.md +0 -59
- package/dist/cli/runs.d.ts +0 -5
- package/dist/cli/runs.js +0 -214
- package/dist/cli/runs.js.map +0 -1
- package/dist/core/reviewer.d.ts +0 -66
- package/dist/core/reviewer.js +0 -265
- package/dist/core/reviewer.js.map +0 -1
- package/src/cli/runs.ts +0 -212
- package/src/core/reviewer.ts +0 -285
package/src/cli/clean.ts
CHANGED
|
@@ -165,6 +165,7 @@ async function clean(args: string[]): Promise<void> {
|
|
|
165
165
|
}
|
|
166
166
|
|
|
167
167
|
const config = loadConfig();
|
|
168
|
+
git.setVerboseGit(config.verboseGit || false);
|
|
168
169
|
const repoRoot = git.getRepoRoot();
|
|
169
170
|
const logsDir = getLogsDir(config);
|
|
170
171
|
const runsDir = safeJoin(logsDir, 'runs');
|
|
@@ -0,0 +1,177 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* CursorFlow 'config' command
|
|
3
|
+
*
|
|
4
|
+
* View and set configuration values
|
|
5
|
+
*/
|
|
6
|
+
|
|
7
|
+
import * as fs from 'fs';
|
|
8
|
+
import * as path from 'path';
|
|
9
|
+
import * as logger from '../utils/logger';
|
|
10
|
+
import { loadConfig, findProjectRoot } from '../utils/config';
|
|
11
|
+
import { safeJoin } from '../utils/path';
|
|
12
|
+
|
|
13
|
+
interface ConfigOptions {
|
|
14
|
+
key: string | null;
|
|
15
|
+
value: string | null;
|
|
16
|
+
list: boolean;
|
|
17
|
+
help: boolean;
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
function printHelp(): void {
|
|
21
|
+
console.log(`
|
|
22
|
+
\x1b[1mcursorflow config\x1b[0m - 설정 조회 및 변경
|
|
23
|
+
|
|
24
|
+
\x1b[1m사용법:\x1b[0m
|
|
25
|
+
cursorflow config # 현재 설정 보기
|
|
26
|
+
cursorflow config <key> # 특정 설정 값 보기
|
|
27
|
+
cursorflow config <key> <value> # 설정 값 변경
|
|
28
|
+
|
|
29
|
+
\x1b[1m주요 설정 키:\x1b[0m
|
|
30
|
+
defaultModel 기본 AI 모델 (예: gemini-3-flash)
|
|
31
|
+
branchPrefix 브랜치 접두사 (예: feature/)
|
|
32
|
+
executor 실행기 (cursor-agent | cloud)
|
|
33
|
+
|
|
34
|
+
\x1b[1m예시:\x1b[0m
|
|
35
|
+
# 현재 설정 보기
|
|
36
|
+
cursorflow config
|
|
37
|
+
|
|
38
|
+
# 기본 모델 확인
|
|
39
|
+
cursorflow config defaultModel
|
|
40
|
+
|
|
41
|
+
# 기본 모델 변경
|
|
42
|
+
cursorflow config defaultModel opus-4.5-thinking
|
|
43
|
+
|
|
44
|
+
\x1b[1m참고:\x1b[0m
|
|
45
|
+
설정 파일 위치: cursorflow.config.js
|
|
46
|
+
설정을 영구 저장하려면 cursorflow.config.js 파일을 직접 수정하세요.
|
|
47
|
+
`);
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
function parseArgs(args: string[]): ConfigOptions {
|
|
51
|
+
const result: ConfigOptions = {
|
|
52
|
+
key: null,
|
|
53
|
+
value: null,
|
|
54
|
+
list: false,
|
|
55
|
+
help: false,
|
|
56
|
+
};
|
|
57
|
+
|
|
58
|
+
let positionalCount = 0;
|
|
59
|
+
|
|
60
|
+
for (let i = 0; i < args.length; i++) {
|
|
61
|
+
const arg = args[i];
|
|
62
|
+
|
|
63
|
+
if (arg === '--help' || arg === '-h') {
|
|
64
|
+
result.help = true;
|
|
65
|
+
} else if (arg === '--list' || arg === '-l') {
|
|
66
|
+
result.list = true;
|
|
67
|
+
} else if (!arg.startsWith('--')) {
|
|
68
|
+
if (positionalCount === 0) {
|
|
69
|
+
result.key = arg;
|
|
70
|
+
} else if (positionalCount === 1) {
|
|
71
|
+
result.value = arg;
|
|
72
|
+
}
|
|
73
|
+
positionalCount++;
|
|
74
|
+
}
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
return result;
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
async function config(args: string[]): Promise<void> {
|
|
81
|
+
const options = parseArgs(args);
|
|
82
|
+
|
|
83
|
+
if (options.help) {
|
|
84
|
+
printHelp();
|
|
85
|
+
return;
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
const projectRoot = findProjectRoot();
|
|
89
|
+
const currentConfig = loadConfig(projectRoot);
|
|
90
|
+
const configPath = safeJoin(projectRoot, 'cursorflow.config.js');
|
|
91
|
+
|
|
92
|
+
// If setting a value
|
|
93
|
+
if (options.key && options.value) {
|
|
94
|
+
const key = options.key;
|
|
95
|
+
const value = options.value;
|
|
96
|
+
|
|
97
|
+
// Validate key exists
|
|
98
|
+
if (!(key in currentConfig)) {
|
|
99
|
+
logger.error(`알 수 없는 설정 키: ${key}`);
|
|
100
|
+
console.log('\n사용 가능한 키: defaultModel, branchPrefix, executor, ...');
|
|
101
|
+
process.exit(1);
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
// Update or create config file
|
|
105
|
+
let configContent: string;
|
|
106
|
+
|
|
107
|
+
if (fs.existsSync(configPath)) {
|
|
108
|
+
// Read existing config
|
|
109
|
+
const existingContent = fs.readFileSync(configPath, 'utf-8');
|
|
110
|
+
|
|
111
|
+
// Simple regex replace for the key
|
|
112
|
+
const keyRegex = new RegExp(`(${key}\\s*:\\s*)['"]?[^'",\\n]+['"]?`, 'g');
|
|
113
|
+
if (keyRegex.test(existingContent)) {
|
|
114
|
+
configContent = existingContent.replace(keyRegex, `$1'${value}'`);
|
|
115
|
+
} else {
|
|
116
|
+
// Add the key to the config
|
|
117
|
+
configContent = existingContent.replace(
|
|
118
|
+
/module\.exports\s*=\s*\{/,
|
|
119
|
+
`module.exports = {\n ${key}: '${value}',`
|
|
120
|
+
);
|
|
121
|
+
}
|
|
122
|
+
} else {
|
|
123
|
+
// Create new config file
|
|
124
|
+
configContent = `module.exports = {
|
|
125
|
+
${key}: '${value}',
|
|
126
|
+
};
|
|
127
|
+
`;
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
fs.writeFileSync(configPath, configContent);
|
|
131
|
+
logger.success(`✅ ${key} = '${value}' 설정됨`);
|
|
132
|
+
console.log(`\n설정 파일: ${configPath}`);
|
|
133
|
+
return;
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
// If viewing a specific key
|
|
137
|
+
if (options.key) {
|
|
138
|
+
const key = options.key;
|
|
139
|
+
|
|
140
|
+
if (!(key in currentConfig)) {
|
|
141
|
+
logger.error(`알 수 없는 설정 키: ${key}`);
|
|
142
|
+
process.exit(1);
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
const value = (currentConfig as any)[key];
|
|
146
|
+
console.log(`${key} = ${JSON.stringify(value)}`);
|
|
147
|
+
return;
|
|
148
|
+
}
|
|
149
|
+
|
|
150
|
+
// List all config
|
|
151
|
+
logger.section('CursorFlow 설정');
|
|
152
|
+
console.log('');
|
|
153
|
+
|
|
154
|
+
const importantKeys = [
|
|
155
|
+
'defaultModel',
|
|
156
|
+
'branchPrefix',
|
|
157
|
+
'executor',
|
|
158
|
+
'flowsDir',
|
|
159
|
+
'tasksDir',
|
|
160
|
+
'logsDir',
|
|
161
|
+
];
|
|
162
|
+
|
|
163
|
+
console.log('\x1b[1m주요 설정:\x1b[0m');
|
|
164
|
+
for (const key of importantKeys) {
|
|
165
|
+
const value = (currentConfig as any)[key];
|
|
166
|
+
console.log(` ${key.padEnd(20)} ${JSON.stringify(value)}`);
|
|
167
|
+
}
|
|
168
|
+
|
|
169
|
+
console.log('');
|
|
170
|
+
console.log(`설정 파일: ${configPath}`);
|
|
171
|
+
console.log('');
|
|
172
|
+
console.log('설정 변경: cursorflow config <key> <value>');
|
|
173
|
+
console.log('예: cursorflow config defaultModel opus-4.5-thinking');
|
|
174
|
+
}
|
|
175
|
+
|
|
176
|
+
export = config;
|
|
177
|
+
|
package/src/cli/doctor.ts
CHANGED
|
@@ -13,12 +13,18 @@
|
|
|
13
13
|
*/
|
|
14
14
|
|
|
15
15
|
import * as logger from '../utils/logger';
|
|
16
|
+
import * as path from 'path';
|
|
17
|
+
import * as fs from 'fs';
|
|
16
18
|
import { runDoctor, saveDoctorStatus } from '../utils/doctor';
|
|
17
19
|
import { runInteractiveAgentTest } from '../utils/cursor-agent';
|
|
20
|
+
import { loadConfig, findProjectRoot } from '../utils/config';
|
|
21
|
+
import { safeJoin } from '../utils/path';
|
|
22
|
+
import { findFlowDir } from '../utils/flow';
|
|
18
23
|
|
|
19
24
|
interface DoctorCliOptions {
|
|
20
25
|
json: boolean;
|
|
21
26
|
tasksDir: string | null;
|
|
27
|
+
flowOrTaskName: string | null;
|
|
22
28
|
executor: string | null;
|
|
23
29
|
includeCursorAgentChecks: boolean;
|
|
24
30
|
testAgent: boolean;
|
|
@@ -26,13 +32,16 @@ interface DoctorCliOptions {
|
|
|
26
32
|
|
|
27
33
|
function printHelp(): void {
|
|
28
34
|
console.log(`
|
|
29
|
-
Usage: cursorflow doctor [options]
|
|
35
|
+
Usage: cursorflow doctor [flow-name] [options]
|
|
30
36
|
|
|
31
37
|
Verify your environment is ready for CursorFlow runs.
|
|
32
38
|
|
|
39
|
+
Arguments:
|
|
40
|
+
[flow-name] Flow or task name to validate (optional)
|
|
41
|
+
|
|
33
42
|
Options:
|
|
34
43
|
--json Output machine-readable JSON
|
|
35
|
-
--tasks-dir <path>
|
|
44
|
+
--tasks-dir <path> Validate specific directory (legacy)
|
|
36
45
|
--executor <type> cursor-agent | cloud
|
|
37
46
|
--no-cursor Skip Cursor Agent install/auth checks
|
|
38
47
|
--test-agent Run interactive agent test (to approve MCP/permissions)
|
|
@@ -40,18 +49,30 @@ Options:
|
|
|
40
49
|
|
|
41
50
|
Examples:
|
|
42
51
|
cursorflow doctor
|
|
52
|
+
cursorflow doctor TestFeature
|
|
43
53
|
cursorflow doctor --test-agent
|
|
44
|
-
cursorflow doctor --tasks-dir _cursorflow/
|
|
54
|
+
cursorflow doctor --tasks-dir _cursorflow/flows/001_TestFeature
|
|
45
55
|
`);
|
|
46
56
|
}
|
|
47
57
|
|
|
48
58
|
function parseArgs(args: string[]): DoctorCliOptions {
|
|
49
59
|
const tasksDirIdx = args.indexOf('--tasks-dir');
|
|
50
60
|
const executorIdx = args.indexOf('--executor');
|
|
61
|
+
|
|
62
|
+
// Find positional argument (flow/task name)
|
|
63
|
+
// Exclude args that are values for options
|
|
64
|
+
const optionValueIndices = new Set<number>();
|
|
65
|
+
if (tasksDirIdx >= 0 && tasksDirIdx + 1 < args.length) optionValueIndices.add(tasksDirIdx + 1);
|
|
66
|
+
if (executorIdx >= 0 && executorIdx + 1 < args.length) optionValueIndices.add(executorIdx + 1);
|
|
67
|
+
|
|
68
|
+
const flowOrTaskName = args.find((arg, idx) =>
|
|
69
|
+
!arg.startsWith('--') && !optionValueIndices.has(idx)
|
|
70
|
+
) || null;
|
|
51
71
|
|
|
52
72
|
const options: DoctorCliOptions = {
|
|
53
73
|
json: args.includes('--json'),
|
|
54
74
|
tasksDir: tasksDirIdx >= 0 ? (args[tasksDirIdx + 1] || null) : null,
|
|
75
|
+
flowOrTaskName,
|
|
55
76
|
executor: executorIdx >= 0 ? (args[executorIdx + 1] || null) : null,
|
|
56
77
|
includeCursorAgentChecks: !args.includes('--no-cursor'),
|
|
57
78
|
testAgent: args.includes('--test-agent'),
|
|
@@ -117,9 +138,32 @@ async function doctor(args: string[]): Promise<void> {
|
|
|
117
138
|
process.exit(success ? 0 : 1);
|
|
118
139
|
}
|
|
119
140
|
|
|
141
|
+
// Resolve tasksDir from flow name if provided
|
|
142
|
+
let tasksDir = options.tasksDir;
|
|
143
|
+
if (!tasksDir && options.flowOrTaskName) {
|
|
144
|
+
try {
|
|
145
|
+
const config = loadConfig();
|
|
146
|
+
const flowsDir = safeJoin(config.projectRoot, config.flowsDir);
|
|
147
|
+
const foundFlow = findFlowDir(flowsDir, options.flowOrTaskName);
|
|
148
|
+
if (foundFlow) {
|
|
149
|
+
tasksDir = foundFlow;
|
|
150
|
+
} else {
|
|
151
|
+
// Try as a direct path
|
|
152
|
+
const directPath = path.resolve(process.cwd(), options.flowOrTaskName);
|
|
153
|
+
if (fs.existsSync(directPath)) {
|
|
154
|
+
tasksDir = directPath;
|
|
155
|
+
} else {
|
|
156
|
+
tasksDir = options.flowOrTaskName;
|
|
157
|
+
}
|
|
158
|
+
}
|
|
159
|
+
} catch {
|
|
160
|
+
tasksDir = options.flowOrTaskName;
|
|
161
|
+
}
|
|
162
|
+
}
|
|
163
|
+
|
|
120
164
|
const report = runDoctor({
|
|
121
165
|
cwd: process.cwd(),
|
|
122
|
-
tasksDir:
|
|
166
|
+
tasksDir: tasksDir || undefined,
|
|
123
167
|
executor: options.executor || undefined,
|
|
124
168
|
includeCursorAgentChecks: options.includeCursorAgentChecks,
|
|
125
169
|
});
|
package/src/cli/index.ts
CHANGED
|
@@ -12,6 +12,11 @@ type CommandFn = (args: string[]) => Promise<void>;
|
|
|
12
12
|
*/
|
|
13
13
|
const COMMANDS: Record<string, CommandFn> = {
|
|
14
14
|
init: require('./init'),
|
|
15
|
+
// New Flow architecture commands
|
|
16
|
+
new: require('./new'),
|
|
17
|
+
add: require('./add'),
|
|
18
|
+
config: require('./config'),
|
|
19
|
+
// Legacy prepare command (deprecated)
|
|
15
20
|
prepare: require('./prepare'),
|
|
16
21
|
run: require('./run'),
|
|
17
22
|
monitor: require('./monitor'),
|
|
@@ -21,7 +26,6 @@ const COMMANDS: Record<string, CommandFn> = {
|
|
|
21
26
|
signal: require('./signal'),
|
|
22
27
|
models: require('./models'),
|
|
23
28
|
logs: require('./logs'),
|
|
24
|
-
runs: require('./runs'),
|
|
25
29
|
tasks: require('./tasks'),
|
|
26
30
|
stop: require('./stop'),
|
|
27
31
|
setup: require('./setup-commands').main,
|
|
@@ -35,37 +39,37 @@ function printHelp(): void {
|
|
|
35
39
|
\x1b[1mUSAGE\x1b[0m
|
|
36
40
|
$ \x1b[32mcursorflow\x1b[0m <command> [options]
|
|
37
41
|
|
|
38
|
-
\x1b[
|
|
39
|
-
\x1b[
|
|
40
|
-
\x1b[
|
|
41
|
-
\x1b[
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
\x1b[
|
|
45
|
-
\x1b[
|
|
46
|
-
\x1b[33mstop\x1b[0m [run-id] [options]
|
|
47
|
-
\x1b[
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
\x1b[
|
|
51
|
-
\x1b[
|
|
52
|
-
\x1b[
|
|
53
|
-
|
|
54
|
-
\x1b[
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
\x1b[
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
$ \x1b[32mcursorflow
|
|
66
|
-
$ \x1b[32mcursorflow
|
|
67
|
-
$ \x1b[32mcursorflow
|
|
68
|
-
$ \x1b[32mcursorflow
|
|
42
|
+
\x1b[1mFLOW COMMANDS (New)\x1b[0m
|
|
43
|
+
\x1b[33mnew\x1b[0m <flow> --lanes "..." Create a new Flow with Lanes
|
|
44
|
+
\x1b[33madd\x1b[0m <flow> <lane> --task Add Tasks to a Lane
|
|
45
|
+
\x1b[33mconfig\x1b[0m [key] [value] View or set config (e.g., defaultModel)
|
|
46
|
+
|
|
47
|
+
\x1b[1mEXECUTION\x1b[0m
|
|
48
|
+
\x1b[33mrun\x1b[0m <flow> [options] Run orchestration (DAG-based)
|
|
49
|
+
\x1b[33mmonitor\x1b[0m [run-dir] [options] \x1b[36mInteractive\x1b[0m lane dashboard
|
|
50
|
+
\x1b[33mstop\x1b[0m [run-id] [options] Stop running workflows
|
|
51
|
+
\x1b[33mresume\x1b[0m [lane] [options] Resume lane(s)
|
|
52
|
+
|
|
53
|
+
\x1b[1mINSPECTION\x1b[0m
|
|
54
|
+
\x1b[33mtasks\x1b[0m [name] [options] Browse and validate prepared tasks
|
|
55
|
+
\x1b[33mlogs\x1b[0m [run-dir] [options] View, export, and follow logs
|
|
56
|
+
\x1b[33mdoctor\x1b[0m [options] Check environment and preflight
|
|
57
|
+
|
|
58
|
+
\x1b[1mUTILITY\x1b[0m
|
|
59
|
+
\x1b[33minit\x1b[0m [options] Initialize CursorFlow in project
|
|
60
|
+
\x1b[33msetup\x1b[0m [options] Install Cursor IDE commands
|
|
61
|
+
\x1b[33mclean\x1b[0m <type> [options] Clean branches/worktrees/logs/tasks
|
|
62
|
+
\x1b[33msignal\x1b[0m <lane> <msg> Directly intervene in a running lane
|
|
63
|
+
\x1b[33mmodels\x1b[0m [options] List available AI models
|
|
64
|
+
|
|
65
|
+
\x1b[1mLEGACY\x1b[0m
|
|
66
|
+
\x1b[33mprepare\x1b[0m <feature> [opts] (deprecated) Use 'new' + 'add' instead
|
|
67
|
+
|
|
68
|
+
\x1b[1mQUICK START\x1b[0m
|
|
69
|
+
$ \x1b[32mcursorflow new MyFeature --lanes "backend,frontend"\x1b[0m
|
|
70
|
+
$ \x1b[32mcursorflow add MyFeature backend --task "name=impl|model=sonnet-4.5|prompt=API 구현"\x1b[0m
|
|
71
|
+
$ \x1b[32mcursorflow add MyFeature frontend --task "name=ui|model=sonnet-4.5|prompt=UI 구현" --after "backend"\x1b[0m
|
|
72
|
+
$ \x1b[32mcursorflow run MyFeature\x1b[0m
|
|
69
73
|
|
|
70
74
|
\x1b[1mDOCUMENTATION\x1b[0m
|
|
71
75
|
https://github.com/eungjin-cigro/cursorflow#readme
|
package/src/cli/logs.ts
CHANGED
|
@@ -5,7 +5,7 @@
|
|
|
5
5
|
import * as fs from 'fs';
|
|
6
6
|
import * as path from 'path';
|
|
7
7
|
import * as logger from '../utils/logger';
|
|
8
|
-
import { loadConfig } from '../utils/config';
|
|
8
|
+
import { loadConfig, getLogsDir } from '../utils/config';
|
|
9
9
|
import { safeJoin } from '../utils/path';
|
|
10
10
|
import {
|
|
11
11
|
readJsonLog,
|
|
@@ -160,17 +160,12 @@ function displayTextLogs(
|
|
|
160
160
|
let logFile: string;
|
|
161
161
|
const readableLog = safeJoin(laneDir, 'terminal-readable.log');
|
|
162
162
|
const rawLog = safeJoin(laneDir, 'terminal-raw.log');
|
|
163
|
-
const cleanLog = safeJoin(laneDir, 'terminal.log');
|
|
164
163
|
|
|
165
164
|
if (options.raw) {
|
|
166
165
|
logFile = rawLog;
|
|
167
|
-
} else if (options.clean) {
|
|
168
|
-
logFile = cleanLog;
|
|
169
|
-
} else if (options.readable && fs.existsSync(readableLog)) {
|
|
170
|
-
logFile = readableLog;
|
|
171
166
|
} else {
|
|
172
|
-
// Default
|
|
173
|
-
logFile =
|
|
167
|
+
// Default to readable log (clean option also uses readable now)
|
|
168
|
+
logFile = readableLog;
|
|
174
169
|
}
|
|
175
170
|
|
|
176
171
|
if (!fs.existsSync(logFile)) {
|
|
@@ -686,17 +681,12 @@ function followLogs(laneDir: string, options: LogsOptions): void {
|
|
|
686
681
|
let logFile: string;
|
|
687
682
|
const readableLog = safeJoin(laneDir, 'terminal-readable.log');
|
|
688
683
|
const rawLog = safeJoin(laneDir, 'terminal-raw.log');
|
|
689
|
-
const cleanLog = safeJoin(laneDir, 'terminal.log');
|
|
690
684
|
|
|
691
685
|
if (options.raw) {
|
|
692
686
|
logFile = rawLog;
|
|
693
|
-
} else if (options.clean) {
|
|
694
|
-
logFile = cleanLog;
|
|
695
|
-
} else if (options.readable && fs.existsSync(readableLog)) {
|
|
696
|
-
logFile = readableLog;
|
|
697
687
|
} else {
|
|
698
|
-
// Default
|
|
699
|
-
logFile =
|
|
688
|
+
// Default to readable log
|
|
689
|
+
logFile = readableLog;
|
|
700
690
|
}
|
|
701
691
|
|
|
702
692
|
if (!fs.existsSync(logFile)) {
|
|
@@ -778,16 +768,14 @@ function displaySummary(runDir: string): void {
|
|
|
778
768
|
|
|
779
769
|
for (const lane of lanes) {
|
|
780
770
|
const laneDir = safeJoin(runDir, 'lanes', lane);
|
|
781
|
-
const cleanLog = safeJoin(laneDir, 'terminal.log');
|
|
782
771
|
const rawLog = safeJoin(laneDir, 'terminal-raw.log');
|
|
783
|
-
const jsonLog = safeJoin(laneDir, 'terminal.jsonl');
|
|
784
772
|
const readableLog = safeJoin(laneDir, 'terminal-readable.log');
|
|
785
773
|
|
|
786
774
|
console.log(` ${logger.COLORS.green}📁 ${lane}${logger.COLORS.reset}`);
|
|
787
775
|
|
|
788
|
-
if (fs.existsSync(
|
|
789
|
-
const stats = fs.statSync(
|
|
790
|
-
console.log(` └─ terminal.log
|
|
776
|
+
if (fs.existsSync(readableLog)) {
|
|
777
|
+
const stats = fs.statSync(readableLog);
|
|
778
|
+
console.log(` └─ terminal-readable.log ${formatSize(stats.size)} ${logger.COLORS.yellow}(default)${logger.COLORS.reset}`);
|
|
791
779
|
}
|
|
792
780
|
|
|
793
781
|
if (fs.existsSync(rawLog)) {
|
|
@@ -795,18 +783,6 @@ function displaySummary(runDir: string): void {
|
|
|
795
783
|
console.log(` └─ terminal-raw.log ${formatSize(stats.size)}`);
|
|
796
784
|
}
|
|
797
785
|
|
|
798
|
-
if (fs.existsSync(readableLog)) {
|
|
799
|
-
const stats = fs.statSync(readableLog);
|
|
800
|
-
console.log(` └─ terminal-readable.log ${formatSize(stats.size)} ${logger.COLORS.yellow}(parsed AI output)${logger.COLORS.reset}`);
|
|
801
|
-
}
|
|
802
|
-
|
|
803
|
-
if (fs.existsSync(jsonLog)) {
|
|
804
|
-
const stats = fs.statSync(jsonLog);
|
|
805
|
-
const entries = readJsonLog(jsonLog);
|
|
806
|
-
const errors = entries.filter(e => e.level === 'error' || e.level === 'stderr').length;
|
|
807
|
-
console.log(` └─ terminal.jsonl ${formatSize(stats.size)} (${entries.length} entries, ${errors} errors)`);
|
|
808
|
-
}
|
|
809
|
-
|
|
810
786
|
console.log('');
|
|
811
787
|
}
|
|
812
788
|
}
|
|
@@ -832,11 +808,22 @@ async function logs(args: string[]): Promise<void> {
|
|
|
832
808
|
}
|
|
833
809
|
|
|
834
810
|
const config = loadConfig();
|
|
811
|
+
const originalCwd = process.cwd();
|
|
812
|
+
|
|
813
|
+
// Change current directory to project root for consistent path handling
|
|
814
|
+
if (config.projectRoot !== originalCwd) {
|
|
815
|
+
logger.debug(`Changing directory to project root: ${config.projectRoot}`);
|
|
816
|
+
process.chdir(config.projectRoot);
|
|
817
|
+
}
|
|
835
818
|
|
|
836
819
|
// Find run directory
|
|
837
820
|
let runDir = options.runDir;
|
|
821
|
+
if (runDir && runDir !== 'latest' && !path.isAbsolute(runDir)) {
|
|
822
|
+
runDir = path.resolve(originalCwd, runDir);
|
|
823
|
+
}
|
|
824
|
+
|
|
838
825
|
if (!runDir || runDir === 'latest') {
|
|
839
|
-
runDir = findLatestRunDir(config
|
|
826
|
+
runDir = findLatestRunDir(getLogsDir(config)) || undefined;
|
|
840
827
|
}
|
|
841
828
|
|
|
842
829
|
if (!runDir || !fs.existsSync(runDir)) {
|