@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/stop.ts
CHANGED
|
@@ -86,7 +86,15 @@ async function stop(args: string[]): Promise<void> {
|
|
|
86
86
|
return;
|
|
87
87
|
}
|
|
88
88
|
|
|
89
|
+
const originalCwd = process.cwd();
|
|
89
90
|
const config = loadConfig();
|
|
91
|
+
|
|
92
|
+
// Change current directory to project root for consistent path handling
|
|
93
|
+
if (config.projectRoot !== originalCwd) {
|
|
94
|
+
logger.debug(`Changing directory to project root: ${config.projectRoot}`);
|
|
95
|
+
process.chdir(config.projectRoot);
|
|
96
|
+
}
|
|
97
|
+
|
|
90
98
|
const logsDir = getLogsDir(config);
|
|
91
99
|
const runsDir = safeJoin(logsDir, 'runs');
|
|
92
100
|
const runService = new RunService(runsDir);
|
package/src/cli/tasks.ts
CHANGED
|
@@ -2,36 +2,55 @@
|
|
|
2
2
|
* CursorFlow tasks command
|
|
3
3
|
*
|
|
4
4
|
* Usage:
|
|
5
|
-
* cursorflow tasks # List all tasks
|
|
6
|
-
* cursorflow tasks --
|
|
7
|
-
* cursorflow tasks
|
|
5
|
+
* cursorflow tasks # List all flows (new) and tasks (legacy)
|
|
6
|
+
* cursorflow tasks --flows # List only flows
|
|
7
|
+
* cursorflow tasks --legacy # List only legacy tasks
|
|
8
|
+
* cursorflow tasks --validate # List with validation
|
|
9
|
+
* cursorflow tasks <name> # Show detailed info
|
|
8
10
|
*/
|
|
9
11
|
|
|
12
|
+
import * as fs from 'fs';
|
|
13
|
+
import * as path from 'path';
|
|
10
14
|
import * as logger from '../utils/logger';
|
|
11
15
|
import { TaskService, TaskDirInfo, ValidationStatus } from '../utils/task-service';
|
|
12
|
-
import { findProjectRoot, loadConfig, getTasksDir } from '../utils/config';
|
|
16
|
+
import { findProjectRoot, loadConfig, getTasksDir, getFlowsDir } from '../utils/config';
|
|
17
|
+
import { safeJoin } from '../utils/path';
|
|
13
18
|
|
|
14
19
|
const COLORS = logger.COLORS;
|
|
15
20
|
|
|
21
|
+
interface FlowInfo {
|
|
22
|
+
id: string;
|
|
23
|
+
name: string;
|
|
24
|
+
path: string;
|
|
25
|
+
timestamp: Date;
|
|
26
|
+
lanes: string[];
|
|
27
|
+
status: string;
|
|
28
|
+
}
|
|
29
|
+
|
|
16
30
|
interface TasksCliOptions {
|
|
17
31
|
validate: boolean;
|
|
18
32
|
taskName: string | null;
|
|
33
|
+
flowsOnly: boolean;
|
|
34
|
+
legacyOnly: boolean;
|
|
19
35
|
}
|
|
20
36
|
|
|
21
37
|
function printHelp(): void {
|
|
22
38
|
console.log(`
|
|
23
|
-
Usage: cursorflow tasks [options] [
|
|
39
|
+
Usage: cursorflow tasks [options] [name]
|
|
24
40
|
|
|
25
|
-
|
|
41
|
+
List and view flows (new) and prepared tasks (legacy).
|
|
26
42
|
|
|
27
43
|
Options:
|
|
28
|
-
--
|
|
44
|
+
--flows Show only flows (from _cursorflow/flows/)
|
|
45
|
+
--legacy Show only legacy tasks (from _cursorflow/tasks/)
|
|
46
|
+
--validate Run validation before listing
|
|
29
47
|
--help, -h Show help
|
|
30
48
|
|
|
31
49
|
Examples:
|
|
32
|
-
cursorflow tasks
|
|
33
|
-
cursorflow tasks --
|
|
34
|
-
cursorflow tasks
|
|
50
|
+
cursorflow tasks # List all flows and tasks
|
|
51
|
+
cursorflow tasks --flows # List only flows
|
|
52
|
+
cursorflow tasks TestFeature # Show flow or task details
|
|
53
|
+
cursorflow tasks --validate # Validate all entries
|
|
35
54
|
`);
|
|
36
55
|
}
|
|
37
56
|
|
|
@@ -39,6 +58,8 @@ function parseArgs(args: string[]): TasksCliOptions {
|
|
|
39
58
|
const options: TasksCliOptions = {
|
|
40
59
|
validate: args.includes('--validate'),
|
|
41
60
|
taskName: null,
|
|
61
|
+
flowsOnly: args.includes('--flows'),
|
|
62
|
+
legacyOnly: args.includes('--legacy'),
|
|
42
63
|
};
|
|
43
64
|
|
|
44
65
|
const nameArg = args.find(arg => !arg.startsWith('-'));
|
|
@@ -54,6 +75,136 @@ function parseArgs(args: string[]): TasksCliOptions {
|
|
|
54
75
|
return options;
|
|
55
76
|
}
|
|
56
77
|
|
|
78
|
+
/**
|
|
79
|
+
* List flows from _cursorflow/flows/
|
|
80
|
+
*/
|
|
81
|
+
function listFlows(flowsDir: string): FlowInfo[] {
|
|
82
|
+
if (!fs.existsSync(flowsDir)) {
|
|
83
|
+
return [];
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
const dirs = fs.readdirSync(flowsDir)
|
|
87
|
+
.filter(name => {
|
|
88
|
+
const dirPath = safeJoin(flowsDir, name);
|
|
89
|
+
return fs.statSync(dirPath).isDirectory() && !name.startsWith('.');
|
|
90
|
+
})
|
|
91
|
+
.sort((a, b) => b.localeCompare(a)); // Most recent first
|
|
92
|
+
|
|
93
|
+
return dirs.map(name => {
|
|
94
|
+
const flowPath = safeJoin(flowsDir, name);
|
|
95
|
+
const metaPath = safeJoin(flowPath, 'flow.meta.json');
|
|
96
|
+
|
|
97
|
+
let meta: any = {};
|
|
98
|
+
try {
|
|
99
|
+
if (fs.existsSync(metaPath)) {
|
|
100
|
+
meta = JSON.parse(fs.readFileSync(metaPath, 'utf-8'));
|
|
101
|
+
}
|
|
102
|
+
} catch {}
|
|
103
|
+
|
|
104
|
+
// Parse flow name from directory (e.g., "001_TestFeature" -> "TestFeature")
|
|
105
|
+
const match = name.match(/^(\d+)_(.+)$/);
|
|
106
|
+
const id = match ? match[1] : name;
|
|
107
|
+
const flowName = match ? match[2] : name;
|
|
108
|
+
|
|
109
|
+
// Get lane files
|
|
110
|
+
const laneFiles = fs.readdirSync(flowPath)
|
|
111
|
+
.filter(f => f.endsWith('.json') && f !== 'flow.meta.json')
|
|
112
|
+
.map(f => {
|
|
113
|
+
const laneMatch = f.match(/^\d+-([^.]+)\.json$/);
|
|
114
|
+
return laneMatch ? laneMatch[1] : f.replace('.json', '');
|
|
115
|
+
});
|
|
116
|
+
|
|
117
|
+
return {
|
|
118
|
+
id,
|
|
119
|
+
name: flowName,
|
|
120
|
+
path: flowPath,
|
|
121
|
+
timestamp: meta.createdAt ? new Date(meta.createdAt) : new Date(),
|
|
122
|
+
lanes: laneFiles,
|
|
123
|
+
status: meta.status || 'pending',
|
|
124
|
+
};
|
|
125
|
+
});
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
/**
|
|
129
|
+
* Get flow info by name
|
|
130
|
+
*/
|
|
131
|
+
function getFlowInfo(flowsDir: string, flowName: string): FlowInfo | null {
|
|
132
|
+
const flows = listFlows(flowsDir);
|
|
133
|
+
return flows.find(f => f.name === flowName || `${f.id}_${f.name}` === flowName) || null;
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
/**
|
|
137
|
+
* Print flows list
|
|
138
|
+
*/
|
|
139
|
+
function printFlowsList(flows: FlowInfo[]): void {
|
|
140
|
+
if (flows.length === 0) {
|
|
141
|
+
logger.info('No flows found in _cursorflow/flows/');
|
|
142
|
+
return;
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
console.log(`${COLORS.bold}Flows:${COLORS.reset}`);
|
|
146
|
+
|
|
147
|
+
for (let i = 0; i < flows.length; i++) {
|
|
148
|
+
const flow = flows[i]!;
|
|
149
|
+
const prefix = i === 0 ? ' ▶' : ' ';
|
|
150
|
+
const name = `${flow.id}_${flow.name}`.padEnd(30);
|
|
151
|
+
const lanes = `${flow.lanes.length} lane${flow.lanes.length !== 1 ? 's' : ''}`.padEnd(10);
|
|
152
|
+
const status = flow.status.padEnd(10);
|
|
153
|
+
const date = formatDate(flow.timestamp);
|
|
154
|
+
|
|
155
|
+
let color = COLORS.reset;
|
|
156
|
+
if (flow.status === 'completed') color = COLORS.green;
|
|
157
|
+
else if (flow.status === 'running') color = COLORS.cyan;
|
|
158
|
+
else if (flow.status === 'failed') color = COLORS.red;
|
|
159
|
+
|
|
160
|
+
console.log(`${color}${prefix} ${name} ${lanes} ${status} ${date}${COLORS.reset}`);
|
|
161
|
+
}
|
|
162
|
+
}
|
|
163
|
+
|
|
164
|
+
/**
|
|
165
|
+
* Print flow details
|
|
166
|
+
*/
|
|
167
|
+
function printFlowDetail(flow: FlowInfo, flowsDir: string): void {
|
|
168
|
+
console.log(`${COLORS.bold}Flow: ${flow.name}${COLORS.reset}`);
|
|
169
|
+
console.log(`${COLORS.cyan}━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━${COLORS.reset}`);
|
|
170
|
+
console.log(` ID: ${flow.id}`);
|
|
171
|
+
console.log(` Status: ${flow.status}`);
|
|
172
|
+
console.log(` Path: ${flow.path}`);
|
|
173
|
+
console.log('');
|
|
174
|
+
|
|
175
|
+
if (flow.lanes.length === 0) {
|
|
176
|
+
console.log('No lanes defined.');
|
|
177
|
+
} else {
|
|
178
|
+
console.log(`${COLORS.bold}Lanes:${COLORS.reset}`);
|
|
179
|
+
for (const laneName of flow.lanes) {
|
|
180
|
+
// Read lane file for task info
|
|
181
|
+
const laneFiles = fs.readdirSync(flow.path)
|
|
182
|
+
.filter(f => f.endsWith('.json') && f !== 'flow.meta.json');
|
|
183
|
+
|
|
184
|
+
const laneFile = laneFiles.find(f => {
|
|
185
|
+
const match = f.match(/^\d+-([^.]+)\.json$/);
|
|
186
|
+
return match && match[1] === laneName;
|
|
187
|
+
});
|
|
188
|
+
|
|
189
|
+
if (laneFile) {
|
|
190
|
+
try {
|
|
191
|
+
const laneData = JSON.parse(fs.readFileSync(safeJoin(flow.path, laneFile), 'utf-8'));
|
|
192
|
+
const tasks = laneData.tasks || [];
|
|
193
|
+
const taskFlow = tasks.map((t: any) => t.name).join(' → ');
|
|
194
|
+
console.log(` ${laneName.padEnd(18)} ${COLORS.blue}[${tasks.length} tasks]${COLORS.reset} ${taskFlow}`);
|
|
195
|
+
} catch {
|
|
196
|
+
console.log(` ${laneName.padEnd(18)} ${COLORS.yellow}[error reading]${COLORS.reset}`);
|
|
197
|
+
}
|
|
198
|
+
} else {
|
|
199
|
+
console.log(` ${laneName}`);
|
|
200
|
+
}
|
|
201
|
+
}
|
|
202
|
+
}
|
|
203
|
+
|
|
204
|
+
console.log('');
|
|
205
|
+
console.log(`${COLORS.gray}Run: cursorflow run ${flow.name}${COLORS.reset}`);
|
|
206
|
+
}
|
|
207
|
+
|
|
57
208
|
function formatDate(date: Date): string {
|
|
58
209
|
const months = ['Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec'];
|
|
59
210
|
return `${months[date.getMonth()]} ${date.getDate()}`;
|
|
@@ -107,9 +258,8 @@ function printTaskDetail(info: TaskDirInfo): void {
|
|
|
107
258
|
const fileName = lane.fileName.padEnd(18);
|
|
108
259
|
const preset = `[${lane.preset}]`.padEnd(10);
|
|
109
260
|
const flow = lane.taskFlow;
|
|
110
|
-
const depends = lane.dependsOn.length > 0 ? ` ${COLORS.gray}(depends: ${lane.dependsOn.join(', ')})${COLORS.reset}` : '';
|
|
111
261
|
|
|
112
|
-
console.log(` ${fileName} ${COLORS.blue}${preset}${COLORS.reset} ${flow}
|
|
262
|
+
console.log(` ${fileName} ${COLORS.blue}${preset}${COLORS.reset} ${flow}`);
|
|
113
263
|
}
|
|
114
264
|
}
|
|
115
265
|
|
|
@@ -119,25 +269,37 @@ async function tasks(args: string[]): Promise<void> {
|
|
|
119
269
|
const options = parseArgs(args);
|
|
120
270
|
const projectRoot = findProjectRoot();
|
|
121
271
|
const config = loadConfig(projectRoot);
|
|
272
|
+
const flowsDir = getFlowsDir(config);
|
|
122
273
|
const tasksDir = getTasksDir(config);
|
|
123
274
|
const taskService = new TaskService(tasksDir);
|
|
124
275
|
|
|
276
|
+
// Check for specific flow/task by name
|
|
125
277
|
if (options.taskName) {
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
278
|
+
// First try to find as a flow
|
|
279
|
+
const flowInfo = getFlowInfo(flowsDir, options.taskName);
|
|
280
|
+
if (flowInfo) {
|
|
281
|
+
printFlowDetail(flowInfo, flowsDir);
|
|
282
|
+
return;
|
|
130
283
|
}
|
|
131
284
|
|
|
132
|
-
//
|
|
285
|
+
// Then try as a legacy task
|
|
286
|
+
const taskInfo = taskService.getTaskDirInfo(options.taskName);
|
|
287
|
+
if (taskInfo) {
|
|
133
288
|
taskService.validateTaskDir(options.taskName);
|
|
134
289
|
const updatedInfo = taskService.getTaskDirInfo(options.taskName)!;
|
|
135
|
-
|
|
136
290
|
printTaskDetail(updatedInfo);
|
|
137
|
-
|
|
138
|
-
|
|
291
|
+
return;
|
|
292
|
+
}
|
|
293
|
+
|
|
294
|
+
logger.error(`Flow or task not found: ${options.taskName}`);
|
|
295
|
+
process.exit(1);
|
|
296
|
+
}
|
|
297
|
+
|
|
298
|
+
// List flows and/or tasks
|
|
299
|
+
const flows = options.legacyOnly ? [] : listFlows(flowsDir);
|
|
300
|
+
let taskList = options.flowsOnly ? [] : taskService.listTaskDirs();
|
|
139
301
|
|
|
140
|
-
|
|
302
|
+
if (options.validate && taskList.length > 0) {
|
|
141
303
|
const spinner = logger.createSpinner('Validating tasks...');
|
|
142
304
|
spinner.start();
|
|
143
305
|
for (const task of taskList) {
|
|
@@ -147,8 +309,25 @@ async function tasks(args: string[]): Promise<void> {
|
|
|
147
309
|
taskList = taskService.listTaskDirs();
|
|
148
310
|
}
|
|
149
311
|
|
|
312
|
+
// Print results
|
|
313
|
+
if (flows.length > 0) {
|
|
314
|
+
printFlowsList(flows);
|
|
315
|
+
if (taskList.length > 0) {
|
|
316
|
+
console.log('');
|
|
317
|
+
}
|
|
318
|
+
}
|
|
319
|
+
|
|
320
|
+
if (taskList.length > 0) {
|
|
321
|
+
console.log(`${COLORS.gray}Legacy Tasks:${COLORS.reset}`);
|
|
150
322
|
printTasksList(taskList);
|
|
151
323
|
}
|
|
324
|
+
|
|
325
|
+
if (flows.length === 0 && taskList.length === 0) {
|
|
326
|
+
logger.info('No flows or tasks found.');
|
|
327
|
+
console.log('');
|
|
328
|
+
console.log('Create a new flow:');
|
|
329
|
+
console.log(' cursorflow new <FlowName> --lanes "lane1,lane2"');
|
|
330
|
+
}
|
|
152
331
|
}
|
|
153
332
|
|
|
154
333
|
export = tasks;
|
|
@@ -129,6 +129,15 @@ export interface FailureContext {
|
|
|
129
129
|
/**
|
|
130
130
|
* Analyze stall condition with multi-layer detection and escalating recovery
|
|
131
131
|
*
|
|
132
|
+
* @deprecated Use StallDetectionService from './stall-detection' instead.
|
|
133
|
+
* This function is kept for backward compatibility but will be removed in a future version.
|
|
134
|
+
*
|
|
135
|
+
* The new unified StallDetectionService provides:
|
|
136
|
+
* - Single source of truth for stall state
|
|
137
|
+
* - Automatic recovery action execution
|
|
138
|
+
* - Better heartbeat filtering
|
|
139
|
+
* - Consistent state management
|
|
140
|
+
*
|
|
132
141
|
* Recovery escalation stages:
|
|
133
142
|
* 1. Phase 0 → Phase 1: Send continue signal (after 2 min idle)
|
|
134
143
|
* 2. Phase 1 → Phase 2: Send stronger prompt (after 2 min grace)
|