@litmers/cursorflow-orchestrator 0.1.39 → 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 +20 -16
- 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/prepare.js +0 -1
- package/dist/cli/prepare.js.map +1 -1
- package/dist/cli/resume.js +23 -5
- 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 +38 -63
- 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 -109
- 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 -77
- package/dist/core/runner/task.js.map +1 -1
- package/dist/core/runner.js +11 -2
- package/dist/core/runner.js.map +1 -1
- package/dist/core/stall-detection.d.ts +27 -4
- package/dist/core/stall-detection.js +116 -28
- 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 +8 -5
- package/dist/services/logging/console.js.map +1 -1
- package/dist/services/logging/formatter.d.ts +9 -3
- package/dist/services/logging/formatter.js +64 -17
- 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 +24 -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 +13 -2
- 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 +15 -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 +99 -20
- 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/git.d.ts +12 -1
- package/dist/utils/git.js +54 -1
- package/dist/utils/git.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 +3 -2
- package/dist/utils/log-formatter.js +11 -11
- 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/prepare.ts +0 -1
- package/src/cli/resume.ts +29 -5
- 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 +45 -62
- package/src/core/runner/agent.ts +66 -33
- package/src/core/runner/pipeline.ts +318 -122
- package/src/core/runner/task.ts +12 -93
- package/src/core/runner.ts +12 -2
- package/src/core/stall-detection.ts +145 -28
- 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 +9 -5
- package/src/services/logging/formatter.ts +74 -17
- 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 +25 -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 +13 -2
- package/src/ui/log-viewer.ts +3 -0
- package/src/utils/config.ts +17 -1
- package/src/utils/cursor-agent.ts +68 -16
- package/src/utils/enhanced-logger.ts +106 -20
- package/src/utils/event-registry.ts +595 -0
- package/src/utils/events.ts +0 -16
- package/src/utils/flow.ts +84 -0
- package/src/utils/git.ts +59 -1
- package/src/utils/log-constants.ts +2 -1
- package/src/utils/log-formatter.ts +11 -12
- 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
|
|
|
@@ -149,12 +155,10 @@ export function withContext(context: string) {
|
|
|
149
155
|
*/
|
|
150
156
|
export function laneOutput(laneName: string, message: string, isError = false, laneIndex?: number, taskIndex?: number, taskName?: string): void {
|
|
151
157
|
const timestamp = `${COLORS.gray}[${formatTimestamp()}]${COLORS.reset}`;
|
|
152
|
-
// Format: [laneIdx-taskIdx-laneName
|
|
158
|
+
// Format: [laneIdx-taskIdx-laneName] padded to 18 chars inside brackets
|
|
153
159
|
const lIdx = laneIndex ?? 1;
|
|
154
160
|
const tIdx = taskIndex ?? 1;
|
|
155
|
-
const combined =
|
|
156
|
-
? `${lIdx}-${tIdx}-${laneName}-${taskName}`
|
|
157
|
-
: `${lIdx}-${tIdx}-${laneName}`;
|
|
161
|
+
const combined = `${lIdx}-${tIdx}-${laneName}`;
|
|
158
162
|
const label = combined.substring(0, 18).padEnd(18);
|
|
159
163
|
const laneLabel = `${COLORS.magenta}[${label}]${COLORS.reset}`;
|
|
160
164
|
const output = isError ? `${COLORS.red}${message}${COLORS.reset}` : message;
|
|
@@ -3,17 +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
|
|
14
|
+
* - Lane labels fixed 14 chars: [1-1-lanename ]
|
|
15
|
+
* - Type labels: emoji + 4char (USER, ASST, TOOL, RESL, SYS, DONE, THNK)
|
|
10
16
|
*/
|
|
11
17
|
|
|
12
18
|
import { COLORS } from './console';
|
|
13
19
|
import { ParsedMessage, MessageType } from '../../types/logging';
|
|
14
20
|
|
|
15
|
-
// Types that should use box format
|
|
16
|
-
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']);
|
|
17
26
|
|
|
18
27
|
/**
|
|
19
28
|
* Strip ANSI escape sequences from text
|
|
@@ -64,10 +73,11 @@ export function formatMessageForConsole(
|
|
|
64
73
|
: '';
|
|
65
74
|
const tsPrefix = ts ? `${COLORS.gray}[${ts}]${COLORS.reset} ` : '';
|
|
66
75
|
|
|
67
|
-
// Lane label
|
|
68
|
-
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;
|
|
69
79
|
const labelPrefix = truncatedLabel
|
|
70
|
-
? `${COLORS.magenta}${truncatedLabel.padEnd(
|
|
80
|
+
? `${COLORS.magenta}[${truncatedLabel.padEnd(14)}]${COLORS.reset} `
|
|
71
81
|
: '';
|
|
72
82
|
|
|
73
83
|
// Determine if should use box format
|
|
@@ -77,17 +87,17 @@ export function formatMessageForConsole(
|
|
|
77
87
|
if (!typePrefix) return `${tsPrefix}${labelPrefix}${formattedContent}`;
|
|
78
88
|
|
|
79
89
|
if (!useBox) {
|
|
80
|
-
|
|
90
|
+
// Compact format: type prefix is already formatted with proper spacing
|
|
91
|
+
return `${tsPrefix}${labelPrefix}${typePrefix} ${formattedContent}`;
|
|
81
92
|
}
|
|
82
93
|
|
|
83
|
-
// Multi-line box format (only for user, assistant,
|
|
84
|
-
// Emoji width is 2, so we need to account for that in indent calculation
|
|
94
|
+
// Multi-line box format (only for user, assistant, result)
|
|
85
95
|
const lines = formattedContent.split('\n');
|
|
86
96
|
const fullPrefix = `${tsPrefix}${labelPrefix}`;
|
|
87
97
|
const strippedPrefix = stripAnsi(typePrefix);
|
|
88
98
|
// Count emojis (they take 2 terminal columns but 1-2 chars in string)
|
|
89
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;
|
|
90
|
-
const visualWidth = strippedPrefix.length + emojiCount;
|
|
100
|
+
const visualWidth = strippedPrefix.length + emojiCount;
|
|
91
101
|
|
|
92
102
|
const boxWidth = 60;
|
|
93
103
|
const header = `${typePrefix}┌${'─'.repeat(boxWidth)}`;
|
|
@@ -111,6 +121,9 @@ function formatMessageContent(msg: ParsedMessage, forceCompact: boolean): { type
|
|
|
111
121
|
formattedContent = formattedContent.replace(/\n\s*\n/g, ' ').replace(/\n/g, ' ').trim();
|
|
112
122
|
}
|
|
113
123
|
|
|
124
|
+
// Determine if this type should be gray (less important)
|
|
125
|
+
const isGray = GRAY_TYPES.has(msg.type);
|
|
126
|
+
|
|
114
127
|
switch (msg.type) {
|
|
115
128
|
case 'user':
|
|
116
129
|
typePrefix = `${COLORS.cyan}🧑 USER${COLORS.reset}`;
|
|
@@ -123,20 +136,20 @@ function formatMessageContent(msg: ParsedMessage, forceCompact: boolean): { type
|
|
|
123
136
|
break;
|
|
124
137
|
|
|
125
138
|
case 'tool':
|
|
126
|
-
// Tool calls are always gray
|
|
139
|
+
// Tool calls are always gray (less important)
|
|
127
140
|
typePrefix = `${COLORS.gray}🔧 TOOL${COLORS.reset}`;
|
|
128
141
|
formattedContent = formatToolCall(formattedContent);
|
|
129
142
|
break;
|
|
130
143
|
|
|
131
144
|
case 'tool_result':
|
|
132
|
-
// Tool results are always gray
|
|
145
|
+
// Tool results are always gray (less important)
|
|
133
146
|
typePrefix = `${COLORS.gray}📄 RESL${COLORS.reset}`;
|
|
134
147
|
const resMatch = formattedContent.match(/\[Tool Result: ([^\]]+)\]/);
|
|
135
148
|
if (resMatch) {
|
|
136
149
|
const simpleName = simplifyToolName(resMatch[1]!);
|
|
137
150
|
formattedContent = `${COLORS.gray}${simpleName} OK${COLORS.reset}`;
|
|
138
151
|
} else {
|
|
139
|
-
formattedContent = `${COLORS.gray}
|
|
152
|
+
formattedContent = `${COLORS.gray}OK${COLORS.reset}`;
|
|
140
153
|
}
|
|
141
154
|
break;
|
|
142
155
|
|
|
@@ -145,14 +158,57 @@ function formatMessageContent(msg: ParsedMessage, forceCompact: boolean): { type
|
|
|
145
158
|
break;
|
|
146
159
|
|
|
147
160
|
case 'system':
|
|
148
|
-
|
|
161
|
+
// System messages are gray (less important)
|
|
162
|
+
typePrefix = `${COLORS.gray}⚙️ SYS${COLORS.reset}`;
|
|
163
|
+
formattedContent = `${COLORS.gray}${formattedContent}${COLORS.reset}`;
|
|
149
164
|
break;
|
|
150
165
|
|
|
151
166
|
case 'thinking':
|
|
152
|
-
// Thinking is always gray and compact
|
|
167
|
+
// Thinking is always gray and compact (less important)
|
|
153
168
|
typePrefix = `${COLORS.gray}🤔 THNK${COLORS.reset}`;
|
|
154
169
|
formattedContent = `${COLORS.gray}${truncate(formattedContent, 100)}${COLORS.reset}`;
|
|
155
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;
|
|
156
212
|
}
|
|
157
213
|
|
|
158
214
|
return { typePrefix, formattedContent };
|
|
@@ -235,6 +291,7 @@ function getTypeInfo(type: MessageType): { label: string; color: string } {
|
|
|
235
291
|
progress: { label: 'PROG ', color: COLORS.blue || COLORS.cyan },
|
|
236
292
|
stdout: { label: 'STDOUT', color: COLORS.white },
|
|
237
293
|
stderr: { label: 'STDERR', color: COLORS.red },
|
|
294
|
+
raw: { label: 'RAW ', color: COLORS.white },
|
|
238
295
|
};
|
|
239
296
|
|
|
240
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,11 +83,21 @@ 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[];
|
|
88
|
+
/** Enable intervention feature (stdin piping for message injection) */
|
|
89
|
+
enableIntervention?: boolean;
|
|
74
90
|
/** Enhanced logging configuration */
|
|
75
91
|
enhancedLogging?: Partial<EnhancedLogConfig>;
|
|
76
92
|
/** Default AI model for tasks (default: 'gemini-3-flash') */
|
|
77
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;
|
|
78
102
|
}
|
|
79
103
|
|