@litmers/cursorflow-orchestrator 0.1.40 → 0.2.2
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 +0 -2
- package/README.md +7 -3
- package/commands/cursorflow-init.md +0 -4
- package/dist/cli/logs.js +108 -9
- package/dist/cli/logs.js.map +1 -1
- package/dist/cli/models.js +20 -3
- package/dist/cli/models.js.map +1 -1
- package/dist/cli/monitor.d.ts +7 -10
- package/dist/cli/monitor.js +1088 -1240
- package/dist/cli/monitor.js.map +1 -1
- package/dist/cli/resume.js +21 -1
- package/dist/cli/resume.js.map +1 -1
- package/dist/cli/run.js +28 -9
- package/dist/cli/run.js.map +1 -1
- package/dist/cli/signal.d.ts +6 -1
- package/dist/cli/signal.js +94 -12
- package/dist/cli/signal.js.map +1 -1
- package/dist/cli/tasks.js +3 -46
- package/dist/cli/tasks.js.map +1 -1
- package/dist/core/agent-supervisor.d.ts +23 -0
- package/dist/core/agent-supervisor.js +42 -0
- package/dist/core/agent-supervisor.js.map +1 -0
- package/dist/core/auto-recovery.d.ts +2 -1
- package/dist/core/auto-recovery.js +6 -1
- package/dist/core/auto-recovery.js.map +1 -1
- package/dist/core/failure-policy.d.ts +0 -1
- package/dist/core/failure-policy.js +0 -1
- package/dist/core/failure-policy.js.map +1 -1
- package/dist/core/git-lifecycle-manager.d.ts +284 -0
- package/dist/core/git-lifecycle-manager.js +778 -0
- package/dist/core/git-lifecycle-manager.js.map +1 -0
- package/dist/core/git-pipeline-coordinator.d.ts +21 -0
- package/dist/core/git-pipeline-coordinator.js +205 -0
- package/dist/core/git-pipeline-coordinator.js.map +1 -0
- package/dist/core/intervention.d.ts +176 -0
- package/dist/core/intervention.js +424 -0
- package/dist/core/intervention.js.map +1 -0
- package/dist/core/lane-state-machine.d.ts +423 -0
- package/dist/core/lane-state-machine.js +890 -0
- package/dist/core/lane-state-machine.js.map +1 -0
- package/dist/core/orchestrator.d.ts +4 -1
- package/dist/core/orchestrator.js +29 -62
- package/dist/core/orchestrator.js.map +1 -1
- package/dist/core/runner/agent.d.ts +7 -1
- package/dist/core/runner/agent.js +45 -30
- package/dist/core/runner/agent.js.map +1 -1
- package/dist/core/runner/pipeline.js +283 -123
- package/dist/core/runner/pipeline.js.map +1 -1
- package/dist/core/runner/task.d.ts +4 -5
- package/dist/core/runner/task.js +6 -80
- package/dist/core/runner/task.js.map +1 -1
- package/dist/core/runner.js +8 -2
- package/dist/core/runner.js.map +1 -1
- package/dist/core/stall-detection.d.ts +11 -4
- package/dist/core/stall-detection.js +62 -27
- package/dist/core/stall-detection.js.map +1 -1
- package/dist/hooks/contexts/index.d.ts +104 -0
- package/dist/hooks/contexts/index.js +134 -0
- package/dist/hooks/contexts/index.js.map +1 -0
- package/dist/hooks/data-accessor.d.ts +86 -0
- package/dist/hooks/data-accessor.js +410 -0
- package/dist/hooks/data-accessor.js.map +1 -0
- package/dist/hooks/flow-controller.d.ts +136 -0
- package/dist/hooks/flow-controller.js +351 -0
- package/dist/hooks/flow-controller.js.map +1 -0
- package/dist/hooks/index.d.ts +68 -0
- package/dist/hooks/index.js +105 -0
- package/dist/hooks/index.js.map +1 -0
- package/dist/hooks/manager.d.ts +129 -0
- package/dist/hooks/manager.js +389 -0
- package/dist/hooks/manager.js.map +1 -0
- package/dist/hooks/types.d.ts +463 -0
- package/dist/hooks/types.js +45 -0
- package/dist/hooks/types.js.map +1 -0
- package/dist/services/logging/buffer.d.ts +2 -2
- package/dist/services/logging/buffer.js +95 -42
- package/dist/services/logging/buffer.js.map +1 -1
- package/dist/services/logging/console.js +6 -1
- package/dist/services/logging/console.js.map +1 -1
- package/dist/services/logging/formatter.d.ts +9 -4
- package/dist/services/logging/formatter.js +64 -18
- package/dist/services/logging/formatter.js.map +1 -1
- package/dist/services/logging/index.d.ts +0 -1
- package/dist/services/logging/index.js +0 -1
- package/dist/services/logging/index.js.map +1 -1
- package/dist/services/logging/paths.d.ts +8 -0
- package/dist/services/logging/paths.js +48 -0
- package/dist/services/logging/paths.js.map +1 -0
- package/dist/services/logging/raw-log.d.ts +6 -0
- package/dist/services/logging/raw-log.js +37 -0
- package/dist/services/logging/raw-log.js.map +1 -0
- package/dist/services/process/index.js +1 -1
- package/dist/services/process/index.js.map +1 -1
- package/dist/types/agent.d.ts +15 -0
- package/dist/types/config.d.ts +22 -1
- package/dist/types/event-categories.d.ts +601 -0
- package/dist/types/event-categories.js +233 -0
- package/dist/types/event-categories.js.map +1 -0
- package/dist/types/events.d.ts +0 -20
- package/dist/types/flow.d.ts +10 -6
- package/dist/types/index.d.ts +1 -1
- package/dist/types/index.js +17 -3
- package/dist/types/index.js.map +1 -1
- package/dist/types/lane.d.ts +1 -1
- package/dist/types/logging.d.ts +1 -1
- package/dist/types/task.d.ts +12 -1
- package/dist/ui/log-viewer.d.ts +3 -0
- package/dist/ui/log-viewer.js +3 -0
- package/dist/ui/log-viewer.js.map +1 -1
- package/dist/utils/config.js +10 -1
- package/dist/utils/config.js.map +1 -1
- package/dist/utils/cursor-agent.d.ts +11 -1
- package/dist/utils/cursor-agent.js +63 -16
- package/dist/utils/cursor-agent.js.map +1 -1
- package/dist/utils/enhanced-logger.d.ts +5 -1
- package/dist/utils/enhanced-logger.js +98 -19
- package/dist/utils/enhanced-logger.js.map +1 -1
- package/dist/utils/event-registry.d.ts +222 -0
- package/dist/utils/event-registry.js +463 -0
- package/dist/utils/event-registry.js.map +1 -0
- package/dist/utils/events.d.ts +1 -13
- package/dist/utils/events.js.map +1 -1
- package/dist/utils/flow.d.ts +10 -0
- package/dist/utils/flow.js +75 -0
- package/dist/utils/flow.js.map +1 -1
- package/dist/utils/log-constants.d.ts +1 -0
- package/dist/utils/log-constants.js +2 -1
- package/dist/utils/log-constants.js.map +1 -1
- package/dist/utils/log-formatter.d.ts +2 -1
- package/dist/utils/log-formatter.js +10 -10
- package/dist/utils/log-formatter.js.map +1 -1
- package/dist/utils/logger.d.ts +11 -0
- package/dist/utils/logger.js +82 -3
- package/dist/utils/logger.js.map +1 -1
- package/dist/utils/repro-thinking-logs.js +0 -13
- package/dist/utils/repro-thinking-logs.js.map +1 -1
- package/dist/utils/run-service.js +1 -1
- package/dist/utils/run-service.js.map +1 -1
- package/examples/README.md +0 -2
- package/examples/demo-project/README.md +1 -2
- package/package.json +18 -28
- package/scripts/setup-security.sh +0 -1
- package/scripts/test-log-parser.ts +171 -0
- package/scripts/verify-change.sh +272 -0
- package/src/cli/logs.ts +121 -10
- package/src/cli/models.ts +20 -3
- package/src/cli/monitor.ts +1257 -1342
- package/src/cli/resume.ts +27 -1
- package/src/cli/run.ts +29 -11
- package/src/cli/signal.ts +115 -17
- package/src/cli/tasks.ts +2 -59
- package/src/core/agent-supervisor.ts +64 -0
- package/src/core/auto-recovery.ts +7 -1
- package/src/core/failure-policy.ts +0 -1
- package/src/core/git-lifecycle-manager.ts +1011 -0
- package/src/core/git-pipeline-coordinator.ts +221 -0
- package/src/core/intervention.ts +481 -0
- package/src/core/lane-state-machine.ts +1097 -0
- package/src/core/orchestrator.ts +35 -61
- package/src/core/runner/agent.ts +66 -33
- package/src/core/runner/pipeline.ts +318 -138
- package/src/core/runner/task.ts +12 -97
- package/src/core/runner.ts +8 -2
- package/src/core/stall-detection.ts +72 -27
- package/src/hooks/contexts/index.ts +256 -0
- package/src/hooks/data-accessor.ts +488 -0
- package/src/hooks/flow-controller.ts +425 -0
- package/src/hooks/index.ts +154 -0
- package/src/hooks/manager.ts +434 -0
- package/src/hooks/types.ts +544 -0
- package/src/services/logging/buffer.ts +104 -43
- package/src/services/logging/console.ts +7 -1
- package/src/services/logging/formatter.ts +74 -18
- package/src/services/logging/index.ts +0 -2
- package/src/services/logging/paths.ts +14 -0
- package/src/services/logging/raw-log.ts +43 -0
- package/src/services/process/index.ts +1 -1
- package/src/types/agent.ts +15 -0
- package/src/types/config.ts +23 -1
- package/src/types/event-categories.ts +663 -0
- package/src/types/events.ts +0 -25
- package/src/types/flow.ts +10 -6
- package/src/types/index.ts +50 -4
- package/src/types/lane.ts +1 -2
- package/src/types/logging.ts +2 -1
- package/src/types/task.ts +12 -1
- package/src/ui/log-viewer.ts +3 -0
- package/src/utils/config.ts +11 -1
- package/src/utils/cursor-agent.ts +68 -16
- package/src/utils/enhanced-logger.ts +105 -19
- package/src/utils/event-registry.ts +595 -0
- package/src/utils/events.ts +0 -16
- package/src/utils/flow.ts +83 -0
- package/src/utils/log-constants.ts +2 -1
- package/src/utils/log-formatter.ts +10 -11
- package/src/utils/logger.ts +49 -3
- package/src/utils/repro-thinking-logs.ts +0 -15
- package/src/utils/run-service.ts +1 -1
- package/dist/services/logging/file-writer.d.ts +0 -71
- package/dist/services/logging/file-writer.js +0 -516
- package/dist/services/logging/file-writer.js.map +0 -1
- package/dist/types/review.d.ts +0 -17
- package/dist/types/review.js +0 -6
- package/dist/types/review.js.map +0 -1
- package/scripts/ai-security-check.js +0 -233
- package/src/services/logging/file-writer.ts +0 -526
- package/src/types/review.ts +0 -20
|
@@ -9,6 +9,7 @@ import * as path from 'path';
|
|
|
9
9
|
import { EventEmitter } from 'events';
|
|
10
10
|
import { LogImportance, JsonLogEntry, BufferedLogEntry as BufferedLogEntryType, MessageType } from '../../types/logging';
|
|
11
11
|
import { COLORS } from './console';
|
|
12
|
+
import { stripAnsi } from './formatter';
|
|
12
13
|
|
|
13
14
|
// Re-export types for convenience
|
|
14
15
|
export type { BufferedLogEntry } from '../../types/logging';
|
|
@@ -108,13 +109,13 @@ export class LogBufferService extends EventEmitter {
|
|
|
108
109
|
const newEntries: BufferedLogEntryType[] = [];
|
|
109
110
|
|
|
110
111
|
for (const laneName of this.lanes) {
|
|
111
|
-
const
|
|
112
|
+
const readablePath = path.join(lanesDir, laneName, 'terminal-readable.log');
|
|
112
113
|
|
|
113
114
|
let fd: number | null = null;
|
|
114
115
|
try {
|
|
115
116
|
// Read file content atomically to avoid TOCTOU race condition
|
|
116
|
-
const lastPos = this.filePositions.get(
|
|
117
|
-
fd = fs.openSync(
|
|
117
|
+
const lastPos = this.filePositions.get(readablePath) || 0;
|
|
118
|
+
fd = fs.openSync(readablePath, 'r');
|
|
118
119
|
const stat = fs.fstatSync(fd); // Use fstat on open fd to avoid race
|
|
119
120
|
|
|
120
121
|
if (stat.size > lastPos) {
|
|
@@ -125,14 +126,11 @@ export class LogBufferService extends EventEmitter {
|
|
|
125
126
|
const lines = newContent.split('\n').filter(line => line.trim());
|
|
126
127
|
|
|
127
128
|
for (const line of lines) {
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
const processed = this.processEntry(entry, laneName);
|
|
131
|
-
if (processed) newEntries.push(processed);
|
|
132
|
-
} catch { /* Skip invalid JSON */ }
|
|
129
|
+
const processed = this.processReadableLine(line, laneName);
|
|
130
|
+
if (processed) newEntries.push(processed);
|
|
133
131
|
}
|
|
134
132
|
|
|
135
|
-
this.filePositions.set(
|
|
133
|
+
this.filePositions.set(readablePath, stat.size);
|
|
136
134
|
}
|
|
137
135
|
} catch { /* File in use, skip */ }
|
|
138
136
|
finally {
|
|
@@ -156,11 +154,11 @@ export class LogBufferService extends EventEmitter {
|
|
|
156
154
|
}
|
|
157
155
|
}
|
|
158
156
|
|
|
159
|
-
private
|
|
160
|
-
const
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
const message
|
|
157
|
+
private processReadableLine(line: string, laneName: string): BufferedLogEntryType | null {
|
|
158
|
+
const cleaned = stripAnsi(line).trim();
|
|
159
|
+
if (!cleaned) return null;
|
|
160
|
+
|
|
161
|
+
const { timestamp, message, level, type } = this.parseReadableMessage(cleaned);
|
|
164
162
|
const importance = this.inferImportance(type, level);
|
|
165
163
|
|
|
166
164
|
return {
|
|
@@ -172,23 +170,63 @@ export class LogBufferService extends EventEmitter {
|
|
|
172
170
|
message: this.truncateMessage(message),
|
|
173
171
|
importance,
|
|
174
172
|
laneColor: this.laneColorMap.get(laneName) || COLORS.white,
|
|
175
|
-
raw:
|
|
173
|
+
raw: {
|
|
174
|
+
timestamp: timestamp.toISOString(),
|
|
175
|
+
level: level as JsonLogEntry['level'],
|
|
176
|
+
lane: laneName,
|
|
177
|
+
message,
|
|
178
|
+
},
|
|
176
179
|
};
|
|
177
180
|
}
|
|
178
181
|
|
|
179
|
-
private
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
182
|
+
private parseReadableMessage(line: string): {
|
|
183
|
+
timestamp: Date;
|
|
184
|
+
message: string;
|
|
185
|
+
level: string;
|
|
186
|
+
type: MessageType | string;
|
|
187
|
+
} {
|
|
188
|
+
let remaining = line;
|
|
189
|
+
let timestamp = new Date();
|
|
190
|
+
|
|
191
|
+
const isoMatch = remaining.match(/^\[(\d{4}-\d{2}-\d{2}T[^\]]+)\]\s*/);
|
|
192
|
+
if (isoMatch) {
|
|
193
|
+
timestamp = new Date(isoMatch[1]!);
|
|
194
|
+
remaining = remaining.slice(isoMatch[0].length);
|
|
195
|
+
} else {
|
|
196
|
+
const timeMatch = remaining.match(/^\[(\d{2}:\d{2}:\d{2})\]\s*/);
|
|
197
|
+
if (timeMatch) {
|
|
198
|
+
const [hours, minutes, seconds] = timeMatch[1]!.split(':').map(Number);
|
|
199
|
+
const now = new Date();
|
|
200
|
+
now.setHours(hours || 0, minutes || 0, seconds || 0, 0);
|
|
201
|
+
timestamp = now;
|
|
202
|
+
remaining = remaining.slice(timeMatch[0].length);
|
|
203
|
+
}
|
|
191
204
|
}
|
|
205
|
+
|
|
206
|
+
const labelMatch = remaining.match(/^\[[^\]]+\]\s*/);
|
|
207
|
+
if (labelMatch) {
|
|
208
|
+
remaining = remaining.slice(labelMatch[0].length);
|
|
209
|
+
}
|
|
210
|
+
|
|
211
|
+
const upper = remaining.toUpperCase();
|
|
212
|
+
let level = 'info';
|
|
213
|
+
let type: MessageType | string = 'stdout';
|
|
214
|
+
|
|
215
|
+
if (remaining.includes('❌') || upper.includes('ERR') || upper.includes('ERROR')) {
|
|
216
|
+
level = 'error';
|
|
217
|
+
type = 'error';
|
|
218
|
+
} else if (remaining.includes('⚠️') || upper.includes('WARN')) {
|
|
219
|
+
level = 'warn';
|
|
220
|
+
type = 'warn';
|
|
221
|
+
} else if (remaining.includes('🔍') || upper.includes('DEBUG')) {
|
|
222
|
+
level = 'debug';
|
|
223
|
+
type = 'debug';
|
|
224
|
+
} else if (remaining.includes('ℹ️') || upper.includes('INFO')) {
|
|
225
|
+
level = 'info';
|
|
226
|
+
type = 'info';
|
|
227
|
+
}
|
|
228
|
+
|
|
229
|
+
return { timestamp, message: remaining, level, type };
|
|
192
230
|
}
|
|
193
231
|
|
|
194
232
|
private inferImportance(type: string, level: string): LogImportance {
|
|
@@ -295,32 +333,55 @@ export class LogBufferService extends EventEmitter {
|
|
|
295
333
|
}
|
|
296
334
|
|
|
297
335
|
if (showLane) {
|
|
298
|
-
|
|
336
|
+
// Lane label: fixed 14 chars inside brackets
|
|
337
|
+
const truncatedLane = entry.laneName.length > 14 ? entry.laneName.substring(0, 14) : entry.laneName;
|
|
338
|
+
parts.push(`${COLORS.magenta}[${truncatedLane.padEnd(14)}]${COLORS.reset}`);
|
|
299
339
|
}
|
|
300
340
|
|
|
301
|
-
|
|
302
|
-
parts.push(
|
|
341
|
+
const { indicator, messageColor } = this.getTypeIndicator(entry.type);
|
|
342
|
+
parts.push(indicator);
|
|
343
|
+
|
|
344
|
+
// Apply message color if needed
|
|
345
|
+
const coloredMessage = messageColor ? `${messageColor}${entry.message}${COLORS.reset}` : entry.message;
|
|
346
|
+
parts.push(coloredMessage);
|
|
303
347
|
|
|
304
348
|
return parts.join(' ');
|
|
305
349
|
}
|
|
306
350
|
|
|
307
|
-
private getTypeIndicator(type: string): string {
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
|
|
351
|
+
private getTypeIndicator(type: string): { indicator: string; messageColor: string } {
|
|
352
|
+
// Color rules:
|
|
353
|
+
// - Important (colored): user(cyan), assistant(green), result(green), error(red), warn(yellow)
|
|
354
|
+
// - Less important (gray): tool, tool_result, thinking, system, debug, stdout, info, raw
|
|
355
|
+
const indicators: Record<string, { indicator: string; messageColor: string }> = {
|
|
356
|
+
user: { indicator: `${COLORS.cyan}🧑 USER${COLORS.reset}`, messageColor: '' },
|
|
357
|
+
assistant: { indicator: `${COLORS.green}🤖 ASST${COLORS.reset}`, messageColor: '' },
|
|
358
|
+
tool: { indicator: `${COLORS.gray}🔧 TOOL${COLORS.reset}`, messageColor: COLORS.gray },
|
|
359
|
+
tool_result: { indicator: `${COLORS.gray}📄 RESL${COLORS.reset}`, messageColor: COLORS.gray },
|
|
360
|
+
error: { indicator: `${COLORS.red}❌ ERR${COLORS.reset}`, messageColor: COLORS.red },
|
|
361
|
+
stderr: { indicator: `${COLORS.red} >>${COLORS.reset}`, messageColor: COLORS.red },
|
|
362
|
+
thinking: { indicator: `${COLORS.gray}🤔 THNK${COLORS.reset}`, messageColor: COLORS.gray },
|
|
363
|
+
result: { indicator: `${COLORS.green}✅ DONE${COLORS.reset}`, messageColor: '' },
|
|
364
|
+
success: { indicator: `${COLORS.green}✅ DONE${COLORS.reset}`, messageColor: '' },
|
|
365
|
+
stdout: { indicator: `${COLORS.gray} >>${COLORS.reset}`, messageColor: COLORS.gray },
|
|
366
|
+
raw: { indicator: `${COLORS.gray} >>${COLORS.reset}`, messageColor: COLORS.gray },
|
|
367
|
+
info: { indicator: `${COLORS.gray}ℹ️ INFO${COLORS.reset}`, messageColor: COLORS.gray },
|
|
368
|
+
warn: { indicator: `${COLORS.yellow}⚠️ WARN${COLORS.reset}`, messageColor: '' },
|
|
369
|
+
debug: { indicator: `${COLORS.gray}🔍 DBUG${COLORS.reset}`, messageColor: COLORS.gray },
|
|
370
|
+
system: { indicator: `${COLORS.gray}⚙️ SYS${COLORS.reset}`, messageColor: COLORS.gray },
|
|
371
|
+
progress: { indicator: `${COLORS.blue}🔄 PROG${COLORS.reset}`, messageColor: '' },
|
|
372
|
+
};
|
|
373
|
+
|
|
374
|
+
const match = indicators[type.toLowerCase()];
|
|
375
|
+
if (match) return match;
|
|
376
|
+
|
|
377
|
+
// Default: gray for unknown types
|
|
378
|
+
return {
|
|
379
|
+
indicator: `${COLORS.gray} ${type.toUpperCase().substring(0, 4).padEnd(4)}${COLORS.reset}`,
|
|
380
|
+
messageColor: COLORS.gray
|
|
318
381
|
};
|
|
319
|
-
return indicators[type.toLowerCase()] || `${COLORS.gray}[${type.toUpperCase().padEnd(6)}]${COLORS.reset}`;
|
|
320
382
|
}
|
|
321
383
|
}
|
|
322
384
|
|
|
323
385
|
export function createLogBuffer(runDir: string, options?: LogBufferOptions): LogBufferService {
|
|
324
386
|
return new LogBufferService(runDir, options);
|
|
325
387
|
}
|
|
326
|
-
|
|
@@ -94,6 +94,10 @@ function normalizeOptions(options: LogOptions | string | undefined, defaultEmoji
|
|
|
94
94
|
}
|
|
95
95
|
|
|
96
96
|
// Primary logging functions
|
|
97
|
+
// Color rules:
|
|
98
|
+
// - Important (colored): error(red), warn(yellow), success(green)
|
|
99
|
+
// - Less important (gray): info, debug
|
|
100
|
+
|
|
97
101
|
export function error(message: string, options?: LogOptions | string): void {
|
|
98
102
|
logWithColor(COLORS.red, 'error', message, normalizeOptions(options, '❌'));
|
|
99
103
|
}
|
|
@@ -103,7 +107,8 @@ export function warn(message: string, options?: LogOptions | string): void {
|
|
|
103
107
|
}
|
|
104
108
|
|
|
105
109
|
export function info(message: string, options?: LogOptions | string): void {
|
|
106
|
-
|
|
110
|
+
// Info is gray (less important) - focus on important messages
|
|
111
|
+
logWithColor(COLORS.gray, 'info', message, normalizeOptions(options, 'ℹ️'));
|
|
107
112
|
}
|
|
108
113
|
|
|
109
114
|
export function success(message: string, options?: LogOptions | string): void {
|
|
@@ -115,6 +120,7 @@ export function debug(message: string, options?: LogOptions | string): void {
|
|
|
115
120
|
}
|
|
116
121
|
|
|
117
122
|
export function progress(message: string, options?: LogOptions | string): void {
|
|
123
|
+
// Progress is blue (visible but not critical)
|
|
118
124
|
logWithColor(COLORS.blue, 'info', message, normalizeOptions(options, '🔄'));
|
|
119
125
|
}
|
|
120
126
|
|
|
@@ -3,18 +3,26 @@
|
|
|
3
3
|
*
|
|
4
4
|
* Formats log messages for console display with various styles.
|
|
5
5
|
*
|
|
6
|
-
* Rules:
|
|
7
|
-
* -
|
|
8
|
-
* -
|
|
6
|
+
* ## Color Rules (by importance):
|
|
7
|
+
* - HIGH (colored): user(cyan), assistant(green), result(green), error(red), warn(yellow)
|
|
8
|
+
* - LOW (gray/dim): tool, tool_result, thinking, system, debug, stdout, raw, info
|
|
9
|
+
*
|
|
10
|
+
* ## Format Rules:
|
|
11
|
+
* - Box format only for: user, assistant, result
|
|
12
|
+
* - Compact format for: tool, tool_result, thinking, system (gray/dim)
|
|
9
13
|
* - Tool names simplified: ShellToolCall → Shell
|
|
10
|
-
* - Lane labels fixed
|
|
14
|
+
* - Lane labels fixed 14 chars: [1-1-lanename ]
|
|
15
|
+
* - Type labels: emoji + 4char (USER, ASST, TOOL, RESL, SYS, DONE, THNK)
|
|
11
16
|
*/
|
|
12
17
|
|
|
13
18
|
import { COLORS } from './console';
|
|
14
19
|
import { ParsedMessage, MessageType } from '../../types/logging';
|
|
15
20
|
|
|
16
|
-
// Types that should use box format
|
|
17
|
-
const BOX_TYPES = new Set(['user', 'assistant', '
|
|
21
|
+
// Types that should use box format (important messages)
|
|
22
|
+
const BOX_TYPES = new Set(['user', 'assistant', 'result']);
|
|
23
|
+
|
|
24
|
+
// Types that should be gray/dim (less important)
|
|
25
|
+
const GRAY_TYPES = new Set(['tool', 'tool_result', 'thinking', 'system', 'debug', 'stdout', 'raw', 'info']);
|
|
18
26
|
|
|
19
27
|
/**
|
|
20
28
|
* Strip ANSI escape sequences from text
|
|
@@ -65,10 +73,11 @@ export function formatMessageForConsole(
|
|
|
65
73
|
: '';
|
|
66
74
|
const tsPrefix = ts ? `${COLORS.gray}[${ts}]${COLORS.reset} ` : '';
|
|
67
75
|
|
|
68
|
-
// Lane label
|
|
69
|
-
const
|
|
76
|
+
// Lane label: fixed 14 chars inside brackets [1-1-lanename ]
|
|
77
|
+
const labelContent = laneLabel.replace(/^\[|\]$/g, ''); // Remove existing brackets if any
|
|
78
|
+
const truncatedLabel = labelContent.length > 14 ? labelContent.substring(0, 14) : labelContent;
|
|
70
79
|
const labelPrefix = truncatedLabel
|
|
71
|
-
? `${COLORS.magenta}${truncatedLabel.padEnd(
|
|
80
|
+
? `${COLORS.magenta}[${truncatedLabel.padEnd(14)}]${COLORS.reset} `
|
|
72
81
|
: '';
|
|
73
82
|
|
|
74
83
|
// Determine if should use box format
|
|
@@ -78,17 +87,17 @@ export function formatMessageForConsole(
|
|
|
78
87
|
if (!typePrefix) return `${tsPrefix}${labelPrefix}${formattedContent}`;
|
|
79
88
|
|
|
80
89
|
if (!useBox) {
|
|
81
|
-
|
|
90
|
+
// Compact format: type prefix is already formatted with proper spacing
|
|
91
|
+
return `${tsPrefix}${labelPrefix}${typePrefix} ${formattedContent}`;
|
|
82
92
|
}
|
|
83
93
|
|
|
84
|
-
// Multi-line box format (only for user, assistant,
|
|
85
|
-
// Emoji width is 2, so we need to account for that in indent calculation
|
|
94
|
+
// Multi-line box format (only for user, assistant, result)
|
|
86
95
|
const lines = formattedContent.split('\n');
|
|
87
96
|
const fullPrefix = `${tsPrefix}${labelPrefix}`;
|
|
88
97
|
const strippedPrefix = stripAnsi(typePrefix);
|
|
89
98
|
// Count emojis (they take 2 terminal columns but 1-2 chars in string)
|
|
90
99
|
const emojiCount = (strippedPrefix.match(/[\u{1F300}-\u{1F9FF}]|[\u{2600}-\u{26FF}]|[\u{2700}-\u{27BF}]|[\u{1F600}-\u{1F64F}]|[\u{1F680}-\u{1F6FF}]|[\u{1F1E0}-\u{1F1FF}]|[\u{2300}-\u{23FF}]|[\u{2B50}-\u{2B55}]|[\u{231A}-\u{231B}]|[\u{23E9}-\u{23F3}]|[\u{23F8}-\u{23FA}]|✅|❌|⚙️|ℹ️|⚠️|🔧|📄|🤔|🧑|🤖/gu) || []).length;
|
|
91
|
-
const visualWidth = strippedPrefix.length + emojiCount;
|
|
100
|
+
const visualWidth = strippedPrefix.length + emojiCount;
|
|
92
101
|
|
|
93
102
|
const boxWidth = 60;
|
|
94
103
|
const header = `${typePrefix}┌${'─'.repeat(boxWidth)}`;
|
|
@@ -112,6 +121,9 @@ function formatMessageContent(msg: ParsedMessage, forceCompact: boolean): { type
|
|
|
112
121
|
formattedContent = formattedContent.replace(/\n\s*\n/g, ' ').replace(/\n/g, ' ').trim();
|
|
113
122
|
}
|
|
114
123
|
|
|
124
|
+
// Determine if this type should be gray (less important)
|
|
125
|
+
const isGray = GRAY_TYPES.has(msg.type);
|
|
126
|
+
|
|
115
127
|
switch (msg.type) {
|
|
116
128
|
case 'user':
|
|
117
129
|
typePrefix = `${COLORS.cyan}🧑 USER${COLORS.reset}`;
|
|
@@ -124,20 +136,20 @@ function formatMessageContent(msg: ParsedMessage, forceCompact: boolean): { type
|
|
|
124
136
|
break;
|
|
125
137
|
|
|
126
138
|
case 'tool':
|
|
127
|
-
// Tool calls are always gray
|
|
139
|
+
// Tool calls are always gray (less important)
|
|
128
140
|
typePrefix = `${COLORS.gray}🔧 TOOL${COLORS.reset}`;
|
|
129
141
|
formattedContent = formatToolCall(formattedContent);
|
|
130
142
|
break;
|
|
131
143
|
|
|
132
144
|
case 'tool_result':
|
|
133
|
-
// Tool results are always gray
|
|
145
|
+
// Tool results are always gray (less important)
|
|
134
146
|
typePrefix = `${COLORS.gray}📄 RESL${COLORS.reset}`;
|
|
135
147
|
const resMatch = formattedContent.match(/\[Tool Result: ([^\]]+)\]/);
|
|
136
148
|
if (resMatch) {
|
|
137
149
|
const simpleName = simplifyToolName(resMatch[1]!);
|
|
138
150
|
formattedContent = `${COLORS.gray}${simpleName} OK${COLORS.reset}`;
|
|
139
151
|
} else {
|
|
140
|
-
formattedContent = `${COLORS.gray}
|
|
152
|
+
formattedContent = `${COLORS.gray}OK${COLORS.reset}`;
|
|
141
153
|
}
|
|
142
154
|
break;
|
|
143
155
|
|
|
@@ -146,14 +158,57 @@ function formatMessageContent(msg: ParsedMessage, forceCompact: boolean): { type
|
|
|
146
158
|
break;
|
|
147
159
|
|
|
148
160
|
case 'system':
|
|
149
|
-
|
|
161
|
+
// System messages are gray (less important)
|
|
162
|
+
typePrefix = `${COLORS.gray}⚙️ SYS${COLORS.reset}`;
|
|
163
|
+
formattedContent = `${COLORS.gray}${formattedContent}${COLORS.reset}`;
|
|
150
164
|
break;
|
|
151
165
|
|
|
152
166
|
case 'thinking':
|
|
153
|
-
// Thinking is always gray and compact
|
|
167
|
+
// Thinking is always gray and compact (less important)
|
|
154
168
|
typePrefix = `${COLORS.gray}🤔 THNK${COLORS.reset}`;
|
|
155
169
|
formattedContent = `${COLORS.gray}${truncate(formattedContent, 100)}${COLORS.reset}`;
|
|
156
170
|
break;
|
|
171
|
+
|
|
172
|
+
case 'info':
|
|
173
|
+
// Info messages are gray (less important)
|
|
174
|
+
typePrefix = `${COLORS.gray}ℹ️ INFO${COLORS.reset}`;
|
|
175
|
+
formattedContent = `${COLORS.gray}${formattedContent}${COLORS.reset}`;
|
|
176
|
+
break;
|
|
177
|
+
|
|
178
|
+
case 'warn':
|
|
179
|
+
// Warnings are yellow (important)
|
|
180
|
+
typePrefix = `${COLORS.yellow}⚠️ WARN${COLORS.reset}`;
|
|
181
|
+
break;
|
|
182
|
+
|
|
183
|
+
case 'error':
|
|
184
|
+
// Errors are red (important)
|
|
185
|
+
typePrefix = `${COLORS.red}❌ ERR${COLORS.reset}`;
|
|
186
|
+
break;
|
|
187
|
+
|
|
188
|
+
case 'success':
|
|
189
|
+
typePrefix = `${COLORS.green}✅ DONE${COLORS.reset}`;
|
|
190
|
+
break;
|
|
191
|
+
|
|
192
|
+
case 'debug':
|
|
193
|
+
// Debug is gray (less important)
|
|
194
|
+
typePrefix = `${COLORS.gray}🔍 DBUG${COLORS.reset}`;
|
|
195
|
+
formattedContent = `${COLORS.gray}${formattedContent}${COLORS.reset}`;
|
|
196
|
+
break;
|
|
197
|
+
|
|
198
|
+
case 'progress':
|
|
199
|
+
typePrefix = `${COLORS.blue}🔄 PROG${COLORS.reset}`;
|
|
200
|
+
break;
|
|
201
|
+
|
|
202
|
+
case 'stdout':
|
|
203
|
+
case 'raw':
|
|
204
|
+
// Raw output is gray (less important)
|
|
205
|
+
typePrefix = `${COLORS.gray} >>${COLORS.reset}`;
|
|
206
|
+
formattedContent = `${COLORS.gray}${formattedContent}${COLORS.reset}`;
|
|
207
|
+
break;
|
|
208
|
+
|
|
209
|
+
case 'stderr':
|
|
210
|
+
typePrefix = `${COLORS.red} >>${COLORS.reset}`;
|
|
211
|
+
break;
|
|
157
212
|
}
|
|
158
213
|
|
|
159
214
|
return { typePrefix, formattedContent };
|
|
@@ -236,6 +291,7 @@ function getTypeInfo(type: MessageType): { label: string; color: string } {
|
|
|
236
291
|
progress: { label: 'PROG ', color: COLORS.blue || COLORS.cyan },
|
|
237
292
|
stdout: { label: 'STDOUT', color: COLORS.white },
|
|
238
293
|
stderr: { label: 'STDERR', color: COLORS.red },
|
|
294
|
+
raw: { label: 'RAW ', color: COLORS.white },
|
|
239
295
|
};
|
|
240
296
|
|
|
241
297
|
return typeMap[type] || { label: type.toUpperCase().padEnd(6), color: COLORS.white };
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import * as path from 'path';
|
|
2
|
+
|
|
3
|
+
export const LOG_FILE_NAMES = {
|
|
4
|
+
clean: 'terminal.log',
|
|
5
|
+
raw: 'terminal-raw.log',
|
|
6
|
+
jsonl: 'terminal.jsonl',
|
|
7
|
+
readable: 'terminal-readable.log',
|
|
8
|
+
} as const;
|
|
9
|
+
|
|
10
|
+
export type LogFileType = keyof typeof LOG_FILE_NAMES;
|
|
11
|
+
|
|
12
|
+
export function getLaneLogPath(laneDir: string, type: LogFileType): string {
|
|
13
|
+
return path.join(laneDir, LOG_FILE_NAMES[type]);
|
|
14
|
+
}
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
import { stripAnsi } from './formatter';
|
|
2
|
+
|
|
3
|
+
export interface ParsedRawLogLine {
|
|
4
|
+
timestamp: Date;
|
|
5
|
+
message: string;
|
|
6
|
+
level: string;
|
|
7
|
+
}
|
|
8
|
+
|
|
9
|
+
const ISO_TIMESTAMP = /^\[(\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}(?:\.\d+)?Z?)\]\s*/;
|
|
10
|
+
const SHORT_TIMESTAMP = /^\[(\d{2}:\d{2}:\d{2})\]\s*/;
|
|
11
|
+
|
|
12
|
+
export function parseRawLogLine(line: string, fallbackTime: Date): ParsedRawLogLine {
|
|
13
|
+
const cleanLine = stripAnsi(line).trimEnd();
|
|
14
|
+
let timestamp = fallbackTime;
|
|
15
|
+
let message = cleanLine;
|
|
16
|
+
|
|
17
|
+
const isoMatch = cleanLine.match(ISO_TIMESTAMP);
|
|
18
|
+
if (isoMatch) {
|
|
19
|
+
const parsed = new Date(isoMatch[1]);
|
|
20
|
+
if (!Number.isNaN(parsed.getTime())) {
|
|
21
|
+
timestamp = parsed;
|
|
22
|
+
}
|
|
23
|
+
message = cleanLine.slice(isoMatch[0].length);
|
|
24
|
+
} else {
|
|
25
|
+
const shortMatch = cleanLine.match(SHORT_TIMESTAMP);
|
|
26
|
+
if (shortMatch) {
|
|
27
|
+
const [hours, minutes, seconds] = shortMatch[1].split(':').map(Number);
|
|
28
|
+
const candidate = new Date(fallbackTime);
|
|
29
|
+
candidate.setHours(hours, minutes, seconds, 0);
|
|
30
|
+
timestamp = candidate;
|
|
31
|
+
message = cleanLine.slice(shortMatch[0].length);
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
const lower = message.toLowerCase();
|
|
36
|
+
const level = lower.includes('error') || lower.includes('failed') || lower.includes('❌')
|
|
37
|
+
? 'error'
|
|
38
|
+
: lower.includes('warn')
|
|
39
|
+
? 'warn'
|
|
40
|
+
: 'info';
|
|
41
|
+
|
|
42
|
+
return { timestamp, message, level };
|
|
43
|
+
}
|
|
@@ -154,7 +154,7 @@ export function getLaneProcessStatus(lanePath: string, laneName: string): LanePr
|
|
|
154
154
|
if (result.startTime) {
|
|
155
155
|
if (result.endTime) {
|
|
156
156
|
result.duration = result.endTime - result.startTime;
|
|
157
|
-
} else if (result.stateStatus === 'running'
|
|
157
|
+
} else if (result.stateStatus === 'running') {
|
|
158
158
|
result.duration = Date.now() - result.startTime;
|
|
159
159
|
}
|
|
160
160
|
}
|
package/src/types/agent.ts
CHANGED
|
@@ -15,10 +15,25 @@ export interface DependencyRequestPlan {
|
|
|
15
15
|
}
|
|
16
16
|
|
|
17
17
|
export interface AgentSendResult {
|
|
18
|
+
/** Whether the operation succeeded */
|
|
18
19
|
ok: boolean;
|
|
20
|
+
/** Process exit code */
|
|
19
21
|
exitCode: number;
|
|
22
|
+
/** Error message if failed */
|
|
20
23
|
error?: string;
|
|
24
|
+
/** Session ID from cursor-agent */
|
|
21
25
|
sessionId?: string;
|
|
26
|
+
/** Result text from the agent response */
|
|
22
27
|
resultText?: string;
|
|
28
|
+
/** Total execution time in milliseconds */
|
|
29
|
+
durationMs?: number;
|
|
30
|
+
/** API call time in milliseconds */
|
|
31
|
+
durationApiMs?: number;
|
|
32
|
+
/** Unique request ID for debugging */
|
|
33
|
+
requestId?: string;
|
|
34
|
+
/** Result subtype: 'success' or 'error' */
|
|
35
|
+
subtype?: 'success' | 'error';
|
|
36
|
+
/** Model used for this request */
|
|
37
|
+
model?: string;
|
|
23
38
|
}
|
|
24
39
|
|
package/src/types/config.ts
CHANGED
|
@@ -49,6 +49,20 @@ export interface EnhancedLogConfig {
|
|
|
49
49
|
raw?: boolean;
|
|
50
50
|
}
|
|
51
51
|
|
|
52
|
+
/**
|
|
53
|
+
* Hook 시스템 설정
|
|
54
|
+
*/
|
|
55
|
+
export interface HooksConfig {
|
|
56
|
+
/** Hook 정의 파일 경로 (e.g., './cursorflow.hooks.ts') */
|
|
57
|
+
file?: string;
|
|
58
|
+
/** Hook 실행 타임아웃 (ms, 기본: 30000) */
|
|
59
|
+
timeout?: number;
|
|
60
|
+
/** 에러 시 계속 진행 여부 (기본: false) */
|
|
61
|
+
continueOnError?: boolean;
|
|
62
|
+
/** 디버그 모드 */
|
|
63
|
+
debug?: boolean;
|
|
64
|
+
}
|
|
65
|
+
|
|
52
66
|
export interface CursorFlowConfig {
|
|
53
67
|
tasksDir: string;
|
|
54
68
|
/** New flows directory (replaces tasksDir in new architecture) */
|
|
@@ -69,7 +83,7 @@ export interface CursorFlowConfig {
|
|
|
69
83
|
maxConcurrentLanes: number;
|
|
70
84
|
projectRoot: string;
|
|
71
85
|
/** Output format for cursor-agent (default: 'json') */
|
|
72
|
-
agentOutputFormat: 'json' | '
|
|
86
|
+
agentOutputFormat: 'json' | 'stream-json';
|
|
73
87
|
webhooks?: WebhookConfig[];
|
|
74
88
|
/** Enable intervention feature (stdin piping for message injection) */
|
|
75
89
|
enableIntervention?: boolean;
|
|
@@ -77,5 +91,13 @@ export interface CursorFlowConfig {
|
|
|
77
91
|
enhancedLogging?: Partial<EnhancedLogConfig>;
|
|
78
92
|
/** Default AI model for tasks (default: 'gemini-3-flash') */
|
|
79
93
|
defaultModel: string;
|
|
94
|
+
/** Auto-approve agent commands (--force flag). Default: true for automation. */
|
|
95
|
+
autoApproveCommands?: boolean;
|
|
96
|
+
/** Auto-approve MCP servers (--approve-mcps flag). Default: true for automation. */
|
|
97
|
+
autoApproveMcps?: boolean;
|
|
98
|
+
/** Enable browser automation (--browser flag). Required for web testing/scraping. */
|
|
99
|
+
browser?: boolean;
|
|
100
|
+
/** Hook 시스템 설정 */
|
|
101
|
+
hooks?: HooksConfig;
|
|
80
102
|
}
|
|
81
103
|
|