@litmers/cursorflow-orchestrator 0.2.2 → 0.2.3
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/README.md +1 -0
- package/dist/cli/index.js +0 -6
- package/dist/cli/index.js.map +1 -1
- package/dist/cli/monitor.js +18 -2
- package/dist/cli/monitor.js.map +1 -1
- package/dist/cli/signal.js +33 -29
- package/dist/cli/signal.js.map +1 -1
- package/dist/core/auto-recovery.d.ts +2 -117
- package/dist/core/auto-recovery.js +4 -487
- package/dist/core/auto-recovery.js.map +1 -1
- package/dist/core/failure-policy.d.ts +0 -52
- package/dist/core/failure-policy.js +7 -174
- package/dist/core/failure-policy.js.map +1 -1
- package/dist/core/intervention.d.ts +0 -6
- package/dist/core/intervention.js +1 -17
- package/dist/core/intervention.js.map +1 -1
- package/dist/core/orchestrator.js +10 -3
- package/dist/core/orchestrator.js.map +1 -1
- package/dist/core/runner/agent.js +18 -15
- package/dist/core/runner/agent.js.map +1 -1
- package/dist/core/stall-detection.js +9 -7
- package/dist/core/stall-detection.js.map +1 -1
- package/package.json +2 -13
- package/src/cli/index.ts +0 -6
- package/src/cli/monitor.ts +18 -2
- package/src/cli/signal.ts +38 -34
- package/src/core/auto-recovery.ts +13 -595
- package/src/core/failure-policy.ts +7 -228
- package/src/core/intervention.ts +0 -18
- package/src/core/orchestrator.ts +13 -3
- package/src/core/runner/agent.ts +21 -16
- package/src/core/stall-detection.ts +11 -9
- package/dist/cli/prepare.d.ts +0 -7
- package/dist/cli/prepare.js +0 -690
- package/dist/cli/prepare.js.map +0 -1
- package/src/cli/prepare.ts +0 -777
package/src/cli/signal.ts
CHANGED
|
@@ -19,6 +19,9 @@ import {
|
|
|
19
19
|
executeUserIntervention,
|
|
20
20
|
isProcessAlive,
|
|
21
21
|
InterventionResult,
|
|
22
|
+
createInterventionRequest,
|
|
23
|
+
InterventionType,
|
|
24
|
+
wrapUserIntervention,
|
|
22
25
|
} from '../core/intervention';
|
|
23
26
|
|
|
24
27
|
interface SignalOptions {
|
|
@@ -26,7 +29,6 @@ interface SignalOptions {
|
|
|
26
29
|
message: string | null;
|
|
27
30
|
timeout: number | null;
|
|
28
31
|
runDir: string | null;
|
|
29
|
-
force: boolean; // 프로세스 종료 없이 대기 모드로 전송
|
|
30
32
|
help: boolean;
|
|
31
33
|
}
|
|
32
34
|
|
|
@@ -35,8 +37,12 @@ function printHelp(): void {
|
|
|
35
37
|
Usage: cursorflow signal <lane> "<message>" [options]
|
|
36
38
|
cursorflow signal <lane> --timeout <ms>
|
|
37
39
|
|
|
38
|
-
|
|
39
|
-
and resume with your
|
|
40
|
+
Send an intervention message to a lane. For running lanes, the agent will be
|
|
41
|
+
interrupted immediately and resume with your message. For pending/waiting/failed
|
|
42
|
+
lanes, the message will be applied when the lane starts or resumes.
|
|
43
|
+
|
|
44
|
+
Note: Completed lanes cannot receive signals.
|
|
45
|
+
To re-run a completed lane, start a new run with: cursorflow run
|
|
40
46
|
|
|
41
47
|
Arguments:
|
|
42
48
|
<lane> Lane name to signal
|
|
@@ -45,15 +51,12 @@ Arguments:
|
|
|
45
51
|
Options:
|
|
46
52
|
--timeout <ms> Update execution timeout (in milliseconds)
|
|
47
53
|
--run-dir <path> Use a specific run directory (default: latest)
|
|
48
|
-
--force Send signal without interrupting current process
|
|
49
|
-
(message will be picked up on next task)
|
|
50
54
|
--help, -h Show help
|
|
51
55
|
|
|
52
56
|
Examples:
|
|
53
57
|
cursorflow signal lane-1 "Please focus on error handling first"
|
|
54
58
|
cursorflow signal lane-2 "Skip the optional tasks and finish"
|
|
55
59
|
cursorflow signal lane-1 --timeout 600000 # Set 10 minute timeout
|
|
56
|
-
cursorflow signal lane-1 "Continue" --force # Don't interrupt, wait for next turn
|
|
57
60
|
`);
|
|
58
61
|
}
|
|
59
62
|
|
|
@@ -61,15 +64,24 @@ function parseArgs(args: string[]): SignalOptions {
|
|
|
61
64
|
const runDirIdx = args.indexOf('--run-dir');
|
|
62
65
|
const timeoutIdx = args.indexOf('--timeout');
|
|
63
66
|
|
|
67
|
+
// Collect indices of option values to exclude from nonOptions
|
|
68
|
+
const optionValueIndices = new Set<number>();
|
|
69
|
+
if (runDirIdx >= 0 && runDirIdx + 1 < args.length) {
|
|
70
|
+
optionValueIndices.add(runDirIdx + 1);
|
|
71
|
+
}
|
|
72
|
+
if (timeoutIdx >= 0 && timeoutIdx + 1 < args.length) {
|
|
73
|
+
optionValueIndices.add(timeoutIdx + 1);
|
|
74
|
+
}
|
|
75
|
+
|
|
64
76
|
// First non-option is lane, second (or rest joined) is message
|
|
65
|
-
|
|
77
|
+
// Exclude option flags and their values
|
|
78
|
+
const nonOptions = args.filter((a, i) => !a.startsWith('--') && !optionValueIndices.has(i));
|
|
66
79
|
|
|
67
80
|
return {
|
|
68
81
|
lane: nonOptions[0] || null,
|
|
69
82
|
message: nonOptions.slice(1).join(' ') || null,
|
|
70
83
|
timeout: timeoutIdx >= 0 ? parseInt(args[timeoutIdx + 1] || '0') || null : null,
|
|
71
84
|
runDir: runDirIdx >= 0 ? args[runDirIdx + 1] || null : null,
|
|
72
|
-
force: args.includes('--force'),
|
|
73
85
|
help: args.includes('--help') || args.includes('-h'),
|
|
74
86
|
};
|
|
75
87
|
}
|
|
@@ -108,18 +120,15 @@ function getLaneStatus(laneDir: string): { state: LaneState | null; isRunning: b
|
|
|
108
120
|
}
|
|
109
121
|
|
|
110
122
|
/**
|
|
111
|
-
*
|
|
123
|
+
* 개입 요청 파일 작성 (비실행 중인 lane용)
|
|
112
124
|
*/
|
|
113
|
-
function
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
const entry = createConversationEntry('intervention', `[HUMAN INTERVENTION]: ${message}`, {
|
|
120
|
-
task: 'DIRECT_SIGNAL'
|
|
125
|
+
function sendInterventionRequest(laneDir: string, message: string): void {
|
|
126
|
+
createInterventionRequest(laneDir, {
|
|
127
|
+
type: InterventionType.USER_MESSAGE,
|
|
128
|
+
message: wrapUserIntervention(message),
|
|
129
|
+
source: 'user',
|
|
130
|
+
priority: 10
|
|
121
131
|
});
|
|
122
|
-
appendLog(convoPath, entry);
|
|
123
132
|
}
|
|
124
133
|
|
|
125
134
|
async function signal(args: string[]): Promise<void> {
|
|
@@ -167,30 +176,25 @@ async function signal(args: string[]): Promise<void> {
|
|
|
167
176
|
logger.info(`📨 Sending intervention to lane: ${options.lane}`);
|
|
168
177
|
logger.info(` Message: "${options.message.substring(0, 50)}${options.message.length > 50 ? '...' : ''}"`);
|
|
169
178
|
|
|
179
|
+
// Completed 레인은 signal 거부 (브랜치 충돌 방지)
|
|
180
|
+
if (state?.status === 'completed') {
|
|
181
|
+
logger.error(`❌ Cannot signal a completed lane.`);
|
|
182
|
+
logger.info(' To re-run this lane, start a new run with: cursorflow run');
|
|
183
|
+
throw new Error('Lane is already completed');
|
|
184
|
+
}
|
|
185
|
+
|
|
170
186
|
// Log to conversation for history
|
|
171
187
|
const entry = createConversationEntry('intervention', `[HUMAN INTERVENTION]: ${options.message}`, {
|
|
172
188
|
task: 'DIRECT_SIGNAL'
|
|
173
189
|
});
|
|
174
190
|
appendLog(convoPath, entry);
|
|
175
191
|
|
|
176
|
-
//
|
|
177
|
-
if (options.force) {
|
|
178
|
-
sendLegacyIntervention(laneDir, options.message);
|
|
179
|
-
logger.success('✅ Signal queued (--force mode). Message will be applied on next task.');
|
|
180
|
-
return;
|
|
181
|
-
}
|
|
182
|
-
|
|
183
|
-
// Lane이 실행 중이 아닌 경우
|
|
192
|
+
// Lane이 실행 중이 아닌 경우 (pending/waiting/failed/paused)
|
|
184
193
|
if (!isRunning) {
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
return;
|
|
188
|
-
}
|
|
189
|
-
|
|
190
|
-
// 실행 중이 아니면 다음 resume 시 적용되도록 파일만 작성
|
|
191
|
-
sendLegacyIntervention(laneDir, options.message);
|
|
194
|
+
// 실행 중이 아니면 다음 시작/resume 시 적용되도록 파일만 작성
|
|
195
|
+
sendInterventionRequest(laneDir, options.message);
|
|
192
196
|
logger.info(`ℹ Lane ${options.lane} is not currently running (status: ${state?.status || 'unknown'}).`);
|
|
193
|
-
logger.success('✅ Signal queued. Message will be applied when lane resumes.');
|
|
197
|
+
logger.success('✅ Signal queued. Message will be applied when lane starts or resumes.');
|
|
194
198
|
return;
|
|
195
199
|
}
|
|
196
200
|
|