@cmdctrl/cursor-cli 0.1.1
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/dist/adapter/cursor-cli.d.ts +36 -0
- package/dist/adapter/cursor-cli.d.ts.map +1 -0
- package/dist/adapter/cursor-cli.js +332 -0
- package/dist/adapter/cursor-cli.js.map +1 -0
- package/dist/adapter/events.d.ts +33 -0
- package/dist/adapter/events.d.ts.map +1 -0
- package/dist/adapter/events.js +53 -0
- package/dist/adapter/events.js.map +1 -0
- package/dist/client/messages.d.ts +50 -0
- package/dist/client/messages.d.ts.map +1 -0
- package/dist/client/messages.js +6 -0
- package/dist/client/messages.js.map +1 -0
- package/dist/client/websocket.d.ts +69 -0
- package/dist/client/websocket.d.ts.map +1 -0
- package/dist/client/websocket.js +272 -0
- package/dist/client/websocket.js.map +1 -0
- package/dist/commands/register.d.ts +10 -0
- package/dist/commands/register.d.ts.map +1 -0
- package/dist/commands/register.js +173 -0
- package/dist/commands/register.js.map +1 -0
- package/dist/commands/start.d.ts +9 -0
- package/dist/commands/start.d.ts.map +1 -0
- package/dist/commands/start.js +49 -0
- package/dist/commands/start.js.map +1 -0
- package/dist/commands/status.d.ts +5 -0
- package/dist/commands/status.d.ts.map +1 -0
- package/dist/commands/status.js +39 -0
- package/dist/commands/status.js.map +1 -0
- package/dist/commands/stop.d.ts +5 -0
- package/dist/commands/stop.d.ts.map +1 -0
- package/dist/commands/stop.js +42 -0
- package/dist/commands/stop.js.map +1 -0
- package/dist/commands/update.d.ts +2 -0
- package/dist/commands/update.d.ts.map +1 -0
- package/dist/commands/update.js +72 -0
- package/dist/commands/update.js.map +1 -0
- package/dist/config/config.d.ts +60 -0
- package/dist/config/config.d.ts.map +1 -0
- package/dist/config/config.js +176 -0
- package/dist/config/config.js.map +1 -0
- package/dist/index.d.ts +3 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +50 -0
- package/dist/index.js.map +1 -0
- package/package.json +38 -0
- package/src/adapter/cursor-cli.ts +370 -0
- package/src/adapter/events.ts +77 -0
- package/src/client/messages.ts +75 -0
- package/src/client/websocket.ts +308 -0
- package/src/commands/register.ts +199 -0
- package/src/commands/start.ts +64 -0
- package/src/commands/status.ts +46 -0
- package/src/commands/stop.ts +47 -0
- package/src/commands/update.ts +73 -0
- package/src/config/config.ts +146 -0
- package/src/index.ts +56 -0
- package/tsconfig.json +19 -0
|
@@ -0,0 +1,370 @@
|
|
|
1
|
+
import { spawn, ChildProcess } from 'child_process';
|
|
2
|
+
import * as readline from 'readline';
|
|
3
|
+
import * as fs from 'fs';
|
|
4
|
+
import * as os from 'os';
|
|
5
|
+
import * as path from 'path';
|
|
6
|
+
import { StreamEvent, extractProgressFromAction } from './events';
|
|
7
|
+
|
|
8
|
+
const DEFAULT_TIMEOUT = 10 * 60 * 1000; // 10 minutes
|
|
9
|
+
|
|
10
|
+
// Find cursor-agent CLI in common locations
|
|
11
|
+
function findCursorCli(): string {
|
|
12
|
+
if (process.env.CURSOR_CLI_PATH) {
|
|
13
|
+
return process.env.CURSOR_CLI_PATH;
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
const home = os.homedir();
|
|
17
|
+
const commonPaths = [
|
|
18
|
+
path.join(home, '.cursor', 'bin', 'cursor-agent'),
|
|
19
|
+
path.join(home, '.local', 'bin', 'cursor-agent'),
|
|
20
|
+
'/usr/local/bin/cursor-agent',
|
|
21
|
+
'/opt/homebrew/bin/cursor-agent',
|
|
22
|
+
'cursor-agent' // Fall back to PATH
|
|
23
|
+
];
|
|
24
|
+
|
|
25
|
+
for (const p of commonPaths) {
|
|
26
|
+
if (p === 'cursor-agent') return p; // PATH fallback
|
|
27
|
+
try {
|
|
28
|
+
if (fs.existsSync(p)) {
|
|
29
|
+
return p;
|
|
30
|
+
}
|
|
31
|
+
} catch {
|
|
32
|
+
continue;
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
return 'cursor-agent'; // Fall back to PATH
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
const CLI_PATH = findCursorCli();
|
|
40
|
+
console.log(`[CursorAdapter] Using CLI path: ${CLI_PATH}`);
|
|
41
|
+
|
|
42
|
+
interface RunningTask {
|
|
43
|
+
taskId: string;
|
|
44
|
+
sessionId: string;
|
|
45
|
+
question: string;
|
|
46
|
+
context: string;
|
|
47
|
+
process: ChildProcess | null;
|
|
48
|
+
timeoutHandle: NodeJS.Timeout | null;
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
type EventCallback = (
|
|
52
|
+
taskId: string,
|
|
53
|
+
eventType: string,
|
|
54
|
+
data: Record<string, unknown>
|
|
55
|
+
) => void;
|
|
56
|
+
|
|
57
|
+
export class CursorAdapter {
|
|
58
|
+
private running: Map<string, RunningTask> = new Map();
|
|
59
|
+
private onEvent: EventCallback;
|
|
60
|
+
|
|
61
|
+
constructor(onEvent: EventCallback) {
|
|
62
|
+
this.onEvent = onEvent;
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
/**
|
|
66
|
+
* Start a new task
|
|
67
|
+
*/
|
|
68
|
+
async startTask(
|
|
69
|
+
taskId: string,
|
|
70
|
+
instruction: string,
|
|
71
|
+
projectPath?: string
|
|
72
|
+
): Promise<void> {
|
|
73
|
+
console.log(`[${taskId}] Starting task: ${instruction.substring(0, 50)}...`);
|
|
74
|
+
|
|
75
|
+
const rt: RunningTask = {
|
|
76
|
+
taskId,
|
|
77
|
+
sessionId: '',
|
|
78
|
+
question: '',
|
|
79
|
+
context: '',
|
|
80
|
+
process: null,
|
|
81
|
+
timeoutHandle: null
|
|
82
|
+
};
|
|
83
|
+
|
|
84
|
+
this.running.set(taskId, rt);
|
|
85
|
+
|
|
86
|
+
// Validate cwd exists
|
|
87
|
+
let cwd: string | undefined = undefined;
|
|
88
|
+
if (projectPath && fs.existsSync(projectPath)) {
|
|
89
|
+
cwd = projectPath;
|
|
90
|
+
} else if (projectPath) {
|
|
91
|
+
console.log(`[${taskId}] Warning: project path does not exist: ${projectPath}, using home dir`);
|
|
92
|
+
cwd = os.homedir();
|
|
93
|
+
this.onEvent(taskId, 'WARNING', {
|
|
94
|
+
warning: `Project path "${projectPath}" does not exist. Running in home directory instead.`
|
|
95
|
+
});
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
// Build command arguments for Cursor CLI
|
|
99
|
+
// cursor-agent -p "instruction" --output-format stream-json
|
|
100
|
+
const args = [
|
|
101
|
+
'-p', instruction,
|
|
102
|
+
'--output-format', 'stream-json'
|
|
103
|
+
];
|
|
104
|
+
|
|
105
|
+
console.log(`[${taskId}] Spawning: ${CLI_PATH} with cwd: ${cwd || 'default'}`);
|
|
106
|
+
|
|
107
|
+
// Spawn Cursor CLI
|
|
108
|
+
const proc = spawn(CLI_PATH, args, {
|
|
109
|
+
cwd,
|
|
110
|
+
stdio: ['ignore', 'pipe', 'pipe'],
|
|
111
|
+
env: {
|
|
112
|
+
...process.env,
|
|
113
|
+
// Pass through Cursor API key if set
|
|
114
|
+
CURSOR_API_KEY: process.env.CURSOR_API_KEY
|
|
115
|
+
}
|
|
116
|
+
});
|
|
117
|
+
|
|
118
|
+
rt.process = proc;
|
|
119
|
+
|
|
120
|
+
// Set timeout
|
|
121
|
+
rt.timeoutHandle = setTimeout(() => {
|
|
122
|
+
console.log(`[${taskId}] Task timed out`);
|
|
123
|
+
proc.kill('SIGKILL');
|
|
124
|
+
this.onEvent(taskId, 'ERROR', { error: 'execution timeout' });
|
|
125
|
+
}, DEFAULT_TIMEOUT);
|
|
126
|
+
|
|
127
|
+
// Handle process events
|
|
128
|
+
this.handleProcessOutput(taskId, proc, rt);
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
/**
|
|
132
|
+
* Resume a task with user's reply
|
|
133
|
+
*/
|
|
134
|
+
async resumeTask(
|
|
135
|
+
taskId: string,
|
|
136
|
+
sessionId: string,
|
|
137
|
+
message: string,
|
|
138
|
+
projectPath?: string
|
|
139
|
+
): Promise<void> {
|
|
140
|
+
console.log(`[${taskId}] Resuming task with session ${sessionId}`);
|
|
141
|
+
|
|
142
|
+
const rt: RunningTask = {
|
|
143
|
+
taskId,
|
|
144
|
+
sessionId,
|
|
145
|
+
question: '',
|
|
146
|
+
context: '',
|
|
147
|
+
process: null,
|
|
148
|
+
timeoutHandle: null
|
|
149
|
+
};
|
|
150
|
+
|
|
151
|
+
this.running.set(taskId, rt);
|
|
152
|
+
|
|
153
|
+
// Validate cwd exists
|
|
154
|
+
let cwd: string | undefined = undefined;
|
|
155
|
+
if (projectPath && fs.existsSync(projectPath)) {
|
|
156
|
+
cwd = projectPath;
|
|
157
|
+
} else if (projectPath) {
|
|
158
|
+
console.log(`[${taskId}] Warning: project path does not exist: ${projectPath}, using home dir`);
|
|
159
|
+
cwd = os.homedir();
|
|
160
|
+
}
|
|
161
|
+
|
|
162
|
+
// Build command arguments with --resume
|
|
163
|
+
// cursor-agent --resume="session-id" -p "user response" --output-format stream-json
|
|
164
|
+
const args = [
|
|
165
|
+
`--resume=${sessionId}`,
|
|
166
|
+
'-p', message,
|
|
167
|
+
'--output-format', 'stream-json'
|
|
168
|
+
];
|
|
169
|
+
|
|
170
|
+
console.log(`[${taskId}] Spawning resume: ${CLI_PATH} --resume=${sessionId} with cwd: ${cwd || 'default'}`);
|
|
171
|
+
|
|
172
|
+
// Spawn Cursor CLI
|
|
173
|
+
const proc = spawn(CLI_PATH, args, {
|
|
174
|
+
cwd,
|
|
175
|
+
stdio: ['ignore', 'pipe', 'pipe'],
|
|
176
|
+
env: {
|
|
177
|
+
...process.env,
|
|
178
|
+
CURSOR_API_KEY: process.env.CURSOR_API_KEY
|
|
179
|
+
}
|
|
180
|
+
});
|
|
181
|
+
|
|
182
|
+
rt.process = proc;
|
|
183
|
+
|
|
184
|
+
// Set timeout
|
|
185
|
+
rt.timeoutHandle = setTimeout(() => {
|
|
186
|
+
console.log(`[${taskId}] Task timed out`);
|
|
187
|
+
proc.kill('SIGKILL');
|
|
188
|
+
this.onEvent(taskId, 'ERROR', { error: 'execution timeout' });
|
|
189
|
+
}, DEFAULT_TIMEOUT);
|
|
190
|
+
|
|
191
|
+
// Handle process events
|
|
192
|
+
this.handleProcessOutput(taskId, proc, rt);
|
|
193
|
+
}
|
|
194
|
+
|
|
195
|
+
/**
|
|
196
|
+
* Cancel a running task
|
|
197
|
+
*/
|
|
198
|
+
async cancelTask(taskId: string): Promise<void> {
|
|
199
|
+
const rt = this.running.get(taskId);
|
|
200
|
+
if (!rt) {
|
|
201
|
+
console.log(`[${taskId}] Task not found for cancellation`);
|
|
202
|
+
return;
|
|
203
|
+
}
|
|
204
|
+
|
|
205
|
+
if (rt.process) {
|
|
206
|
+
rt.process.kill('SIGTERM');
|
|
207
|
+
}
|
|
208
|
+
if (rt.timeoutHandle) {
|
|
209
|
+
clearTimeout(rt.timeoutHandle);
|
|
210
|
+
}
|
|
211
|
+
|
|
212
|
+
this.running.delete(taskId);
|
|
213
|
+
console.log(`[${taskId}] Task cancelled`);
|
|
214
|
+
}
|
|
215
|
+
|
|
216
|
+
/**
|
|
217
|
+
* Stop all running tasks
|
|
218
|
+
*/
|
|
219
|
+
async stopAll(): Promise<void> {
|
|
220
|
+
for (const [taskId, rt] of this.running) {
|
|
221
|
+
console.log(`[${taskId}] Stopping task`);
|
|
222
|
+
if (rt.process) {
|
|
223
|
+
rt.process.kill('SIGTERM');
|
|
224
|
+
}
|
|
225
|
+
if (rt.timeoutHandle) {
|
|
226
|
+
clearTimeout(rt.timeoutHandle);
|
|
227
|
+
}
|
|
228
|
+
}
|
|
229
|
+
this.running.clear();
|
|
230
|
+
}
|
|
231
|
+
|
|
232
|
+
/**
|
|
233
|
+
* Get list of running task IDs
|
|
234
|
+
*/
|
|
235
|
+
getRunningTasks(): string[] {
|
|
236
|
+
return Array.from(this.running.keys());
|
|
237
|
+
}
|
|
238
|
+
|
|
239
|
+
/**
|
|
240
|
+
* Handle process stdout/stderr and emit events
|
|
241
|
+
*/
|
|
242
|
+
private handleProcessOutput(
|
|
243
|
+
taskId: string,
|
|
244
|
+
proc: ChildProcess,
|
|
245
|
+
rt: RunningTask
|
|
246
|
+
): void {
|
|
247
|
+
// Create readline interface for NDJSON parsing
|
|
248
|
+
const rl = readline.createInterface({
|
|
249
|
+
input: proc.stdout!,
|
|
250
|
+
crlfDelay: Infinity
|
|
251
|
+
});
|
|
252
|
+
|
|
253
|
+
// Parse each line as JSON
|
|
254
|
+
rl.on('line', (line) => {
|
|
255
|
+
// Emit raw output for verbose mode
|
|
256
|
+
this.onEvent(taskId, 'OUTPUT', { output: line });
|
|
257
|
+
|
|
258
|
+
try {
|
|
259
|
+
const event = JSON.parse(line) as StreamEvent;
|
|
260
|
+
this.handleStreamEvent(taskId, event, rt);
|
|
261
|
+
} catch {
|
|
262
|
+
// Not valid JSON, skip
|
|
263
|
+
}
|
|
264
|
+
});
|
|
265
|
+
|
|
266
|
+
// Log stderr
|
|
267
|
+
proc.stderr?.on('data', (data) => {
|
|
268
|
+
console.log(`[${taskId}] stderr: ${data.toString()}`);
|
|
269
|
+
});
|
|
270
|
+
|
|
271
|
+
// Handle process exit
|
|
272
|
+
proc.on('close', (code) => {
|
|
273
|
+
console.log(`[${taskId}] Process exited with code ${code}`);
|
|
274
|
+
|
|
275
|
+
if (rt.timeoutHandle) {
|
|
276
|
+
clearTimeout(rt.timeoutHandle);
|
|
277
|
+
}
|
|
278
|
+
this.running.delete(taskId);
|
|
279
|
+
});
|
|
280
|
+
|
|
281
|
+
proc.on('error', (err) => {
|
|
282
|
+
console.error(`[${taskId}] Process error:`, err);
|
|
283
|
+
this.onEvent(taskId, 'ERROR', { error: err.message });
|
|
284
|
+
|
|
285
|
+
if (rt.timeoutHandle) {
|
|
286
|
+
clearTimeout(rt.timeoutHandle);
|
|
287
|
+
}
|
|
288
|
+
this.running.delete(taskId);
|
|
289
|
+
});
|
|
290
|
+
}
|
|
291
|
+
|
|
292
|
+
/**
|
|
293
|
+
* Handle a parsed stream event from Cursor CLI
|
|
294
|
+
*/
|
|
295
|
+
private handleStreamEvent(
|
|
296
|
+
taskId: string,
|
|
297
|
+
event: StreamEvent,
|
|
298
|
+
rt: RunningTask
|
|
299
|
+
): void {
|
|
300
|
+
switch (event.type) {
|
|
301
|
+
case 'start':
|
|
302
|
+
if (event.session_id) {
|
|
303
|
+
rt.sessionId = event.session_id;
|
|
304
|
+
console.log(`[${taskId}] Session initialized: ${event.session_id}`);
|
|
305
|
+
}
|
|
306
|
+
break;
|
|
307
|
+
|
|
308
|
+
case 'thinking':
|
|
309
|
+
// Accumulate thinking content for context
|
|
310
|
+
if (event.content) {
|
|
311
|
+
if (rt.context) {
|
|
312
|
+
rt.context += '\n\n';
|
|
313
|
+
}
|
|
314
|
+
rt.context += event.content;
|
|
315
|
+
}
|
|
316
|
+
break;
|
|
317
|
+
|
|
318
|
+
case 'action':
|
|
319
|
+
// Track action for progress
|
|
320
|
+
const progress = extractProgressFromAction(event);
|
|
321
|
+
if (progress) {
|
|
322
|
+
this.onEvent(taskId, 'PROGRESS', {
|
|
323
|
+
action: progress.action,
|
|
324
|
+
target: progress.target
|
|
325
|
+
});
|
|
326
|
+
}
|
|
327
|
+
break;
|
|
328
|
+
|
|
329
|
+
case 'approval_request':
|
|
330
|
+
// User input needed - pause and wait
|
|
331
|
+
console.log(`[${taskId}] Approval requested: ${event.action}`);
|
|
332
|
+
rt.question = event.action || 'Approve this action?';
|
|
333
|
+
|
|
334
|
+
this.onEvent(taskId, 'WAIT_FOR_USER', {
|
|
335
|
+
session_id: rt.sessionId,
|
|
336
|
+
prompt: rt.question,
|
|
337
|
+
options: [],
|
|
338
|
+
context: rt.context,
|
|
339
|
+
approval_details: {
|
|
340
|
+
action: event.action,
|
|
341
|
+
tool: event.tool,
|
|
342
|
+
file: event.file
|
|
343
|
+
}
|
|
344
|
+
});
|
|
345
|
+
break;
|
|
346
|
+
|
|
347
|
+
case 'action_complete':
|
|
348
|
+
// Action was approved and completed
|
|
349
|
+
console.log(`[${taskId}] Action complete: ${event.status}`);
|
|
350
|
+
break;
|
|
351
|
+
|
|
352
|
+
case 'result':
|
|
353
|
+
// Task completed
|
|
354
|
+
console.log(`[${taskId}] Task completed`);
|
|
355
|
+
this.onEvent(taskId, 'TASK_COMPLETE', {
|
|
356
|
+
session_id: rt.sessionId,
|
|
357
|
+
result: event.content || ''
|
|
358
|
+
});
|
|
359
|
+
break;
|
|
360
|
+
|
|
361
|
+
case 'error':
|
|
362
|
+
// Error occurred
|
|
363
|
+
console.error(`[${taskId}] Error: ${event.error}`);
|
|
364
|
+
this.onEvent(taskId, 'ERROR', {
|
|
365
|
+
error: event.error || 'Unknown error'
|
|
366
|
+
});
|
|
367
|
+
break;
|
|
368
|
+
}
|
|
369
|
+
}
|
|
370
|
+
}
|
|
@@ -0,0 +1,77 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Types for Cursor CLI stream-json output
|
|
3
|
+
* Note: These are based on research and may need adjustment
|
|
4
|
+
* once we verify actual Cursor CLI output format
|
|
5
|
+
*/
|
|
6
|
+
|
|
7
|
+
export interface StreamEvent {
|
|
8
|
+
type: 'start' | 'thinking' | 'action' | 'approval_request' | 'action_complete' | 'result' | 'error';
|
|
9
|
+
session_id?: string;
|
|
10
|
+
timestamp?: string;
|
|
11
|
+
content?: string;
|
|
12
|
+
tool?: string;
|
|
13
|
+
file?: string;
|
|
14
|
+
diff?: string;
|
|
15
|
+
action?: string;
|
|
16
|
+
status?: string;
|
|
17
|
+
error?: string;
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
export interface ApprovalRequest {
|
|
21
|
+
action: string;
|
|
22
|
+
tool: string;
|
|
23
|
+
file?: string;
|
|
24
|
+
command?: string;
|
|
25
|
+
description?: string;
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
export interface ProgressInfo {
|
|
29
|
+
action: string;
|
|
30
|
+
target: string;
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
/**
|
|
34
|
+
* Extract progress info from action event
|
|
35
|
+
*/
|
|
36
|
+
export function extractProgressFromAction(event: StreamEvent): ProgressInfo | null {
|
|
37
|
+
if (event.type !== 'action' || !event.tool) {
|
|
38
|
+
return null;
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
switch (event.tool) {
|
|
42
|
+
case 'file_read':
|
|
43
|
+
return {
|
|
44
|
+
action: 'Reading',
|
|
45
|
+
target: event.file || 'file'
|
|
46
|
+
};
|
|
47
|
+
case 'file_write':
|
|
48
|
+
case 'file_edit':
|
|
49
|
+
return {
|
|
50
|
+
action: 'Editing',
|
|
51
|
+
target: event.file || 'file'
|
|
52
|
+
};
|
|
53
|
+
case 'shell':
|
|
54
|
+
case 'terminal':
|
|
55
|
+
const cmd = event.content || '';
|
|
56
|
+
return {
|
|
57
|
+
action: 'Running',
|
|
58
|
+
target: cmd.length > 30 ? cmd.substring(0, 30) + '...' : cmd
|
|
59
|
+
};
|
|
60
|
+
case 'search':
|
|
61
|
+
case 'grep':
|
|
62
|
+
return {
|
|
63
|
+
action: 'Searching',
|
|
64
|
+
target: event.content || 'files'
|
|
65
|
+
};
|
|
66
|
+
case 'web_search':
|
|
67
|
+
return {
|
|
68
|
+
action: 'Searching web',
|
|
69
|
+
target: event.content || ''
|
|
70
|
+
};
|
|
71
|
+
default:
|
|
72
|
+
return {
|
|
73
|
+
action: event.tool,
|
|
74
|
+
target: event.file || event.content || ''
|
|
75
|
+
};
|
|
76
|
+
}
|
|
77
|
+
}
|
|
@@ -0,0 +1,75 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Message types for daemon <-> server communication
|
|
3
|
+
*/
|
|
4
|
+
|
|
5
|
+
// Server -> Daemon messages
|
|
6
|
+
|
|
7
|
+
export interface PingMessage {
|
|
8
|
+
type: 'ping';
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
export interface TaskStartMessage {
|
|
12
|
+
type: 'task_start';
|
|
13
|
+
task_id: string;
|
|
14
|
+
instruction: string;
|
|
15
|
+
project_path?: string;
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
export interface TaskResumeMessage {
|
|
19
|
+
type: 'task_resume';
|
|
20
|
+
task_id: string;
|
|
21
|
+
session_id: string;
|
|
22
|
+
message: string;
|
|
23
|
+
project_path?: string;
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
export interface TaskCancelMessage {
|
|
27
|
+
type: 'task_cancel';
|
|
28
|
+
task_id: string;
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
export interface VersionStatusMessage {
|
|
32
|
+
type: 'version_status';
|
|
33
|
+
status: 'current' | 'update_available' | 'update_required';
|
|
34
|
+
your_version: string;
|
|
35
|
+
min_version?: string;
|
|
36
|
+
recommended_version?: string;
|
|
37
|
+
latest_version?: string;
|
|
38
|
+
changelog_url?: string;
|
|
39
|
+
message?: string;
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
export type ServerMessage =
|
|
43
|
+
| PingMessage
|
|
44
|
+
| TaskStartMessage
|
|
45
|
+
| TaskResumeMessage
|
|
46
|
+
| TaskCancelMessage
|
|
47
|
+
| VersionStatusMessage;
|
|
48
|
+
|
|
49
|
+
// Daemon -> Server messages
|
|
50
|
+
|
|
51
|
+
export interface PongMessage {
|
|
52
|
+
type: 'pong';
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
export interface StatusMessage {
|
|
56
|
+
type: 'status';
|
|
57
|
+
running_tasks: string[];
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
export interface EventMessage {
|
|
61
|
+
type: 'event';
|
|
62
|
+
task_id: string;
|
|
63
|
+
event_type: string;
|
|
64
|
+
[key: string]: unknown;
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
export type DaemonMessage = PongMessage | StatusMessage | EventMessage;
|
|
68
|
+
|
|
69
|
+
// Event types sent from daemon to server
|
|
70
|
+
export type EventType =
|
|
71
|
+
| 'WAIT_FOR_USER'
|
|
72
|
+
| 'TASK_COMPLETE'
|
|
73
|
+
| 'OUTPUT'
|
|
74
|
+
| 'PROGRESS'
|
|
75
|
+
| 'ERROR';
|